upload tizen1.0 source
authorKim Kibum <kb0929.kim@samsung.com>
Sun, 29 Apr 2012 08:04:32 +0000 (17:04 +0900)
committerKim Kibum <kb0929.kim@samsung.com>
Sun, 29 Apr 2012 08:04:32 +0000 (17:04 +0900)
539 files changed:
CONTRIBUTIONS [new file with mode: 0644]
README
build_nsis.sh [new file with mode: 0755]
build_release [new file with mode: 0755]
configurations/tizen.config [new file with mode: 0644]
configurations/tizen_hostapd.config [moved from debian/slp.config with 71% similarity]
debian/changelog
debian/control
debian/rules
debian/wpa_supplicant.conf [deleted file]
debian/wpasupplicant.install.in
doc/Makefile [new file with mode: 0644]
doc/code_structure.doxygen [new file with mode: 0644]
doc/ctrl_iface.doxygen [new file with mode: 0644]
doc/dbus.doxygen [new file with mode: 0644]
doc/directories.doxygen [new file with mode: 0644]
doc/doxygen.conf [new file with mode: 0644]
doc/driver_wrapper.doxygen [new file with mode: 0644]
doc/eap.doxygen [new file with mode: 0644]
doc/eap_server.doxygen [new file with mode: 0644]
doc/hostapd.fig [new file with mode: 0644]
doc/hostapd_ctrl_iface.doxygen [new file with mode: 0644]
doc/mainpage.doxygen [new file with mode: 0644]
doc/porting.doxygen [new file with mode: 0644]
doc/testing_tools.doxygen [new file with mode: 0644]
doc/wpa_supplicant.fig [new file with mode: 0644]
eap_example/Makefile [new file with mode: 0644]
eap_example/README [new file with mode: 0644]
eap_example/ca.pem [new file with mode: 0644]
eap_example/eap_example.c [new file with mode: 0644]
eap_example/eap_example_peer.c [new file with mode: 0644]
eap_example/eap_example_server.c [new file with mode: 0644]
eap_example/server-key.pem [new file with mode: 0644]
eap_example/server.key [new file with mode: 0644]
eap_example/server.pem [new file with mode: 0644]
etc/rc.d/init.d/wpa_supplicant [new file with mode: 0755]
hostapd/Android.mk [new file with mode: 0644]
hostapd/ChangeLog [new file with mode: 0644]
hostapd/Makefile [new file with mode: 0644]
hostapd/README [new file with mode: 0644]
hostapd/README-WPS [new file with mode: 0644]
hostapd/config_file.c [new file with mode: 0644]
hostapd/config_file.h [new file with mode: 0644]
hostapd/ctrl_iface.c [new file with mode: 0644]
hostapd/ctrl_iface.h [new file with mode: 0644]
hostapd/defconfig [new file with mode: 0644]
hostapd/dump_state.c [new file with mode: 0644]
hostapd/dump_state.h [new file with mode: 0644]
hostapd/eap_register.c [new file with mode: 0644]
hostapd/eap_register.h [new file with mode: 0644]
hostapd/eap_testing.txt [new file with mode: 0644]
hostapd/hlr_auc_gw.c [new file with mode: 0644]
hostapd/hlr_auc_gw.milenage_db [new file with mode: 0644]
hostapd/hostapd.8 [new file with mode: 0644]
hostapd/hostapd.accept [new file with mode: 0644]
hostapd/hostapd.conf [new file with mode: 0644]
hostapd/hostapd.deny [new file with mode: 0644]
hostapd/hostapd.eap_user [new file with mode: 0644]
hostapd/hostapd.radius_clients [new file with mode: 0644]
hostapd/hostapd.sim_db [new file with mode: 0644]
hostapd/hostapd.vlan [new file with mode: 0644]
hostapd/hostapd.wpa_psk [new file with mode: 0644]
hostapd/hostapd_cli.1 [new file with mode: 0644]
hostapd/hostapd_cli.c [new file with mode: 0644]
hostapd/logwatch/README [new file with mode: 0644]
hostapd/logwatch/hostapd [new file with mode: 0755]
hostapd/logwatch/hostapd.conf [new file with mode: 0644]
hostapd/main.c [new file with mode: 0644]
hostapd/nt_password_hash.c [new file with mode: 0644]
hostapd/wired.conf [new file with mode: 0644]
mac80211_hwsim/tests/0001-wpa2-psk/hostapd.conf [new file with mode: 0644]
mac80211_hwsim/tests/0001-wpa2-psk/test.txt [new file with mode: 0644]
mac80211_hwsim/tests/0001-wpa2-psk/wpa_supplicant.conf [new file with mode: 0644]
mac80211_hwsim/tests/0002-vlan/hostapd.accept [new file with mode: 0644]
mac80211_hwsim/tests/0002-vlan/hostapd.conf [new file with mode: 0644]
mac80211_hwsim/tests/0002-vlan/hostapd.vlan [new file with mode: 0644]
mac80211_hwsim/tests/0002-vlan/test.txt [new file with mode: 0644]
mac80211_hwsim/tools/Makefile [new file with mode: 0644]
mac80211_hwsim/tools/hwsim_test.c [new file with mode: 0644]
packaging/wpasupplicant.spec [new file with mode: 0644]
radius_example/Makefile [new file with mode: 0644]
radius_example/README [new file with mode: 0644]
radius_example/radius_example.c [new file with mode: 0644]
src/Makefile
src/ap/accounting.c
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/authsrv.c
src/ap/beacon.c
src/ap/beacon.h
src/ap/ctrl_iface_ap.c
src/ap/drv_callbacks.c
src/ap/hostapd.c
src/ap/hostapd.h
src/ap/hw_features.c
src/ap/hw_features.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 [new file with mode: 0644]
src/ap/ieee802_1x.c
src/ap/ieee802_1x.h
src/ap/p2p_hostapd.c [new file with mode: 0644]
src/ap/p2p_hostapd.h [new file with mode: 0644]
src/ap/peerkey_auth.c
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/wmm.c
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_i.h
src/ap/wpa_auth_ie.c
src/ap/wps_hostapd.c
src/ap/wps_hostapd.h
src/common/defs.h
src/common/gas.c [new file with mode: 0644]
src/common/gas.h [new file with mode: 0644]
src/common/ieee802_11_common.c
src/common/ieee802_11_common.h
src/common/ieee802_11_defs.h
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 [deleted file]
src/crypto/Makefile
src/crypto/aes-internal-dec.c
src/crypto/aes-internal-enc.c
src/crypto/crypto.h
src/crypto/crypto_internal-rsa.c
src/crypto/crypto_internal.c
src/crypto/dh_group5.c
src/crypto/dh_groups.c
src/crypto/fips_prf_internal.c
src/crypto/md5-internal.c
src/crypto/ms_funcs.c
src/crypto/random.c [new file with mode: 0644]
src/crypto/random.h [new file with mode: 0644]
src/crypto/sha1-pbkdf2.c
src/crypto/sha1-tlsprf.c
src/crypto/sha1.h
src/crypto/sha256-internal.c
src/crypto/sha256-tlsprf.c [new file with mode: 0644]
src/crypto/sha256.h
src/crypto/sha256_i.h [new file with mode: 0644]
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 [deleted file]
src/drivers/Apple80211.h [deleted file]
src/drivers/MobileApple80211.c [deleted file]
src/drivers/MobileApple80211.h [deleted file]
src/drivers/android_drv.h [new file with mode: 0644]
src/drivers/driver.h
src/drivers/driver_atheros.c
src/drivers/driver_atmel.c [deleted file]
src/drivers/driver_broadcom.c [deleted file]
src/drivers/driver_bsd.c
src/drivers/driver_common.c [new file with mode: 0644]
src/drivers/driver_hostap.c
src/drivers/driver_iphone.m [deleted file]
src/drivers/driver_ipw.c [deleted file]
src/drivers/driver_madwifi.c
src/drivers/driver_ndis.c
src/drivers/driver_ndiswrapper.c [deleted file]
src/drivers/driver_nl80211.c
src/drivers/driver_osx.m [deleted file]
src/drivers/driver_ralink.c [deleted file]
src/drivers/driver_ralink.h [deleted file]
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 [new file with mode: 0644]
src/drivers/linux_ioctl.c
src/drivers/linux_ioctl.h
src/drivers/linux_wext.h [new file with mode: 0644]
src/drivers/netlink.c
src/drivers/netlink.h
src/drivers/nl80211_copy.h
src/drivers/rfkill.c [new file with mode: 0644]
src/drivers/rfkill.h [new file with mode: 0644]
src/drivers/wireless_copy.h [deleted file]
src/eap_common/eap_defs.h
src/eap_common/eap_fast_common.c
src/eap_common/eap_peap_common.c
src/eap_common/eap_peap_common.h
src/eap_common/eap_pwd_common.c [new file with mode: 0644]
src/eap_common/eap_pwd_common.h [new file with mode: 0644]
src/eap_common/eap_sim_common.c
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_fast.c
src/eap_peer/eap_fast_pac.c
src/eap_peer/eap_gpsk.c
src/eap_peer/eap_i.h
src/eap_peer/eap_leap.c
src/eap_peer/eap_methods.c
src/eap_peer/eap_methods.h
src/eap_peer/eap_mschapv2.c
src/eap_peer/eap_pax.c
src/eap_peer/eap_peap.c
src/eap_peer/eap_psk.c
src/eap_peer/eap_pwd.c [new file with mode: 0644]
src/eap_peer/eap_sake.c
src/eap_peer/eap_sim.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_wsc.c
src/eap_peer/ikev2.c
src/eap_peer/tncc.c
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_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 [new file with mode: 0644]
src/eap_server/eap_server_sake.c
src/eap_server/eap_server_sim.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_wsc.c
src/eap_server/eap_sim_db.c
src/eap_server/ikev2.c
src/eap_server/tncs.c
src/eapol_auth/eapol_auth_sm.c
src/eapol_auth/eapol_auth_sm.h
src/eapol_supp/eapol_supp_sm.c
src/eapol_supp/eapol_supp_sm.h
src/l2_packet/l2_packet_freebsd.c
src/l2_packet/l2_packet_linux.c
src/p2p/Makefile [new file with mode: 0644]
src/p2p/p2p.c [new file with mode: 0644]
src/p2p/p2p.h [new file with mode: 0644]
src/p2p/p2p_build.c [new file with mode: 0644]
src/p2p/p2p_dev_disc.c [new file with mode: 0644]
src/p2p/p2p_go_neg.c [new file with mode: 0644]
src/p2p/p2p_group.c [new file with mode: 0644]
src/p2p/p2p_i.h [new file with mode: 0644]
src/p2p/p2p_invitation.c [new file with mode: 0644]
src/p2p/p2p_parse.c [new file with mode: 0644]
src/p2p/p2p_pd.c [new file with mode: 0644]
src/p2p/p2p_sd.c [new file with mode: 0644]
src/p2p/p2p_utils.c [new file with mode: 0644]
src/radius/.gitignore [deleted file]
src/radius/radius.c
src/radius/radius.h
src/radius/radius_client.c
src/radius/radius_client.h
src/radius/radius_server.c
src/radius/radius_server.h
src/rsn_supp/peerkey.c
src/rsn_supp/pmksa_cache.c
src/rsn_supp/pmksa_cache.h
src/rsn_supp/preauth.c
src/rsn_supp/tdls.c [new file with mode: 0644]
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 [deleted file]
src/tls/Makefile
src/tls/libtommath.c
src/tls/pkcs5.c
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_record.c
src/tls/tlsv1_record.h
src/tls/tlsv1_server.c
src/tls/tlsv1_server.h
src/tls/tlsv1_server_read.c
src/tls/tlsv1_server_write.c
src/tls/x509v3.c
src/tls/x509v3.h
src/utils/.gitignore [deleted file]
src/utils/Makefile
src/utils/base64.c
src/utils/base64.h
src/utils/common.c
src/utils/common.h
src/utils/edit.c [new file with mode: 0644]
src/utils/edit.h [new file with mode: 0644]
src/utils/edit_readline.c [new file with mode: 0644]
src/utils/edit_simple.c [new file with mode: 0644]
src/utils/eloop.c
src/utils/eloop.h
src/utils/eloop_win.c
src/utils/includes.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/radiotap.h
src/utils/radiotap_iter.h
src/utils/wpa_debug.c
src/utils/wpa_debug.h
src/utils/wpabuf.h
src/wps/http_client.c
src/wps/upnp_xml.c
src/wps/upnp_xml.h
src/wps/wps.c
src/wps/wps.h
src/wps/wps_attr_build.c
src/wps/wps_attr_parse.c
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_registrar.c
src/wps/wps_ufd.c
src/wps/wps_upnp.c
src/wps/wps_upnp.h
src/wps/wps_upnp_ap.c
src/wps/wps_upnp_event.c
src/wps/wps_upnp_i.h
src/wps/wps_upnp_ssdp.c
src/wps/wps_upnp_web.c
src/wps/wps_validate.c [new file with mode: 0644]
tests/Makefile [new file with mode: 0644]
tests/test-aes.c [new file with mode: 0644]
tests/test-asn1.c [new file with mode: 0644]
tests/test-base64.c [new file with mode: 0644]
tests/test-https.c [new file with mode: 0644]
tests/test-list.c [new file with mode: 0644]
tests/test-md4.c [new file with mode: 0644]
tests/test-md5.c [new file with mode: 0644]
tests/test-milenage.c [new file with mode: 0644]
tests/test-ms_funcs.c [new file with mode: 0644]
tests/test-rc4.c [new file with mode: 0644]
tests/test-sha1.c [new file with mode: 0644]
tests/test-sha256.c [new file with mode: 0644]
tests/test-x509.c [new file with mode: 0644]
tests/test-x509v3.c [new file with mode: 0644]
tests/test_x509v3_nist.sh [new file with mode: 0755]
tests/test_x509v3_nist2.sh [new file with mode: 0755]
wlantest/Makefile [new file with mode: 0644]
wlantest/bss.c [new file with mode: 0644]
wlantest/ccmp.c [new file with mode: 0644]
wlantest/crc32.c [new file with mode: 0644]
wlantest/ctrl.c [new file with mode: 0644]
wlantest/inject.c [new file with mode: 0644]
wlantest/monitor.c [new file with mode: 0644]
wlantest/process.c [new file with mode: 0644]
wlantest/readpcap.c [new file with mode: 0644]
wlantest/rx_data.c [new file with mode: 0644]
wlantest/rx_eapol.c [new file with mode: 0644]
wlantest/rx_ip.c [new file with mode: 0644]
wlantest/rx_mgmt.c [new file with mode: 0644]
wlantest/rx_tdls.c [new file with mode: 0644]
wlantest/sta.c [new file with mode: 0644]
wlantest/tkip.c [new file with mode: 0644]
wlantest/wep.c [new file with mode: 0644]
wlantest/wired.c [new file with mode: 0644]
wlantest/wlantest.c [new file with mode: 0644]
wlantest/wlantest.h [new file with mode: 0644]
wlantest/wlantest_cli.c [new file with mode: 0644]
wlantest/wlantest_ctrl.h [new file with mode: 0644]
wlantest/writepcap.c [new file with mode: 0644]
wpa_supplicant/.gitignore [deleted file]
wpa_supplicant/Android.mk [new file with mode: 0644]
wpa_supplicant/ChangeLog
wpa_supplicant/Makefile
wpa_supplicant/README
wpa_supplicant/README-P2P [new file with mode: 0644]
wpa_supplicant/README-WPS
wpa_supplicant/ap.c
wpa_supplicant/ap.h
wpa_supplicant/bgscan.c
wpa_supplicant/bgscan.h
wpa_supplicant/bgscan_learn.c [new file with mode: 0644]
wpa_supplicant/bgscan_simple.c
wpa_supplicant/blacklist.c
wpa_supplicant/bss.c
wpa_supplicant/bss.h
wpa_supplicant/config.c
wpa_supplicant/config.h
wpa_supplicant/config_file.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_unix.c
wpa_supplicant/dbus/.gitignore [deleted file]
wpa_supplicant/dbus/Makefile
wpa_supplicant/dbus/dbus-wpa_supplicant.conf
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 [new file with mode: 0644]
wpa_supplicant/dbus/dbus_new_handlers_p2p.h [new file with mode: 0644]
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 [deleted file]
wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in [new file with mode: 0644]
wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service [deleted file]
wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in [new file with mode: 0644]
wpa_supplicant/defconfig
wpa_supplicant/doc/docbook/.gitignore [deleted file]
wpa_supplicant/doc/docbook/wpa_supplicant.sgml
wpa_supplicant/driver_i.h
wpa_supplicant/eap_register.c
wpa_supplicant/eapol_test.c
wpa_supplicant/events.c
wpa_supplicant/examples/p2p-action-udhcp.sh [new file with mode: 0755]
wpa_supplicant/examples/p2p-action.sh [new file with mode: 0755]
wpa_supplicant/examples/udhcpd-p2p.conf [new file with mode: 0644]
wpa_supplicant/examples/wps-ap-cli [new file with mode: 0755]
wpa_supplicant/gas_query.c [new file with mode: 0644]
wpa_supplicant/gas_query.h [new file with mode: 0644]
wpa_supplicant/ibss_rsn.c
wpa_supplicant/ibss_rsn.h
wpa_supplicant/interworking.c [new file with mode: 0644]
wpa_supplicant/interworking.h [new file with mode: 0644]
wpa_supplicant/main.c
wpa_supplicant/mlme.c [deleted file]
wpa_supplicant/mlme.h [deleted file]
wpa_supplicant/notify.c
wpa_supplicant/notify.h
wpa_supplicant/offchannel.c [new file with mode: 0644]
wpa_supplicant/offchannel.h [new file with mode: 0644]
wpa_supplicant/p2p_supplicant.c [new file with mode: 0644]
wpa_supplicant/p2p_supplicant.h [new file with mode: 0644]
wpa_supplicant/scan.c
wpa_supplicant/scan.h
wpa_supplicant/sme.c
wpa_supplicant/sme.h
wpa_supplicant/symbian/wpa_supplicant.mmp
wpa_supplicant/systemd/wpa_supplicant-nl80211@.service.in [new file with mode: 0644]
wpa_supplicant/systemd/wpa_supplicant-wired@.service.in [new file with mode: 0644]
wpa_supplicant/systemd/wpa_supplicant.service.in [new file with mode: 0644]
wpa_supplicant/systemd/wpa_supplicant@.service.in [new file with mode: 0644]
wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj [new file with mode: 0755]
wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj [new file with mode: 0755]
wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj [new file with mode: 0755]
wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj [new file with mode: 0755]
wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj
wpa_supplicant/win_example.reg [changed mode: 0644->0755]
wpa_supplicant/wpa_cli.c
wpa_supplicant/wpa_gui-qt4/.gitignore [deleted file]
wpa_supplicant/wpa_gui-qt4/icons.qrc
wpa_supplicant/wpa_gui-qt4/icons/Makefile [new file with mode: 0644]
wpa_supplicant/wpa_gui-qt4/icons/README
wpa_supplicant/wpa_gui-qt4/icons/group.svg [new file with mode: 0644]
wpa_supplicant/wpa_gui-qt4/icons/invitation.svg [new file with mode: 0644]
wpa_supplicant/wpa_gui-qt4/icons_png.qrc
wpa_supplicant/wpa_gui-qt4/lang/.gitignore [deleted file]
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/signalbar.cpp [new file with mode: 0644]
wpa_supplicant/wpa_gui-qt4/signalbar.h [new file with mode: 0644]
wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
wpa_supplicant/wpa_gui-qt4/wpagui.cpp
wpa_supplicant/wpa_gui/.gitignore [deleted file]
wpa_supplicant/wpa_gui/eventhistory.ui [deleted file]
wpa_supplicant/wpa_gui/eventhistory.ui.h [deleted file]
wpa_supplicant/wpa_gui/main.cpp [deleted file]
wpa_supplicant/wpa_gui/networkconfig.ui [deleted file]
wpa_supplicant/wpa_gui/networkconfig.ui.h [deleted file]
wpa_supplicant/wpa_gui/scanresults.ui [deleted file]
wpa_supplicant/wpa_gui/scanresults.ui.h [deleted file]
wpa_supplicant/wpa_gui/setup-mingw-cross-compiling [deleted file]
wpa_supplicant/wpa_gui/userdatarequest.ui [deleted file]
wpa_supplicant/wpa_gui/userdatarequest.ui.h [deleted file]
wpa_supplicant/wpa_gui/wpa_gui.pro [deleted file]
wpa_supplicant/wpa_gui/wpagui.ui [deleted file]
wpa_supplicant/wpa_gui/wpagui.ui.h [deleted file]
wpa_supplicant/wpa_gui/wpamsg.h [deleted file]
wpa_supplicant/wpa_priv.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant.conf
wpa_supplicant/wpa_supplicant_i.h
wpa_supplicant/wpas_glue.c
wpa_supplicant/wpas_glue.h
wpa_supplicant/wps_supplicant.c
wpa_supplicant/wps_supplicant.h
wpa_supplicant/xcode/wpa_supplicant.xcodeproj/project.pbxproj [deleted file]

diff --git a/CONTRIBUTIONS b/CONTRIBUTIONS
new file mode 100644 (file)
index 0000000..7670769
--- /dev/null
@@ -0,0 +1,103 @@
+Contributions to hostap.git
+---------------------------
+
+This software is distributed under a permissive open source license to
+allow it to be used in any projects, whether open source or proprietary.
+Contributions to the project are welcome and it is important to maintain
+clear record of contributions and terms under which they are licensed.
+To help with this, following procedure is used to allow acceptance and
+recording of the terms.
+
+These terms are similar to the process used in Linux kernel development.
+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.
+
+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
+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.
+
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+    have the right to submit it under the open source license
+    indicated in the file; or
+
+(b) The contribution is based upon previous work that, to the best
+    of my knowledge, is covered under an appropriate open source
+    license and I have the right under that license to submit that
+    work with modifications, whether created in whole or in part
+    by me, under the same open source license (unless I am
+    permitted to submit under a different license), as indicated
+    in the file; or
+
+(c) The contribution was provided directly to me by some other
+    person who certified (a), (b) or (c) and I have not modified
+    it.
+
+(d) I understand and agree that this project and the contribution
+    are public and that a record of the contribution (including all
+    personal information I submit with it, including my sign-off) is
+    maintained indefinitely and may be redistributed consistent with
+    this project or the open source license(s) involved.
+
+Additionally, I certify that:
+
+(e) The contribution can be licensed under the modified BSD license
+    as shown below even in case of files that are currently licensed
+    under other terms.
+
+
+To indicate your acceptance of these terms, please add the following
+line to each contribution you make to the project:
+
+Signed-hostap: Your Name <your@email.example.org>
+
+using your real name. Pseudonyms or anonymous contributions cannot
+unfortunately be accepted.
+
+
+
+Modified BSD license (no advertisement clause):
+
+Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> and contributors
+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. Neither the name(s) of the above-listed copyright holder(s) nor the
+   names of its contributors may be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README b/README
index 9c6be85..186e4b9 100644 (file)
--- a/README
+++ b/README
@@ -1,19 +1,75 @@
-wpa_supplicant and hostapd v0.6.x
----------------------------------
+wpa_supplicant and hostapd
+--------------------------
 
-Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
-These program is dual-licensed under both the GPL version 2 and BSD
-license. Either license may be used at your option.
+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.
+
+If you are submitting changes to the project, please see CONTRIBUTIONS
+file for more instructions.
 
 
 This package may include either wpa_supplicant, hostapd, or both. See
 README file respective subdirectories (wpa_supplicant/README or
 hostapd/README) for more details.
 
-Source code files have been moved around in v0.6.x releases and
-compared to earlier releases, the programs are now build by first
-going to a subdirectory (wpa_supplicant or hostapd) and creating
-build configuration (.config) and running 'make' there (for
-Linux/BSD/cygwin builds).
+Source code files were moved around in v0.6.x releases and compared to
+earlier releases, the programs are now built by first going to a
+subdirectory (wpa_supplicant or hostapd) and creating build
+configuration (.config) and running 'make' there (for Linux/BSD/cygwin
+builds).
+
+
+License
+-------
+
+GPL v2:
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+(this copy of the license is in COPYING file)
+
+
+Alternatively, this software may be distributed, used, and modified
+under the terms of BSD license:
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. Neither the name(s) of the above-listed copyright holder(s) nor the
+   names of its contributors may be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/build_nsis.sh b/build_nsis.sh
new file mode 100755 (executable)
index 0000000..e41bc36
--- /dev/null
@@ -0,0 +1,16 @@
+#!/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
diff --git a/build_release b/build_release
new file mode 100755 (executable)
index 0000000..22dcd42
--- /dev/null
@@ -0,0 +1,148 @@
+#!/bin/sh
+
+WINLOCAL=/home/jm/H-win/local
+
+set -e
+
+if [ -z "$1" ]; then
+    echo "build_release <version> [nobin]"
+    exit 1
+fi
+
+TMP=tmp.build_release
+RELDIR=`pwd`/Release
+VER=$1
+NOW=`date +%Y-%m-%d`
+
+echo "Version: $VER - $NOW"
+
+DATEw=`head -n 3 wpa_supplicant/ChangeLog | tail -n 1 | sed "s/ .*//"`
+DATEh=`head -n 3 hostapd/ChangeLog | tail -n 1 | sed "s/ .*//"`
+
+if [ "$DATEw" != "$NOW" -o "$DATEh" != "$NOW" ]; then
+    echo "NOTE! Date mismatch in ChangeLog: wpa_supplicant $DATEw hostapd $DATEh != $NOW"
+fi
+
+if [ -r $TMP ]; then
+    echo "Temporary directory '$TMP' exists. Remove it before running this."
+    exit 1
+fi
+
+mkdir $TMP
+mkdir -p $RELDIR
+
+git archive --format=tar --prefix=wpa-$VER/ HEAD \
+       README COPYING patches src wpa_supplicant hostapd |
+       gzip > $RELDIR/wpa-$VER.tar.gz
+git archive --format=tar --prefix=hostapd-$VER/ HEAD \
+       README COPYING patches src hostapd |
+       gzip > $RELDIR/hostapd-$VER.tar.gz
+git archive --format=tar --prefix=wpa_supplicant-$VER/ HEAD \
+       README COPYING patches src wpa_supplicant |
+       tar --directory=$TMP -xf -
+
+cd $TMP
+make -C wpa_supplicant-$VER/wpa_supplicant/doc/docbook man
+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
diff --git a/configurations/tizen.config b/configurations/tizen.config
new file mode 100644 (file)
index 0000000..27142c3
--- /dev/null
@@ -0,0 +1,475 @@
+# Example wpa_supplicant build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cases, these lines should use += in order not
+# to override previous values of the variables.
+
+
+# Uncomment following two lines and fix the paths if you have installed OpenSSL
+# or GnuTLS in non-default location
+#CFLAGS += -I/usr/local/openssl/include
+#LIBS += -L/usr/local/openssl/lib
+
+# Some Red Hat versions seem to include kerberos header files from OpenSSL, but
+# the kerberos files are not in the default include path. Following line can be
+# used to fix build issues on such systems (krb5.h not found).
+#CFLAGS += -I/usr/include/kerberos
+
+# Example configuration for various cross-compilation platforms
+
+#### sveasoft (e.g., for Linksys WRT54G) ######################################
+#CC=mipsel-uclibc-gcc
+#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
+#CFLAGS += -Os
+#CPPFLAGS += -I../src/include -I../../src/router/openssl/include
+#LIBS += -L/opt/brcm/hndtools-mipsel-uclibc-0.9.19/lib -lssl
+###############################################################################
+
+#### openwrt (e.g., for Linksys WRT54G) #######################################
+#CC=mipsel-uclibc-gcc
+#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
+#CFLAGS += -Os
+#CPPFLAGS=-I../src/include -I../openssl-0.9.7d/include \
+#      -I../WRT54GS/release/src/include
+#LIBS = -lssl
+###############################################################################
+
+
+# Driver interface for Host AP driver
+CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for Agere driver
+#CONFIG_DRIVER_HERMES=y
+# Change include directories to match with the local setup
+#CFLAGS += -I../../hcf -I../../include -I../../include/hcf
+#CFLAGS += -I../../include/wireless
+
+# Driver interface for madwifi driver
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_MADWIFI=y
+# Set include directory to the madwifi source tree
+#CFLAGS += -I../../madwifi
+
+# Driver interface for ndiswrapper
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_NDISWRAPPER=y
+
+# Driver interface for Atmel driver
+#CONFIG_DRIVER_ATMEL=y
+
+# Driver interface for old Broadcom driver
+# Please note that the newer Broadcom driver ("hybrid Linux driver") supports
+# Linux wireless extensions and does not need (or even work) with the old
+# driver wrapper. Use CONFIG_DRIVER_WEXT=y with that driver.
+#CONFIG_DRIVER_BROADCOM=y
+# Example path for wlioctl.h; change to match your configuration
+#CFLAGS += -I/opt/WRT54GS/release/src/include
+
+# Driver interface for Intel ipw2100/2200 driver
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_IPW=y
+
+# Driver interface for Ralink driver
+#CONFIG_DRIVER_RALINK=y
+
+# Driver interface for generic Linux wireless extensions
+# Note: WEXT is deprecated in the current Linux kernel version and no new
+# functionality is added to it. nl80211-based interface is the new
+# replacement for WEXT and its use allows wpa_supplicant to properly control
+# the driver to improve existing functionality like roaming and to support new
+# functionality.
+CONFIG_DRIVER_WEXT=y
+
+# Driver interface for Linux drivers using the nl80211 kernel interface
+CONFIG_DRIVER_NL80211=y
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
+
+# Driver interface for Windows NDIS
+#CONFIG_DRIVER_NDIS=y
+#CFLAGS += -I/usr/include/w32api/ddk
+#LIBS += -L/usr/local/lib
+# For native build using mingw
+#CONFIG_NATIVE_WINDOWS=y
+# Additional directories for cross-compilation on Linux host for mingw target
+#CFLAGS += -I/opt/mingw/mingw32/include/ddk
+#LIBS += -L/opt/mingw/mingw32/lib
+#CC=mingw32-gcc
+# By default, driver_ndis uses WinPcap for low-level operations. This can be
+# replaced with the following option which replaces WinPcap calls with NDISUIO.
+# However, this requires that WZC is disabled (net stop wzcsvc) before starting
+# wpa_supplicant.
+# CONFIG_USE_NDISUIO=y
+
+# Driver interface for development testing
+#CONFIG_DRIVER_TEST=y
+
+# Driver interface for wired Ethernet drivers
+#CONFIG_DRIVER_WIRED=y
+
+# Driver interface for the Broadcom RoboSwitch family
+#CONFIG_DRIVER_ROBOSWITCH=y
+
+# Driver interface for no driver (e.g., WPS ER only)
+#CONFIG_DRIVER_NONE=y
+
+# Solaris libraries
+#LIBS += -lsocket -ldlpi -lnsl
+#LIBS_c += -lsocket
+
+# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
+# included)
+CONFIG_IEEE8021X_EAPOL=y
+
+# EAP-MD5
+CONFIG_EAP_MD5=y
+
+# EAP-MSCHAPv2
+CONFIG_EAP_MSCHAPV2=y
+
+# EAP-TLS
+CONFIG_EAP_TLS=y
+
+# EAL-PEAP
+CONFIG_EAP_PEAP=y
+
+# EAP-TTLS
+CONFIG_EAP_TTLS=y
+
+# EAP-FAST
+# Note: Default OpenSSL package does not include support for all the
+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
+# the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch)
+# to add the needed functions.
+#CONFIG_EAP_FAST=y
+
+# EAP-GTC
+CONFIG_EAP_GTC=y
+
+# EAP-OTP
+CONFIG_EAP_OTP=y
+
+# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used)
+#CONFIG_EAP_SIM=y
+
+# EAP-PSK (experimental; this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-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
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# Smartcard support (i.e., private key on a smartcard), e.g., with openssl
+# engine.
+CONFIG_SMARTCARD=y
+
+# PC/SC interface for smartcards (USIM, GSM SIM)
+# Enable this if EAP-SIM or EAP-AKA is included
+#CONFIG_PCSC=y
+
+# Development testing
+#CONFIG_EAPOL_TEST=y
+
+# Select control interface backend for external programs, e.g, wpa_cli:
+# unix = UNIX domain sockets (default for Linux/*BSD)
+# udp = UDP sockets using localhost (127.0.0.1)
+# named_pipe = Windows Named Pipe (default for Windows)
+# y = use default (backwards compatibility)
+# If this option is commented out, control interface is not included in the
+# build.
+CONFIG_CTRL_IFACE=unix
+
+# Include support for GNU Readline and History Libraries in wpa_cli.
+# When building a wpa_cli binary for distribution, please note that these
+# libraries are licensed under GPL and as such, BSD license may not apply for
+# the resulting binary.
+#CONFIG_READLINE=y
+
+# Include internal line edit mode in wpa_cli. This can be used as a replacement
+# for GNU Readline to provide limited command line editing and history support.
+#CONFIG_WPA_CLI_EDIT=y
+
+# Remove debugging code that is printing out debug message to stdout.
+# This can be used to reduce the size of the wpa_supplicant considerably
+# if debugging code is not needed. The size reduction can be around 35%
+# (e.g., 90 kB).
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save
+# 35-50 kB in code size.
+#CONFIG_NO_WPA=y
+
+# Remove WPA2 support. This allows WPA to be used, but removes WPA2 code to
+# save about 1 kB in code size when building only WPA-Personal (no EAP support)
+# or 6 kB if building for WPA-Enterprise.
+#CONFIG_NO_WPA2=y
+
+# Remove IEEE 802.11i/WPA-Personal ASCII passphrase support
+# This option can be used to reduce code size by removing support for
+# converting ASCII passphrases into PSK. If this functionality is removed, the
+# PSK can only be configured as the 64-octet hexstring (e.g., from
+# wpa_passphrase). This saves about 0.5 kB in code size.
+#CONFIG_NO_WPA_PASSPHRASE=y
+
+# Disable scan result processing (ap_mode=1) to save code size by about 1 kB.
+# This can be used if ap_scan=1 mode is never enabled.
+#CONFIG_NO_SCAN_PROCESSING=y
+
+# Select configuration backend:
+# file = text file (e.g., wpa_supplicant.conf; note: the configuration file
+#      path is given on command line, not here; this option is just used to
+#      select the backend that allows configuration files to be used)
+# winreg = Windows registry (see win_example.reg for an example)
+CONFIG_BACKEND=file
+
+# Remove configuration write functionality (i.e., to allow the configuration
+# file to be updated based on runtime configuration changes). The runtime
+# configuration can still be changed, the changes are just not going to be
+# persistent over restarts. This option can be used to reduce code size by
+# about 3.5 kB.
+#CONFIG_NO_CONFIG_WRITE=y
+
+# Remove support for configuration blobs to reduce code size by about 1.5 kB.
+#CONFIG_NO_CONFIG_BLOBS=y
+
+# Select program entry point implementation:
+# main = UNIX/POSIX like main() function (default)
+# main_winsvc = Windows service (read parameters from registry)
+# main_none = Very basic example (development use only)
+CONFIG_MAIN=main
+
+# Select wrapper for operatins system and C library specific functions
+# unix = UNIX/POSIX like systems (default)
+# win32 = Windows systems
+# none = Empty template
+CONFIG_OS=unix
+
+# Select event loop implementation
+# eloop = select() loop (default)
+# eloop_win = Windows events and WaitForMultipleObject() loop
+# eloop_none = Empty template
+CONFIG_ELOOP=eloop
+
+# Select layer 2 packet implementation
+# linux = Linux packet socket (default)
+# pcap = libpcap/libdnet/WinPcap
+# freebsd = FreeBSD libpcap
+# winpcap = WinPcap with receive thread
+# ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y)
+# none = Empty template
+CONFIG_L2_PACKET=linux
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection)
+# This version is an experimental implementation based on IEEE 802.11w/D1.0
+# draft and is subject to change since the standard has not yet been finalized.
+# Driver support is also needed for IEEE 802.11w.
+#CONFIG_IEEE80211W=y
+
+# Select TLS implementation
+# openssl = OpenSSL (default)
+# gnutls = GnuTLS
+# 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
+
+# Enable privilege separation (see README 'Privilege separation' for details)
+#CONFIG_PRIVSEP=y
+
+# Enable mitigation against certain attacks against TKIP by delaying Michael
+# MIC error reports by a random amount of time between 0 and 60 seconds
+#CONFIG_DELAYED_MIC_ERROR_REPORT=y
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, comment out these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, comment out these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+# 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
+
+# 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
+
+#Additional flags
+CONFIG_LIBNL20=y
+CONFIG_P2P=y
+CONFIG_AP=y
similarity index 71%
rename from debian/slp.config
rename to configurations/tizen_hostapd.config
index 0194b8d..63a8453 100644 (file)
@@ -55,11 +55,6 @@ CONFIG_DRIVER_HOSTAP=y
 # Set include directory to the madwifi source tree
 #CFLAGS += -I../../madwifi
 
-# Driver interface for Prism54 driver
-# (Note: Prism54 is not yet supported, i.e., this will not work as-is and is
-# for developers only)
-#CONFIG_DRIVER_PRISM54=y
-
 # Driver interface for ndiswrapper
 # Deprecated; use CONFIG_DRIVER_WEXT=y instead.
 #CONFIG_DRIVER_NDISWRAPPER=y
@@ -83,15 +78,23 @@ CONFIG_DRIVER_HOSTAP=y
 #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_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
@@ -118,6 +121,13 @@ CONFIG_DRIVER_WEXT=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
@@ -151,19 +161,19 @@ CONFIG_EAP_GTC=y
 CONFIG_EAP_OTP=y
 
 # EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used)
-CONFIG_EAP_SIM=y
+#CONFIG_EAP_SIM=y
 
 # EAP-PSK (experimental; this is _not_ needed for WPA-PSK)
-CONFIG_EAP_PSK=y
+#CONFIG_EAP_PSK=y
 
 # EAP-PAX
-CONFIG_EAP_PAX=y
+#CONFIG_EAP_PAX=y
 
 # LEAP
 CONFIG_EAP_LEAP=y
 
 # EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used)
-CONFIG_EAP_AKA=y
+#CONFIG_EAP_AKA=y
 
 # EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used).
 # This requires CONFIG_EAP_AKA to be enabled, too.
@@ -185,6 +195,13 @@ CONFIG_EAP_AKA=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
 
 # EAP-IKEv2
 #CONFIG_EAP_IKEV2=y
@@ -211,7 +228,7 @@ CONFIG_SMARTCARD=y
 # y = use default (backwards compatibility)
 # If this option is commented out, control interface is not included in the
 # build.
-CONFIG_CTRL_IFACE=y
+CONFIG_CTRL_IFACE=unix
 
 # Include support for GNU Readline and History Libraries in wpa_cli.
 # When building a wpa_cli binary for distribution, please note that these
@@ -219,6 +236,10 @@ CONFIG_CTRL_IFACE=y
 # 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%
@@ -241,11 +262,6 @@ CONFIG_CTRL_IFACE=y
 # wpa_passphrase). This saves about 0.5 kB in code size.
 #CONFIG_NO_WPA_PASSPHRASE=y
 
-# Remove AES extra functions. This can be used to reduce code size by about
-# 1.5 kB by removing extra AES modes that are not needed for commonly used
-# client configurations (they are needed for some EAP types).
-#CONFIG_NO_AES_EXTRAS=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
@@ -255,7 +271,7 @@ CONFIG_CTRL_IFACE=y
 #      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
+CONFIG_BACKEND=file
 
 # Remove configuration write functionality (i.e., to allow the configuration
 # file to be updated based on runtime configuration changes). The runtime
@@ -271,19 +287,19 @@ CONFIG_CTRL_IFACE=y
 # 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
+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
+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
+CONFIG_ELOOP=eloop
 
 # Select layer 2 packet implementation
 # linux = Linux packet socket (default)
@@ -301,22 +317,28 @@ CONFIG_PEERKEY=y
 # 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
+#CONFIG_IEEE80211W=y
 
 # Select TLS implementation
 # openssl = OpenSSL (default)
-# gnutls = GnuTLS (needed for TLS/IA, see also CONFIG_GNUTLS_EXTRA)
+# gnutls = GnuTLS
 # internal = Internal TLSv1 implementation (experimental)
 # none = Empty template
 CONFIG_TLS=openssl
 
-# Whether to enable TLS/IA support, which is required for EAP-TTLSv1.
-# You need CONFIG_TLS=gnutls for this to have any effect. Please note that
-# even though the core GnuTLS library is released under LGPL, this extra
-# library uses GPL and as such, the terms of GPL apply to the combination
-# of wpa_supplicant and GnuTLS if this option is enabled. BSD license may not
-# apply for distribution of the resulting binary.
-#CONFIG_GNUTLS_EXTRA=y
+# 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
@@ -372,22 +394,78 @@ CONFIG_CTRL_IFACE_DBUS_INTRO=y
 # amount of memory/flash.
 #CONFIG_DYNAMIC_EAP_METHODS=y
 
-# Include client MLME (management frame processing).
-# This can be used to move MLME processing of Linux mac80211 stack into user
-# space. Please note that this is currently only available with
-# driver_nl80211.c and only with a modified version of Linux kernel and
-# wpa_supplicant.
-#CONFIG_CLIENT_MLME=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
+
 # 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
+#CONFIG_DELAYED_MIC_ERROR_REPORT=y
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, comment out these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, comment out these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+# 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
+
+# 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
index d9de133..cceb592 100644 (file)
@@ -1,3 +1,59 @@
+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
index 88dfaa3..4abe922 100644 (file)
@@ -3,7 +3,7 @@ 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), libdbus-glib-1-dev, libssl-dev, libdbus-1-dev, pkg-config
+Build-Depends: debhelper (>= 5), libssl-dev, libdbus-1-dev, pkg-config, libnl2-dev
 Standards-Version: 0.1.0
 
 Package: wpasupplicant
index 1c5b2fe..c673255 100755 (executable)
@@ -27,13 +27,14 @@ else
 endif
 
 LDFLAGS += -Wl,--rpath=$(PREFIX)/lib -Wl,--as-needed
-CONFIG := debian/slp.config
+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) 
+       CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" ./configure --prefix=$(PREFIX)
 
 build: build-stamp
 build-stamp:
@@ -43,6 +44,11 @@ build-stamp:
        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)
 
@@ -62,6 +68,7 @@ clean:
        dh_testroot
 
        $(MAKE) -C wpa_supplicant clean
+       #$(MAKE) -C hostapd clean
 
        #if [ -f wpa_supplicant/$(WPAGUI)/Makefile ]; then \
        #       $(MAKE) -C wpa_supplicant/$(WPAGUI) distclean ; \
@@ -69,34 +76,29 @@ clean:
 
        #$(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_clean -k
        dh_installdirs
        dh_install
 
        # Add here commands to install the package into debian/ncurses.
        #$(MAKE) DESTDIR=$(CURDIR)/debian/tmp install
 
-       # ifupdown
-       #install --mode=755 -D debian/ifupdown/ifupdown.sh \
-       #       debian/wpasupplicant/etc/wpa_supplicant/ifupdown.sh
-       #install --mode=755 -D debian/ifupdown/functions.sh \
-       #       debian/wpasupplicant/etc/wpa_supplicant/functions.sh
-       #install --mode=755 -D debian/ifupdown/action_wpa.sh \
-       #       debian/wpasupplicant/etc/wpa_supplicant/action_wpa.sh
-
-       # wpa_action
-       #install --mode=755 -D debian/ifupdown/wpa_action.sh \
-       #       debian/wpasupplicant/sbin/wpa_action
-
        # D-Bus
        install --mode=644 -D wpa_supplicant/dbus/dbus-wpa_supplicant.conf \
                debian/wpasupplicant/$(PREFIX)/etc/dbus-1/system.d/wpa_supplicant.conf
@@ -104,6 +106,12 @@ install: build
                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
@@ -120,12 +128,12 @@ binary-indep: build install
 binary-arch: build install
        dh_testdir
        dh_testroot
-#      dh_installchangelogs 
+#      dh_installchangelogs
 #      dh_installdocs
 #      dh_installexamples
 #      dh_install --sourcedir=debian/tmp
 #      dh_installmenu
-#      dh_installdebconf       
+#      dh_installdebconf
 #      dh_installlogrotate
 #      dh_installemacsen
 #      dh_installpam
@@ -148,4 +156,4 @@ binary-arch: build install
        dh_builddeb
 
 binary: binary-indep binary-arch
-.PHONY: build clean binary-indep binary-arch binary install 
+.PHONY: build clean binary-indep binary-arch binary install
diff --git a/debian/wpa_supplicant.conf b/debian/wpa_supplicant.conf
deleted file mode 100644 (file)
index 8905c59..0000000
+++ /dev/null
@@ -1 +0,0 @@
-ctrl_interface=/var/run/wpa_supplicant
index 78b4308..a07f514 100644 (file)
@@ -1 +1,4 @@
-wpa_supplicant/wpa_supplicant @PREFIX@/bin/
+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/Makefile b/doc/Makefile
new file mode 100644 (file)
index 0000000..5c1b386
--- /dev/null
@@ -0,0 +1,26 @@
+all: docs
+
+%.eps: %.fig
+       fig2dev -L eps $*.fig $*.eps
+
+%.png: %.fig
+       fig2dev -L png -m 3 $*.fig | pngtopnm | pnmscale 0.4 | pnmtopng \
+               > $*.png
+
+docs-pics: wpa_supplicant.png wpa_supplicant.eps hostapd.png hostapd.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
+       (cd ..; doxygen doc/doxygen.conf; cd doc)
+
+clean:
+       rm -f *~
+       rm -f wpa_supplicant.eps wpa_supplicant.png
+       rm -f hostapd.eps hostapd.png
+       rm -f doxygen.warnings
+       rm -rf html latex
+       rm -f wpa_supplicant-devel.pdf
diff --git a/doc/code_structure.doxygen b/doc/code_structure.doxygen
new file mode 100644 (file)
index 0000000..96f6160
--- /dev/null
@@ -0,0 +1,322 @@
+/**
+\page code_structure Structure of the source code
+
+[ \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" |
+\ref configuration "Configuration" |
+\ref ctrl_iface "Control interface" |
+\ref wpa_code "WPA supplicant" |
+\ref eap_peer "EAP peer" |
+\ref eapol_supp "EAPOL supplicant" |
+\ref win_port "Windows port" |
+\ref test_programs "Test programs" ]
+
+%wpa_supplicant implementation is divided into number of independent
+modules. Core code includes functionality for controlling the network
+selection, association, and configuration. Independent modules include
+WPA code (key handshake, PMKSA caching, pre-authentication), EAPOL
+state machine, and EAP state machine and methods. In addition, there
+are number of separate files for generic helper functions.
+
+Both WPA and EAPOL/EAP state machines can be used separately in other
+programs than %wpa_supplicant. As an example, the included test
+programs eapol_test and preauth_test are using these modules.
+
+\ref driver_wrapper "Driver interface API" is defined in driver.h and
+all hardware/driver dependent functionality is implemented in
+driver_*.c.
+
+
+\section wpa_supplicant_core wpa_supplicant core functionality
+
+wpa_supplicant.c
+       Program initialization, main control loop
+
+main.c
+       main() for UNIX-like operating systems and MinGW (Windows); this
+       uses command line arguments to configure wpa_supplicant
+
+events.c
+       Driver event processing; wpa_supplicant_event() and related functions
+
+wpa_supplicant_i.h
+       Internal definitions for %wpa_supplicant core; should not be
+       included into independent modules
+
+
+\section generic_helper_func Generic helper functions
+
+%wpa_supplicant uses generic helper functions some of which are shared
+with with hostapd. The following C files are currently used:
+
+eloop.c and eloop.h
+       Event loop (select() loop with registerable timeouts, socket read
+       callbacks, and signal callbacks)
+
+common.c and common.h
+       Common helper functions
+
+defs.h
+       Definitions shared by multiple files
+
+l2_packet.h, l2_packet_linux.c, and l2_packet_pcap.c
+       Layer 2 (link) access wrapper (includes native Linux implementation
+       and wrappers for libdnet/libpcap). A new l2_packet implementation
+       may need to be added when porting to new operating systems that are
+       not supported by libdnet/libpcap. Makefile can be used to select which
+       l2_packet implementation is included. l2_packet_linux.c uses Linux
+       packet sockets and l2_packet_pcap.c has a more portable version using
+       libpcap and libdnet.
+
+pcsc_funcs.c and pcsc_funcs.h
+       Wrapper for PC/SC lite SIM and smart card readers
+
+priv_netlink.h
+       Private version of netlink definitions from Linux kernel header files;
+       this could be replaced with C library header file once suitable
+       version becomes commonly available
+
+version.h
+       Version number definitions
+
+wireless_copy.h
+       Private version of Linux wireless extensions definitions from kernel
+       header files; this could be replaced with C library header file once
+       suitable version becomes commonly available
+
+
+\section crypto_func Cryptographic functions
+
+md5.c and md5.h
+       MD5 (replaced with a crypto library if TLS support is included)
+       HMAC-MD5 (keyed checksum for message authenticity validation)
+
+rc4.c and rc4.h
+       RC4 (broadcast/default key encryption)
+
+sha1.c and sha1.h
+       SHA-1 (replaced with a crypto library if TLS support is included)
+       HMAC-SHA-1 (keyed checksum for message authenticity validation)
+       PRF-SHA-1 (pseudorandom (key/nonce generation) function)
+       PBKDF2-SHA-1 (ASCII passphrase to shared secret)
+       T-PRF (for EAP-FAST)
+       TLS-PRF (RFC 2246)
+
+sha256.c and sha256.h
+       SHA-256 (replaced with a crypto library if TLS support is included)
+
+aes_wrap.c, aes_wrap.h, aes.c
+       AES (replaced with a crypto library if TLS support is included),
+       AES Key Wrap Algorithm with 128-bit KEK, RFC3394 (broadcast/default
+       key encryption),
+       One-Key CBC MAC (OMAC1) hash with AES-128,
+       AES-128 CTR mode encryption,
+       AES-128 EAX mode encryption/decryption,
+       AES-128 CBC
+
+crypto.h
+       Definition of crypto library wrapper
+
+crypto_openssl.c
+       Wrapper functions for libcrypto (OpenSSL)
+
+crypto_internal.c
+       Wrapper functions for internal crypto implementation
+
+crypto_gnutls.c
+       Wrapper functions for libgcrypt (used by GnuTLS)
+
+ms_funcs.c and ms_funcs.h
+       Helper functions for MSCHAPV2 and LEAP
+
+tls.h
+       Definition of TLS library wrapper
+
+tls_none.c
+       Dummy implementation of TLS library wrapper for cases where TLS
+       functionality is not included.
+
+tls_openssl.c
+       TLS library wrapper for openssl
+
+tls_internal.c
+       TLS library for internal TLS implementation
+
+tls_gnutls.c
+       TLS library wrapper for GnuTLS
+
+
+\section tls_func TLS library
+
+asn1.c and asn1.h
+       ASN.1 DER parsing
+
+bignum.c and bignum.h
+       Big number math
+
+rsa.c and rsa.h
+       RSA
+
+x509v3.c and x509v3.h
+       X.509v3 certificate parsing and processing
+
+tlsv1_client.c, tlsv1_client.h
+       TLSv1 client (RFC 2246)
+
+tlsv1_client_i.h
+       Internal structures for TLSv1 client
+
+tlsv1_client_read.c
+       TLSv1 client: read handshake messages
+
+tlsv1_client_write.c
+       TLSv1 client: write handshake messages
+
+tlsv1_common.c and tlsv1_common.h
+       Common TLSv1 routines and definitions
+
+tlsv1_cred.c and tlsv1_cred.h
+       TLSv1 credentials
+
+tlsv1_record.c and tlsv1_record.h
+       TLSv1 record protocol
+
+
+\section configuration Configuration
+
+config_ssid.h
+       Definition of per network configuration items
+
+config.h
+       Definition of the %wpa_supplicant configuration
+
+config.c
+       Configuration parser and common functions
+
+config_file.c
+       Configuration backend for text files (e.g., wpa_supplicant.conf)
+
+config_winreg.c
+       Configuration backend for Windows registry
+
+
+\section ctrl_iface Control interface
+
+%wpa_supplicant has a \ref ctrl_iface_page "control interface"
+that can be used to get status
+information and manage operations from external programs. An example
+command line interface (wpa_cli) and GUI (wpa_gui) for this interface
+are included in the %wpa_supplicant distribution.
+
+ctrl_iface.c and ctrl_iface.h
+       %wpa_supplicant-side of the control interface
+
+ctrl_iface_unix.c
+       UNIX domain sockets -based control interface backend
+
+ctrl_iface_udp.c
+       UDP sockets -based control interface backend
+
+ctrl_iface_named_pipe.c
+       Windows named pipes -based control interface backend
+
+wpa_ctrl.c and wpa_ctrl.h
+       Library functions for external programs to provide access to the
+       %wpa_supplicant control interface
+
+wpa_cli.c
+       Example program for using %wpa_supplicant control interface
+
+
+\section wpa_code WPA supplicant
+
+wpa.c and wpa.h
+       WPA state machine and 4-Way/Group Key Handshake processing
+
+preauth.c and preauth.h
+       PMKSA caching and pre-authentication (RSN/WPA2)
+
+wpa_i.h
+       Internal definitions for WPA code; not to be included to other modules.
+
+\section eap_peer EAP peer
+
+\ref eap_peer_module "EAP peer implementation" is a separate module that
+can be used by other programs than just %wpa_supplicant.
+
+eap.c and eap.h
+       EAP state machine and method interface
+
+eap_defs.h
+       Common EAP definitions
+
+eap_i.h
+       Internal definitions for EAP state machine and EAP methods; not to be
+       included in other modules
+
+eap_sim_common.c and eap_sim_common.h
+       Common code for EAP-SIM and EAP-AKA
+
+eap_tls_common.c and eap_tls_common.h
+       Common code for EAP-PEAP, EAP-TTLS, and EAP-FAST
+
+eap_tlv.c and eap_tlv.h
+       EAP-TLV code for EAP-PEAP and EAP-FAST
+
+eap_ttls.c and eap_ttls.h
+       EAP-TTLS
+
+eap_pax.c, eap_pax_common.h, eap_pax_common.c
+       EAP-PAX
+
+eap_psk.c, eap_psk_common.h, eap_psk_common.c
+       EAP-PSK (note: this is not needed for WPA-PSK)
+
+eap_sake.c, eap_sake_common.h, eap_sake_common.c
+       EAP-SAKE
+
+eap_gpsk.c, eap_gpsk_common.h, eap_gpsk_common.c
+       EAP-GPSK
+
+eap_aka.c, eap_fast.c, eap_gtc.c, eap_leap.c, eap_md5.c, eap_mschapv2.c,
+eap_otp.c, eap_peap.c, eap_sim.c, eap_tls.c
+       Other EAP method implementations
+
+
+\section eapol_supp EAPOL supplicant
+
+eapol_supp_sm.c and eapol_supp_sm.h
+       EAPOL supplicant state machine and IEEE 802.1X processing
+
+
+\section win_port Windows port
+
+ndis_events.c
+       Code for receiving NdisMIndicateStatus() events and delivering them to
+       %wpa_supplicant driver_ndis.c in more easier to use form
+
+win_if_list.c
+       External program for listing current network interface
+
+
+\section test_programs Test programs
+
+radius_client.c and radius_client.h
+       RADIUS authentication client implementation for eapol_test
+
+radius.c and radius.h
+       RADIUS message processing for eapol_test
+
+eapol_test.c
+       Standalone EAP testing tool with integrated RADIUS authentication
+       client
+
+preauth_test.c
+       Standalone RSN pre-authentication tool
+
+wpa_passphrase.c
+       WPA ASCII passphrase to PSK conversion
+
+*/
diff --git a/doc/ctrl_iface.doxygen b/doc/ctrl_iface.doxygen
new file mode 100644 (file)
index 0000000..f820f9e
--- /dev/null
@@ -0,0 +1,1053 @@
+/**
+\page ctrl_iface_page %wpa_supplicant control interface
+
+%wpa_supplicant implements a control interface that can be used by
+external programs to control the operations of the %wpa_supplicant
+daemon and to get status information and event notifications. There is
+a small C library, in a form of a single C file, wpa_ctrl.c, that
+provides helper functions to facilitate the use of the control
+interface. External programs can link this file into them and then use
+the library functions documented in wpa_ctrl.h to interact with
+%wpa_supplicant. This library can also be used with C++. wpa_cli.c and
+wpa_gui are example programs using this library.
+
+There are multiple mechanisms for inter-process communication. For
+example, Linux version of %wpa_supplicant is using UNIX domain sockets
+for the control interface and Windows version UDP sockets. The use of
+the functions defined in wpa_ctrl.h can be used to hide the details of
+the used IPC from external programs.
+
+
+\section using_ctrl_iface Using the control interface
+
+External programs, e.g., a GUI or a configuration utility, that need to
+communicate with %wpa_supplicant should link in wpa_ctrl.c. This
+allows them to use helper functions to open connection to the control
+interface with wpa_ctrl_open() and to send commands with
+wpa_ctrl_request().
+
+%wpa_supplicant uses the control interface for two types of communication:
+commands and unsolicited event messages. Commands are a pair of
+messages, a request from the external program and a response from
+%wpa_supplicant. These can be executed using wpa_ctrl_request().
+Unsolicited event messages are sent by %wpa_supplicant to the control
+interface connection without specific request from the external program
+for receiving each message. However, the external program needs to
+attach to the control interface with wpa_ctrl_attach() to receive these
+unsolicited messages.
+
+If the control interface connection is used both for commands and
+unsolicited event messages, there is potential for receiving an
+unsolicited message between the command request and response.
+wpa_ctrl_request() caller will need to supply a callback, msg_cb,
+for processing these messages. Often it is easier to open two
+control interface connections by calling wpa_ctrl_open() twice and
+then use one of the connections for commands and the other one for
+unsolicited messages. This way command request/response pairs will
+not be broken by unsolicited messages. wpa_cli is an example of how
+to use only one connection for both purposes and wpa_gui demonstrates
+how to use two separate connections.
+
+Once the control interface connection is not needed anymore, it should
+be closed by calling wpa_ctrl_close(). If the connection was used for
+unsolicited event messages, it should be first detached by calling
+wpa_ctrl_detach().
+
+
+\section ctrl_iface_cmds Control interface commands
+
+Following commands can be used with wpa_ctrl_request():
+
+\subsection ctrl_iface_PING PING
+
+This command can be used to test whether %wpa_supplicant is replying
+to the control interface commands. The expected reply is \c PONG if the
+connection is open and %wpa_supplicant is processing commands.
+
+
+\subsection ctrl_iface_MIB MIB
+
+Request a list of MIB variables (dot1x, dot11). The output is a text
+block with each line in \c variable=value format. For example:
+
+\verbatim
+dot11RSNAOptionImplemented=TRUE
+dot11RSNAPreauthenticationImplemented=TRUE
+dot11RSNAEnabled=FALSE
+dot11RSNAPreauthenticationEnabled=FALSE
+dot11RSNAConfigVersion=1
+dot11RSNAConfigPairwiseKeysSupported=5
+dot11RSNAConfigGroupCipherSize=128
+dot11RSNAConfigPMKLifetime=43200
+dot11RSNAConfigPMKReauthThreshold=70
+dot11RSNAConfigNumberOfPTKSAReplayCounters=1
+dot11RSNAConfigSATimeout=60
+dot11RSNAAuthenticationSuiteSelected=00-50-f2-2
+dot11RSNAPairwiseCipherSelected=00-50-f2-4
+dot11RSNAGroupCipherSelected=00-50-f2-4
+dot11RSNAPMKIDUsed=
+dot11RSNAAuthenticationSuiteRequested=00-50-f2-2
+dot11RSNAPairwiseCipherRequested=00-50-f2-4
+dot11RSNAGroupCipherRequested=00-50-f2-4
+dot11RSNAConfigNumberOfGTKSAReplayCounters=0
+dot11RSNA4WayHandshakeFailures=0
+dot1xSuppPaeState=5
+dot1xSuppHeldPeriod=60
+dot1xSuppAuthPeriod=30
+dot1xSuppStartPeriod=30
+dot1xSuppMaxStart=3
+dot1xSuppSuppControlledPortStatus=Authorized
+dot1xSuppBackendPaeState=2
+dot1xSuppEapolFramesRx=0
+dot1xSuppEapolFramesTx=440
+dot1xSuppEapolStartFramesTx=2
+dot1xSuppEapolLogoffFramesTx=0
+dot1xSuppEapolRespFramesTx=0
+dot1xSuppEapolReqIdFramesRx=0
+dot1xSuppEapolReqFramesRx=0
+dot1xSuppInvalidEapolFramesRx=0
+dot1xSuppEapLengthErrorFramesRx=0
+dot1xSuppLastEapolFrameVersion=0
+dot1xSuppLastEapolFrameSource=00:00:00:00:00:00
+\endverbatim
+
+
+\subsection ctrl_iface_STATUS STATUS
+
+Request current WPA/EAPOL/EAP status information. The output is a text
+block with each line in \c variable=value format. For example:
+
+\verbatim
+bssid=02:00:01:02:03:04
+ssid=test network
+pairwise_cipher=CCMP
+group_cipher=CCMP
+key_mgmt=WPA-PSK
+wpa_state=COMPLETED
+ip_address=192.168.1.21
+Supplicant PAE state=AUTHENTICATED
+suppPortStatus=Authorized
+EAP state=SUCCESS
+\endverbatim
+
+
+\subsection ctrl_iface_STATUS-VERBOSE STATUS-VERBOSE
+
+Same as STATUS, but with more verbosity (i.e., more \c variable=value pairs).
+
+\verbatim
+bssid=02:00:01:02:03:04
+ssid=test network
+id=0
+pairwise_cipher=CCMP
+group_cipher=CCMP
+key_mgmt=WPA-PSK
+wpa_state=COMPLETED
+ip_address=192.168.1.21
+Supplicant PAE state=AUTHENTICATED
+suppPortStatus=Authorized
+heldPeriod=60
+authPeriod=30
+startPeriod=30
+maxStart=3
+portControl=Auto
+Supplicant Backend state=IDLE
+EAP state=SUCCESS
+reqMethod=0
+methodState=NONE
+decision=COND_SUCC
+ClientTimeout=60
+\endverbatim
+
+
+\subsection ctrl_iface_PMKSA PMKSA
+
+Show PMKSA cache
+
+\verbatim
+Index / AA / PMKID / expiration (in seconds) / opportunistic
+1 / 02:00:01:02:03:04 / 000102030405060708090a0b0c0d0e0f / 41362 / 0
+2 / 02:00:01:33:55:77 / 928389281928383b34afb34ba4212345 / 362 / 1
+\endverbatim
+
+
+\subsection ctrl_iface_SET SET <variable> <value>
+
+Set variables:
+- EAPOL::heldPeriod
+- EAPOL::authPeriod
+- EAPOL::startPeriod
+- EAPOL::maxStart
+- dot11RSNAConfigPMKLifetime
+- dot11RSNAConfigPMKReauthThreshold
+- dot11RSNAConfigSATimeout
+
+Example command:
+\verbatim
+SET EAPOL::heldPeriod 45
+\endverbatim
+
+
+\subsection ctrl_iface_LOGON LOGON
+
+IEEE 802.1X EAPOL state machine logon.
+
+
+\subsection ctrl_iface_LOGOFF LOGOFF
+
+IEEE 802.1X EAPOL state machine logoff.
+
+
+\subsection ctrl_iface_REASSOCIATE REASSOCIATE
+
+Force reassociation.
+
+
+\subsection ctrl_iface_RECONNECT RECONNECT
+
+Connect if disconnected (i.e., like \c REASSOCIATE, but only connect
+if in disconnected state).
+
+
+\subsection ctrl_iface_PREAUTH PREAUTH <BSSID>
+
+Start pre-authentication with the given BSSID.
+
+
+\subsection ctrl_iface_ATTACH ATTACH
+
+Attach the connection as a monitor for unsolicited events. This can
+be done with wpa_ctrl_attach().
+
+
+\subsection ctrl_iface_DETACH DETACH
+
+Detach the connection as a monitor for unsolicited events. This can
+be done with wpa_ctrl_detach().
+
+
+\subsection ctrl_iface_LEVEL LEVEL <debug level>
+
+Change debug level.
+
+
+\subsection ctrl_iface_RECONFIGURE RECONFIGURE
+
+Force %wpa_supplicant to re-read its configuration data.
+
+
+\subsection ctrl_iface_TERMINATE TERMINATE
+
+Terminate %wpa_supplicant process.
+
+
+\subsection ctrl_iface_BSSID BSSID <network id> <BSSID>
+
+Set preferred BSSID for a network. Network id can be received from the
+\c LIST_NETWORKS command output.
+
+
+\subsection ctrl_iface_LIST_NETWORKS LIST_NETWORKS
+
+List configured networks.
+
+\verbatim
+network id / ssid / bssid / flags
+0      example network any     [CURRENT]
+\endverbatim
+
+(note: fields are separated with tabs)
+
+
+\subsection ctrl_iface_DISCONNECT DISCONNECT
+
+Disconnect and wait for \c REASSOCIATE or \c RECONNECT command before
+connecting.
+
+
+\subsection ctrl_iface_SCAN SCAN
+
+Request a new BSS scan.
+
+
+\subsection ctrl_iface_SCAN_RESULTS SCAN_RESULTS
+
+Get the latest scan results.
+
+\verbatim
+bssid / frequency / signal level / flags / ssid
+00:09:5b:95:e0:4e      2412    208     [WPA-PSK-CCMP]  jkm private
+02:55:24:33:77:a3      2462    187     [WPA-PSK-TKIP]  testing
+00:09:5b:95:e0:4f      2412    209             jkm guest
+\endverbatim
+
+(note: fields are separated with tabs)
+
+
+\subsection ctrl_iface_BSS BSS
+
+Get detailed per-BSS scan results. \c BSS command can be used to
+iterate through scan results one BSS at a time and to fetch all
+information from the found BSSes. This provides access to the same
+data that is available through \c SCAN_RESULTS but in a way that
+avoids problems with large number of scan results not fitting in the
+ctrl_iface messages.
+
+There are two options for selecting the BSS with the \c BSS command:
+"BSS <idx>" requests information for the BSS identified by the index
+(0 .. size-1) in the scan results table and "BSS <BSSID>" requests
+information for the given BSS (based on BSSID in 00:01:02:03:04:05
+format).
+
+BSS information is presented in following format. Please note that new
+fields may be added to this field=value data, so the ctrl_iface user
+should be prepared to ignore values it does not understand.
+
+\verbatim
+bssid=00:09:5b:95:e0:4e
+freq=2412
+beacon_int=0
+capabilities=0x0011
+qual=51
+noise=161
+level=212
+tsf=0000000000000000
+ie=000b6a6b6d2070726976617465010180dd180050f20101000050f20401000050f20401000050f2020000
+ssid=jkm private
+\endverbatim
+
+
+
+\subsection ctrl_iface_SELECT_NETWORK SELECT_NETWORK <network id>
+
+Select a network (disable others). Network id can be received from the
+\c LIST_NETWORKS command output.
+
+
+\subsection ctrl_iface_ENABLE_NETWORK ENABLE_NETWORK <network id>
+
+Enable a network. Network id can be received from the
+\c LIST_NETWORKS command output. Special network id \c all can be
+used to enable all network.
+
+
+\subsection ctrl_iface_DISABLE_NETWORK DISABLE_NETWORK <network id>
+
+Disable a network. Network id can be received from the
+\c LIST_NETWORKS command output. Special network id \c all can be
+used to disable all network.
+
+
+\subsection ctrl_iface_ADD_NETWORK ADD_NETWORK
+
+Add a new network. This command creates a new network with empty
+configuration. The new network is disabled and once it has been
+configured it can be enabled with \c ENABLE_NETWORK command. \c ADD_NETWORK
+returns the network id of the new network or FAIL on failure.
+
+
+\subsection ctrl_iface_REMOVE_NETWORK REMOVE_NETWORK <network id>
+
+Remove a network. Network id can be received from the
+\c LIST_NETWORKS command output. Special network id \c all can be
+used to remove all network.
+
+
+\subsection ctrl_iface_SET_NETWORK SET_NETWORK <network id> <variable> <value>
+
+Set network variables. Network id can be received from the
+\c LIST_NETWORKS command output.
+
+This command uses the same variables and data formats as the
+configuration file. See example wpa_supplicant.conf for more details.
+
+- ssid (network name, SSID)
+- psk (WPA passphrase or pre-shared key)
+- key_mgmt (key management protocol)
+- identity (EAP identity)
+- password (EAP password)
+- ...
+
+
+\subsection ctrl_iface_GET_NETWORK GET_NETWORK <network id> <variable>
+
+Get network variables. Network id can be received from the
+\c LIST_NETWORKS command output.
+
+
+\subsection ctrl_iface_SAVE_CONFIG SAVE_CONFIG
+
+Save the current configuration.
+
+
+\subsection ctrl_iface_P2P_FIND P2P_FIND
+
+Start P2P device discovery. Optional parameter can be used to specify
+the duration for the discovery in seconds (e.g., "P2P_FIND 5"). If the
+duration is not specified, discovery will be started for indefinite
+time, i.e., until it is terminated by P2P_STOP_FIND or P2P_CONNECT (to
+start group formation with a discovered peer).
+
+The default search type is to first run a full scan of all channels
+and then continue scanning only social channels (1, 6, 11). This
+behavior can be changed by specifying a different search type: social
+(e.g., "P2P_FIND 5 type=social") will skip the initial full scan and
+only search social channels; progressive (e.g., "P2P_FIND
+type=progressive") starts with a full scan and then searches
+progressively through all channels one channel at the time with the
+social channel scans. Progressive device discovery can be used to find
+new groups (and groups that were not found during the initial scan,
+e.g., due to the GO being asleep) over time without adding
+considerable extra delay for every Search state round.
+
+
+\subsection ctrl_iface_P2P_STOP_FIND P2P_STOP_FIND
+
+Stop ongoing P2P device discovery or other operation (connect, listen
+mode).
+
+
+\subsection ctrl_iface_P2P_CONNECT P2P_CONNECT
+
+Start P2P group formation with a discovered P2P peer. This includes
+group owner negotiation, group interface setup, provisioning, and
+establishing data connection.
+
+P2P_CONNECT <peer device address> <pbc|pin|PIN#>
+[label|display|keypad] [persistent] [join|auth] [go_intent=<0..15>]
+
+Start P2P group formation with a discovered P2P peer. This includes
+optional group owner negotiation, group interface setup, provisioning,
+and establishing data connection.
+
+The <pbc|pin|PIN#> parameter specifies the WPS provisioning
+method. "pbc" string starts pushbutton method, "pin" string start PIN
+method using an automatically generated PIN (which will be returned as
+the command return code), PIN# means that a pre-selected PIN can be
+used (e.g., 12345670). [label|display|keypad] is used with PIN method
+to specify which PIN is used (label=PIN from local label,
+display=dynamically generated random PIN from local display,
+keypad=PIN entered from peer device label or display). "persistent"
+parameter can be used to request a persistent group to be formed.
+
+"join" indicates that this is a command to join an existing group as a
+client. It skips the GO Negotiation part.
+
+"auth" indicates that the WPS parameters are authorized for the peer
+device without actually starting GO Negotiation (i.e., the peer is
+expected to initiate GO Negotiation). This is mainly for testing
+purposes.
+
+The optional "go_intent" parameter can be used to override the default
+GO Intent value.
+
+
+\subsection ctrl_iface_P2P_LISTEN P2P_LISTEN
+
+Start Listen-only state. Optional parameter can be used to specify the
+duration for the Listen operation in seconds. This command may not
+be of that much use during normal operations and is mainly designed
+for testing. It can also be used to keep the device discoverable
+without having to maintain a group.
+
+
+\subsection ctrl_iface_P2P_GROUP_REMOVE P2P_GROUP_REMOVE
+
+Terminate a P2P group. If a new virtual network interface was used for
+the group, it will also be removed. The network interface name of the
+group interface is used as a parameter for this command.
+
+
+\subsection ctrl_iface_P2P_GROUP_ADD P2P_GROUP_ADD
+
+Set up a P2P group owner manually (i.e., without group owner
+negotiation with a specific peer). This is also known as autonomous
+GO. Optional persistent=<network id> can be used to specify restart of
+a persistent group.
+
+
+\subsection ctrl_iface_P2P_PROV_DISC P2P_PROV_DISC
+
+Send P2P provision discovery request to the specified peer. The
+parameters for this command are the P2P device address of the peer and
+the desired configuration method. For example, "P2P_PROV_DISC
+02:01:02:03:04:05 display" would request the peer to display a PIN for
+us and "P2P_PROV_DISC 02:01:02:03:04:05 keypad" would request the peer
+to enter a PIN that we display.
+
+
+\subsection ctrl_iface_P2P_GET_PASSPHRASE P2P_GET_PASSPHRASE
+
+Get the passphrase for a group (only available when acting as a GO).
+
+
+\subsection ctrl_iface_P2P_SERV_DISC_REQ P2P_SERV_DISC_REQ
+
+Schedule a P2P service discovery request. The parameters for this
+command are the device address of the peer device (or 00:00:00:00:00:00
+for wildcard query that is sent to every discovered P2P peer that
+supports service discovery) and P2P Service Query TLV(s) as hexdump.
+For example, "P2P_SERV_DISC_REQ 00:00:00:00:00:00 02000001" schedules
+a request for listing all supported service discovery protocols and
+requests this to be sent to all discovered peers. The pending requests
+are sent during device discovery (see \ref ctrl_iface_P2P_FIND).
+
+This command returns an identifier for the pending query (e.g.,
+"1f77628") that can be used to cancel the request. Directed requests
+will be automatically removed when the specified peer has replied to
+it.
+
+
+\subsection ctrl_iface_P2P_SERV_DISC_CANCEL_REQ P2P_SERV_DISC_CANCEL_REQ
+
+Cancel a pending P2P service discovery request. This command takes a
+single parameter: identifier for the pending query (the value returned
+by \ref ctrl_iface_P2P_SERV_DISC_REQ), e.g.,
+"P2P_SERV_DISC_CANCEL_REQ 1f77628".
+
+
+\subsection ctrl_iface_P2P_SERV_DISC_RESP P2P_SERV_DISC_RESP
+
+Reply to a service discovery query. This command takes following
+parameters: frequency in MHz, destination address, dialog token,
+response TLV(s). The first three parameters are copied from the
+request event. For example,
+"P2P_SERV_DISC_RESP 2437 02:40:61:c2:f3:b7 1 0300000101".
+
+
+\subsection ctrl_iface_P2P_SERVICE_UPDATE P2P_SERVICE_UPDATE
+
+Indicate that local services have changed. This is used to increment
+the P2P service indicator value so that peers know when previously
+cached information may have changed.
+
+
+\subsection ctrl_iface_P2P_SERV_DISC_EXTERNAL P2P_SERV_DISC_EXTERNAL
+
+Configure external processing of P2P service requests: 0 (default) =
+no external processing of requests (i.e., internal code will reject
+each request), 1 = external processing of requests (external program
+is responsible for replying to service discovery requests with
+\ref ctrl_iface_P2P_SERV_DISC_RESP).
+
+
+\subsection ctrl_iface_P2P_REJECT P2P_REJECT
+
+Reject connection attempt from a peer (specified with a device
+address). This is a mechanism to reject a pending GO Negotiation with
+a peer and request to automatically block any further connection or
+discovery of the peer.
+
+
+\subsection ctrl_iface_P2P_INVITE P2P_INVITE
+
+Invite a peer to join a group or to (re)start a persistent group.
+
+
+\subsection ctrl_iface_P2P_PEER P2P_PEER
+
+Fetch information about a discovered peer. This command takes in an
+argument specifying which peer to select: P2P Device Address of the
+peer, "FIRST" to indicate the first peer in the list, or "NEXT-<P2P
+Device Address>" to indicate the entry following the specified peer
+(to allow for iterating through the list).
+
+
+\subsection ctrl_iface_P2P_EXT_LISTEN P2P_EXT_LISTEN
+
+Enable/disable extended listen timing. Without parameters, this
+command disables extended listen timing. When enabling the feature,
+two parameters are used: availibility period and availability interval
+(both in milliseconds and with range of 1-65535).
+
+
+\section ctrl_iface_interactive Interactive requests
+
+If %wpa_supplicant needs additional information during authentication
+(e.g., password), it will use a specific prefix, \c CTRL-REQ-
+(\a WPA_CTRL_REQ macro) in an unsolicited event message. An external
+program, e.g., a GUI, can provide such information by using
+\c CTRL-RSP- (\a WPA_CTRL_RSP macro) prefix in a command with matching
+field name.
+
+The following fields can be requested in this way from the user:
+- IDENTITY (EAP identity/user name)
+- PASSWORD (EAP password)
+- NEW_PASSWORD (New password if the server is requesting password change)
+- PIN (PIN code for accessing a SIM or smartcard)
+- OTP (one-time password; like password, but the value is used only once)
+- PASSPHRASE (passphrase for a private key file)
+
+\verbatim
+CTRL-REQ-<field name>-<network id>-<human readable text>
+CTRL-RSP-<field name>-<network id>-<value>
+\endverbatim
+
+For example, request from %wpa_supplicant:
+\verbatim
+CTRL-REQ-PASSWORD-1-Password needed for SSID test-network
+\endverbatim
+
+And a matching reply from the GUI:
+\verbatim
+CTRL-RSP-PASSWORD-1-secret
+\endverbatim
+
+
+\subsection ctrl_iface_GET_CAPABILITY GET_CAPABILITY <option> [strict]
+
+Get list of supported functionality (eap, pairwise, group,
+proto). Supported functionality is shown as space separate lists of
+values used in the same format as in %wpa_supplicant configuration.
+If optional argument, 'strict', is added, only the values that the
+driver claims to explicitly support are included. Without this, all
+available capabilities are included if the driver does not provide
+a mechanism for querying capabilities.
+
+Example request/reply pairs:
+
+\verbatim
+GET_CAPABILITY eap
+AKA FAST GTC LEAP MD5 MSCHAPV2 OTP PAX PEAP PSK SIM TLS TTLS
+\endverbatim
+
+\verbatim
+GET_CAPABILITY pairwise
+CCMP TKIP NONE
+\endverbatim
+
+\verbatim
+GET_CAPABILITY pairwise strict
+\endverbatim
+
+\verbatim
+GET_CAPABILITY group
+CCMP TKIP WEP104 WEP40
+\endverbatim
+
+\verbatim
+GET_CAPABILITY key_mgmt
+WPA-PSK WPA-EAP IEEE8021X NONE
+\endverbatim
+
+\verbatim
+GET_CAPABILITY proto
+RSN WPA
+\endverbatim
+
+\verbatim
+GET_CAPABILITY auth_alg
+OPEN SHARED LEAP
+\endverbatim
+
+
+\subsection ctrl_iface_AP_SCAN AP_SCAN <ap_scan value>
+
+Change ap_scan value:
+0 = no scanning,
+1 = %wpa_supplicant requests scans and uses scan results to select the AP,
+2 = %wpa_supplicant does not use scanning and just requests driver to
+associate and take care of AP selection
+
+
+\subsection ctrl_iface_INTERFACES INTERFACES
+
+List configured interfaces.
+
+\verbatim
+wlan0
+eth0
+\endverbatim
+
+
+\section ctrl_iface_events Control interface events
+
+%wpa_supplicant generates number messages based on events like
+connection or a completion of a task. These are available to external
+programs that attach to receive unsolicited messages over the control
+interface with wpa_ctrl_attach().
+
+The event messages will be delivered over the attach control interface
+as text strings that start with the priority level of the message and
+a fixed prefix text as defined in wpa_ctrl.h. After this, optional
+additional information may be included depending on the event
+message. For example, following event message is delivered when new
+scan results are available:
+
+\verbatim
+<2>CTRL-EVENT-SCAN-RESULTS
+\endverbatim
+
+Following priority levels are used:
+- 0 = MSGDUMP
+- 1 = DEBUG
+- 2 = INFO
+- 3 = WARNING
+- 4 = ERROR
+
+By default, any priority level greater than equal to 2 (INFO) are
+delivered over the attached control interface. LEVEL command can be
+used to set the level of messages which will be delivered. It should
+be noted that there are many debug messages that do not include any
+particulat prefix and are subject to change. They may be used for
+debug information, but can usually be ignored by external programs.
+
+In most cases, the external program can skip over the priority field
+in the beginning of the event message and then compare the following
+text to the event strings from wpa_ctrl.h that the program is
+interested in processing.
+
+Following subsections describe the most common event notifications
+generated by %wpa_supplicant.
+
+\subsection ctrl_iface_event_CTRL_REQ CTRL-REQ-
+
+WPA_CTRL_REQ: Request information from a user. See
+\ref ctrl_iface_interactive "Interactive requests" sections for more
+details.
+
+\subsection ctrl_iface_event_CONNECTED CTRL-EVENT-CONNECTED
+
+WPA_EVENT_CONNECTED: Indicate successfully completed authentication
+and that the data connection is now enabled.
+
+\subsection ctrl_iface_event_DISCONNECTED CTRL-EVENT-DISCONNECTED
+
+WPA_EVENT_DISCONNECTED: Disconnected, data connection is not available
+
+\subsection ctrl_iface_event_TERMINATING  CTRL-EVENT-TERMINATING
+
+WPA_EVENT_TERMINATING: %wpa_supplicant is exiting
+
+\subsection ctrl_iface_event_PASSWORD_CHANGED CTRL-EVENT-PASSWORD-CHANGED
+
+WPA_EVENT_PASSWORD_CHANGED: Password change was completed successfully
+
+\subsection ctrl_iface_event_EAP_NOTIFICATION CTRL-EVENT-EAP-NOTIFICATION
+
+WPA_EVENT_EAP_NOTIFICATION: EAP-Request/Notification received
+
+\subsection ctrl_iface_event_EAP_STARTED CTRL-EVENT-EAP-STARTED
+
+WPA_EVENT_EAP_STARTED: EAP authentication started (EAP-Request/Identity
+received)
+
+\subsection ctrl_iface_event_EAP_METHOD CTRL-EVENT-EAP-METHOD
+
+WPA_EVENT_EAP_METHOD: EAP method selected
+
+\subsection ctrl_iface_event_EAP_SUCCESS CTRL-EVENT-EAP-SUCCESS
+
+WPA_EVENT_EAP_SUCCESS: EAP authentication completed successfully
+
+\subsection ctrl_iface_event_EAP_FAILURE CTRL-EVENT-EAP-FAILURE
+
+WPA_EVENT_EAP_FAILURE: EAP authentication failed (EAP-Failure received)
+
+\subsection ctrl_iface_event_SCAN_RESULTS CTRL-EVENT-SCAN-RESULTS
+
+WPA_EVENT_SCAN_RESULTS: New scan results available
+
+\subsection ctrl_iface_event_BSS_ADDED CTRL-EVENT-BSS-ADDED
+
+WPA_EVENT_BSS_ADDED: A new BSS entry was added. The event prefix is
+followed by the BSS entry id and BSSID.
+
+\verbatim
+CTRL-EVENT-BSS-ADDED 34 00:11:22:33:44:55
+\endverbatim
+
+\subsection ctrl_iface_event_BSS_REMOVED CTRL-EVENT-BSS-REMOVED
+
+WPA_EVENT_BSS_REMOVED: A BSS entry was removed. The event prefix is
+followed by BSS entry id and BSSID.
+
+\verbatim
+CTRL-EVENT-BSS-REMOVED 34 00:11:22:33:44:55
+\endverbatim
+
+\subsection ctrl_iface_event_WPS_OVERLAP_DETECTED WPS-OVERLAP-DETECTED
+
+WPS_EVENT_OVERLAP: WPS overlap detected in PBC mode
+
+\subsection ctrl_iface_event_WPS_AP_AVAILABLE_PBC WPS-AP-AVAILABLE-PBC
+
+WPS_EVENT_AP_AVAILABLE_PBC: Available WPS AP with active PBC found in
+scan results.
+
+\subsection ctrl_iface_event_WPS_AP_AVAILABLE_PIN WPS-AP-AVAILABLE-PIN
+
+WPS_EVENT_AP_AVAILABLE_PIN: Available WPS AP with recently selected PIN
+registrar found in scan results.
+
+\subsection ctrl_iface_event_WPS_AP_AVAILABLE WPS-AP-AVAILABLE
+
+WPS_EVENT_AP_AVAILABLE: Available WPS AP found in scan results
+
+\subsection ctrl_iface_event_WPS_CRED_RECEIVED WPS-CRED-RECEIVED
+
+WPS_EVENT_CRED_RECEIVED: A new credential received
+
+\subsection ctrl_iface_event_WPS_M2D WPS-M2D
+
+WPS_EVENT_M2D: M2D received
+
+\subsection ctrl_iface_event_WPS_FAIL
+
+WPS_EVENT_FAIL: WPS registration failed after M2/M2D
+
+\subsection ctrl_iface_event_WPS_SUCCESS WPS-SUCCESS
+
+WPS_EVENT_SUCCESS: WPS registration completed successfully
+
+\subsection ctrl_iface_event_WPS_TIMEOUT WPS-TIMEOUT
+
+WPS_EVENT_TIMEOUT: WPS enrollment attempt timed out and was terminated
+
+\subsection ctrl_iface_event_WPS_ENROLLEE_SEEN WPS-ENROLLEE-SEEN
+
+WPS_EVENT_ENROLLEE_SEEN: WPS Enrollee was detected (used in AP mode).
+The event prefix is followed by MAC addr, UUID-E, pri dev type,
+config methods, dev passwd id, request type, [dev name].
+
+\verbatim
+WPS-ENROLLEE-SEEN 02:00:00:00:01:00
+572cf82f-c957-5653-9b16-b5cfb298abf1 1-0050F204-1 0x80 4 1
+[Wireless Client]
+\endverbatim
+
+\subsection ctrl_iface_event_WPS_ER_AP_ADD WPS-ER-AP-ADD
+
+WPS_EVENT_ER_AP_ADD: WPS ER discovered an AP
+
+\verbatim
+WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002 02:11:22:33:44:55
+pri_dev_type=6-0050F204-1 wps_state=1 |Very friendly name|Company|
+Long description of the model|WAP|http://w1.fi/|http://w1.fi/hostapd/
+\endverbatim
+
+\subsection ctrl_iface_event_WPS_ER_AP_REMOVE WPS-ER-AP-REMOVE
+
+WPS_EVENT_ER_AP_REMOVE: WPS ER removed an AP entry
+
+\verbatim
+WPS-ER-AP-REMOVE 87654321-9abc-def0-1234-56789abc0002
+\endverbatim
+
+\subsection ctrl_iface_event_WPS_ER_ENROLLEE_ADD WPS-ER-ENROLLEE-ADD
+
+WPS_EVENT_ER_ENROLLEE_ADD: WPS ER discovered a new Enrollee
+
+\verbatim
+WPS-ER-ENROLLEE-ADD 2b7093f1-d6fb-5108-adbb-bea66bb87333
+02:66:a0:ee:17:27 M1=1 config_methods=0x14d dev_passwd_id=0
+pri_dev_type=1-0050F204-1
+|Wireless Client|Company|cmodel|123|12345|
+\endverbatim
+
+\subsection ctrl_iface_event_WPS_ER_ENROLLEE_REMOVE WPS-ER-ENROLLEE-REMOVE
+
+WPS_EVENT_ER_ENROLLEE_REMOVE: WPS ER removed an Enrollee entry
+
+\verbatim
+WPS-ER-ENROLLEE-REMOVE 2b7093f1-d6fb-5108-adbb-bea66bb87333
+02:66:a0:ee:17:27
+\endverbatim
+
+\subsection ctrl_iface_event_WPS_PIN_NEEDED WPS-PIN-NEEDED
+
+WPS_EVENT_PIN_NEEDED: PIN is needed to complete provisioning with an
+Enrollee. This is followed by information about the Enrollee (UUID,
+MAC address, device name, manufacturer, model name, model number,
+serial number, primary device type).
+\verbatim
+WPS-PIN-NEEDED 5a02a5fa-9199-5e7c-bc46-e183d3cb32f7 02:2a:c4:18:5b:f3
+[Wireless Client|Company|cmodel|123|12345|1-0050F204-1]
+\endverbatim
+
+\subsection ctrl_iface_event_WPS_NEW_AP_SETTINGS WPS-NEW-AP-SETTINGS
+
+WPS_EVENT_NEW_AP_SETTINGS: New AP settings were received
+
+\subsection ctrl_iface_event_WPS_REG_SUCCESS WPS-REG-SUCCESS
+
+WPS_EVENT_REG_SUCCESS: WPS provisioning was completed successfully
+(AP/Registrar)
+
+\subsection ctrl_iface_event_WPS_AP_SETUP_LOCKED WPS-AP-SETUP-LOCKED
+
+WPS_EVENT_AP_SETUP_LOCKED: AP changed into setup locked state due to
+multiple failed configuration attempts using the AP PIN.
+
+\subsection ctrl_iface_event_AP_STA_CONNECTED AP-STA-CONNECTED
+
+AP_STA_CONNECTED: A station associated with us (AP mode event). The
+event prefix is followed by the MAC address of the station.
+
+\verbatim
+AP-STA-CONNECTED 02:2a:c4:18:5b:f3
+\endverbatim
+
+\subsection ctrl_iface_event_AP_STA_DISCONNECTED AP-STA-DISCONNECTED
+
+AP_STA_DISCONNECTED: A station disassociated (AP mode event)
+
+\verbatim
+AP-STA-DISCONNECTED 02:2a:c4:18:5b:f3
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_DEVICE_FOUND P2P-DEVICE-FOUND
+
+P2P_EVENT_DEVICE_FOUND: Indication of a discovered P2P device with
+information about that device.
+
+\verbatim
+P2P-DEVICE-FOUND 02:b5:64:63:30:63 p2p_dev_addr=02:b5:64:63:30:63
+pri_dev_type=1-0050f204-1 name='Wireless Client' config_methods=0x84
+dev_capab=0x21 group_capab=0x0
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_GO_NEG_REQUEST P2P-GO-NEG-REQUEST
+
+P2P_EVENT_GO_NEG_REQUEST: A P2P device requested GO negotiation, but we
+were not ready to start the negotiation.
+
+\verbatim
+P2P-GO-NEG-REQUEST 02:40:61:c2:f3:b7 dev_passwd_id=4
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_GO_NEG_SUCCESS P2P-GO-NEG-SUCCESS
+
+P2P_EVENT_GO_NEG_SUCCESS: Indication of successfully complete group
+owner negotiation.
+
+\subsection ctrl_iface_event_P2P_EVENT_GO_NEG_FAILURE P2P-GO-NEG-FAILURE
+
+P2P_EVENT_GO_NEG_FAILURE: Indication of failed group owner negotiation.
+
+\subsection ctrl_iface_event_P2P_EVENT_GROUP_FORMATION_SUCCESS P2P-GROUP-FORMATION-SUCCESS
+
+P2P_EVENT_GROUP_FORMATION_SUCCESS: Indication that P2P group formation
+has been completed successfully.
+
+\subsection ctrl_iface_event_P2P_EVENT_GROUP_FORMATION_FAILURE P2P-GROUP-FORMATION-FAILURE
+
+P2P_EVENT_GROUP_FORMATION_FAILURE: Indication that P2P group formation
+failed (e.g., due to provisioning failure or timeout).
+
+\subsection ctrl_iface_event_P2P_EVENT_GROUP_STARTED P2P-GROUP-STARTED
+
+P2P_EVENT_GROUP_STARTED: Indication of a new P2P group having been
+started. Additional parameters: network interface name for the group,
+role (GO/client), SSID. The passphrase used in the group is also
+indicated here if known (on GO) or PSK (on client). If the group is a
+persistent one, a flag indicating that is included.
+
+\verbatim
+P2P-GROUP-STARTED wlan0-p2p-0 GO ssid="DIRECT-3F Testing"
+passphrase="12345678" go_dev_addr=02:40:61:c2:f3:b7 [PERSISTENT]
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_GROUP_REMOVED P2P-GROUP-REMOVED
+
+P2P_EVENT_GROUP_REMOVED: Indication of a P2P group having been removed.
+Additional parameters: network interface name for the group, role
+(GO/client).
+
+\verbatim
+P2P-GROUP-REMOVED wlan0-p2p-0 GO
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_PROV_DISC_SHOW_PIN P2P-PROV-DISC-SHOW-PIN
+
+P2P_EVENT_PROV_DISC_SHOW_PIN: Request from the peer for us to display
+a PIN that will be entered on the peer. The following parameters are
+included after the event prefix: peer_address PIN. The PIN is a
+random PIN generated for this connection. P2P_CONNECT command can be
+used to accept the request with the same PIN configured for the
+connection.
+
+\verbatim
+P2P-PROV-DISC-SHOW-PIN 02:40:61:c2:f3:b7 12345670
+p2p_dev_addr=02:40:61:c2:f3:b7 pri_dev_type=1-0050F204-1 name='Test'
+config_methods=0x188 dev_capab=0x21 group_capab=0x0
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_PROV_DISC_ENTER_PIN P2P-PROV-DISC-ENTER-PIN
+
+P2P_EVENT_PROV_DISC_ENTER_PIN: Request from the peer for us to enter a
+PIN displayed on the peer. The following parameter is included after
+the event prefix: peer address.
+
+\verbatim
+P2P-PROV-DISC-ENTER-PIN 02:40:61:c2:f3:b7 p2p_dev_addr=02:40:61:c2:f3:b7
+pri_dev_type=1-0050F204-1 name='Test' config_methods=0x188
+dev_capab=0x21 group_capab=0x0
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_PROV_DISC_PBC_REQ P2P-PROV-DISC-PBC-REQ
+
+P2P_EVENT_PROV_DISC_PBC_REQ: Request from the peer for us to connect
+using PBC. The following parameters are included after the event prefix:
+peer_address. P2P_CONNECT command can be used to accept the request.
+
+\verbatim
+P2P-PROV-DISC-PBC-REQ 02:40:61:c2:f3:b7 p2p_dev_addr=02:40:61:c2:f3:b7
+pri_dev_type=1-0050F204-1 name='Test' config_methods=0x188
+dev_capab=0x21 group_capab=0x0
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_PROV_DISC_PBC_RESP P2P-PROV-DISC-PBC-RESP
+
+P2P_EVENT_PROV_DISC_PBC_RESP: The peer accepted our provision discovery
+request to connect using PBC. The following parameters are included
+after the event prefix: peer_address. P2P_CONNECT command can be used to
+start GO Negotiation after this.
+
+\verbatim
+P2P-PROV-DISC-PBC-RESP 02:40:61:c2:f3:b7
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_SERV_DISC_REQ P2P-SERV-DISC-REQ
+
+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.
+
+\verbatim
+P2P-SERV-DISC-REQ 2412 02:40:61:c2:f3:b7 0 0 02000001
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_SERV_DISC_RESP P2P-SERV-DISC-RESP
+
+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.
+
+\verbatim
+P2P-SERV-DISC-RESP 02:40:61:c2:f3:b7 0 0300000101
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_INVITATION_RECEIVED P2P-INVITATION-RECEIVED
+
+P2P-INVITATION-RECEIVED: Indicate reception of a P2P Invitation
+Request. For persistent groups, the parameter after the event prefix
+indicates which network block includes the persistent group data.
+
+\verbatim
+P2P-INVITATION-RECEIVED sa=02:40:61:c2:f3:b7 persistent=0
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_INVITATION_RESULT P2P-INVITATION-RESULT
+
+P2P-INVITATION-RESULT: Indicate result of a P2P invitation that was
+requested with \ref ctrl_iface_P2P_INVITE. The parameter
+status=<value> shows the status code returned by the peer (or -1 on
+local failure or timeout).
+
+\verbatim
+P2P-INVITATION-RESULT status=1
+\endverbatim
+
+*/
diff --git a/doc/dbus.doxygen b/doc/dbus.doxygen
new file mode 100644 (file)
index 0000000..eeea200
--- /dev/null
@@ -0,0 +1,715 @@
+/**
+\page dbus %wpa_supplicant D-Bus API
+
+This section documents the %wpa_supplicant D-Bus API. Every D-Bus
+interface implemented by %wpa_supplicant is described here including
+their methods, signals, and properties with arguments, returned
+values, and possible errors.
+
+Interfaces:
+- \ref dbus_main
+- \ref dbus_interface
+- \ref dbus_wps
+- \ref dbus_bss
+- \ref dbus_network
+
+
+\section dbus_main fi.w1.wpa_supplicant1
+
+Interface implemented by the main %wpa_supplicant D-Bus object
+registered in the bus with fi.w1.wpa_supplicant1 name.
+
+\subsection dbus_main_methods Methods
+
+    <ul>
+      <li>
+       <h3>CreateInterface ( a{sv} : args ) --> o : interface</h3>
+       <p>Registers a wireless interface in %wpa_supplicant.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>a{sv} : args</dt>
+         <dd>
+           A dictionary with arguments used to add the interface to %wpa_supplicant. The dictionary may contain the following entries:
+           <table>
+             <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th>
+             <tr><td>Ifname</td><td>s</td><td>Name of the network interface to control, e.g., wlan0</td><td>Yes</td>
+             <tr><td>Bridge_ifname</td><td>s</td><td>Name of the bridge interface to control, e.g., br0</td><td>No</td>
+             <tr><td>Driver</td><td>s</td><td>Driver name which the interface uses, e.g., nl80211</td><td>No</td>
+           </table>
+         </dd>
+       </dl>
+       <h4>Returns</h4>
+       <dl>
+         <dt>o : interface</dt>
+         <dd>A D-Bus path to object representing created interface</dd>
+       </dl>
+       <h4>Possible errors</h4>
+       <dl>
+         <dt>fi.w1.wpa_supplicant1.InterfaceExists</dt>
+         <dd>%wpa_supplicant already controls this interface.</dd>
+         <dt>fi.w1.wpa_supplicant1.UnknownError</dt>
+         <dd>Creating interface failed for an unknown reason.</dd>
+         <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
+         <dd>Invalid entries were found in the passed argument.</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>RemoveInterface ( o : interface ) --> nothing</h3>
+       <p>Deregisters a wireless interface from %wpa_supplicant.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>o : interface</dt>
+         <dd>A D-Bus path to an object representing an interface to remove returned by CreateInterface</dd>
+       </dl>
+       <h4>Possible errors</h4>
+       <dl>
+         <dt>fi.w1.wpa_supplicant1.InterfaceUnknown</dt>
+         <dd>Object pointed by the path doesn't exist or doesn't represent an interface.</dd>
+         <dt>fi.w1.wpa_supplicant1.UnknownError</dt>
+         <dd>Removing interface failed for an unknown reason.</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>GetInterface ( s : ifname ) --> o : interface</h3>
+       <p>Returns a D-Bus path to an object related to an interface which %wpa_supplicant already controls.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>s : ifname</dt>
+         <dd>Name of the network interface, e.g., wlan0</dd>
+       </dl>
+       <h4>Returns</h4>
+       <dl>
+         <dt>o : interface</dt>
+         <dd>A D-Bus path to an object representing an interface</dd>
+       </dl>
+       <h4>Possible errors</h4>
+       <dl>
+         <dt>fi.w1.wpa_supplicant1.InterfaceUnknown</dt>
+         <dd>An interface with the passed name in not controlled by %wpa_supplicant.</dd>
+         <dt>fi.w1.wpa_supplicant1.UnknownError</dt>
+         <dd>Getting an interface object path failed for an unknown reason.</dd>
+       </dl>
+      </li>
+    </ul>
+
+\subsection dbus_main_properties Properties
+
+    <ul>
+      <li>
+       <h3>DebugLevel - s - (read/write)</h3>
+       <p>Global %wpa_supplicant debugging level. Possible values are
+       "msgdump" (verbose debugging), "debug" (debugging),
+       "info" (informative), "warning" (warnings), and "error" (errors).</p>
+      </li>
+
+      <li>
+       <h3>DebugTimestamp - b - (read/write)</h3>
+       <p>Global %wpa_supplicant debugging parameter. Determines if timestamps are shown in debug logs.</p>
+      </li>
+
+      <li>
+       <h3>DebugShowKeys - b - (read/write)</h3>
+       <p>Global %wpa_supplicant debugging parameter. Determines if secrets are shown in debug logs.</p>
+      </li>
+
+      <li>
+       <h3>Interfaces - ao - (read)</h3>
+       <p>An array with paths to D-Bus objects representing controlled interfaces each.</p>
+      </li>
+
+      <li>
+       <h3>EapMethods - as - (read)</h3>
+       <p>An array with supported EAP methods names.</p>
+      </li>
+    </ul>
+
+\subsection dbus_main_signals Signals
+
+    <ul>
+      <li>
+       <h3>InterfaceAdded ( o : interface, a{sv} : properties )</h3>
+       <p>A new interface was added to %wpa_supplicant.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>o : interface</dt>
+         <dd>A D-Bus path to an object representing the added interface</dd>
+       </dl>
+       <dl>
+         <dt>a{sv} : properties</dt>
+         <dd>A dictionary containing properties of added interface.</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>InterfaceRemoved ( o : interface )</h3>
+       <p>An interface was removed from %wpa_supplicant.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>o : interface</dt>
+         <dd>A D-Bus path to an object representing the removed interface</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>PropertiesChanged ( a{sv} : properties )</h3>
+       <p>Some properties have changed.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>a{sv} : properties</dt>
+         <dd>A dictionary with pairs of properties names which have changed and theirs new values. Possible dictionary keys are: "DebugParams"</dd>
+       </dl>
+      </li>
+    </ul>
+
+
+\section dbus_interface fi.w1.wpa_supplicant1.Interface
+
+Interface implemented by objects related to network interface added to
+%wpa_supplicant, i.e., returned by
+fi.w1.wpa_supplicant1.CreateInterface.
+
+\subsection dbus_interface_methods Methods
+
+    <ul>
+      <li>
+       <h3>Scan ( a{sv} : args ) --> nothing</h3>
+       <p>Triggers a scan.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>a{sv} : args</dt>
+         <dd>
+           A dictionary with arguments describing scan type:
+           <table>
+             <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th>
+             <tr><td>Type</td><td>s</td><td>Type of the scan. Possible values: "active", "passive"</td><td>Yes</td>
+             <tr><td>SSIDs</td><td>aay</td><td>Array of SSIDs to scan for (applies only if scan type is active)</td><td>No</td>
+             <tr><td>IEs</td><td>aay</td><td>Information elements to used in active scan (applies only if scan type is active)</td><td>No</td>
+             <tr><td>Channels</td><td>a(uu)</td><td>Array of frequencies to scan in form of (center, width) in MHz.</td><td>No</td>
+           </table>
+         </dd>
+       </dl>
+       <h4>Possible errors</h4>
+       <dl>
+         <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
+         <dd>Invalid entries were found in the passed argument.</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>Disconnect ( ) --> nothing</h3>
+       <p>Disassociates the interface from current network.</p>
+       <h4>Possible errors</h4>
+       <dl>
+         <dt>fi.w1.wpa_supplicant1.NotConnected</dt>
+         <dd>Interface is not connected to any network.</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>AddNetwork ( a{sv} : args ) --> o : network</h3>
+       <p>Adds a new network to the interface.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>a{sv} : args</dt>
+         <dd>A dictionary with network configuration. Dictionary entries are equivalent to entries in the "network" block in %wpa_supplicant configuration file. Entry values should be appropriate type to the entry, e.g., an entry with key "frequency" should have value type int.</dd>
+       </dl>
+       <h4>Returns</h4>
+       <dl>
+         <dt>o : network</dt>
+         <dd>A D-Bus path to an object representing a configured network</dd>
+       </dl>
+       <h4>Possible errors</h4>
+       <dl>
+         <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
+         <dd>Invalid entries were found in the passed argument.</dd>
+         <dt>fi.w1.wpa_supplicant1.UnknownError</dt>
+         <dd>Adding network failed for an unknown reason.</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>RemoveNetwork ( o : network ) --> nothing</h3>
+       <p>Removes a configured network from the interface.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>o : network</dt>
+         <dd>A D-Bus path to an object representing a configured network returned by fi.w1.wpa_supplicant1.Interface.AddNetwork</dd>
+       </dl>
+       <h4>Possible errors</h4>
+       <dl>
+         <dt>fi.w1.wpa_supplicant1.NetworkUnknown</dt>
+         <dd>A passed path doesn't point to any network object.</dd>
+         <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
+         <dd>A passed path doesn't point to any network object.</dd>
+         <dt>fi.w1.wpa_supplicant1.UnknownError</dt>
+         <dd>Removing network failed for an unknown reason.</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>SelectNetwork ( o : network ) --> nothing</h3>
+       <p>Attempt association with a configured network.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>o : network</dt>
+         <dd>A D-Bus path to an object representing a configured network returned by fi.w1.wpa_supplicant1.Interface.AddNetwork</dd>
+       </dl>
+       <h4>Possible errors</h4>
+       <dl>
+         <dt>fi.w1.wpa_supplicant1.NetworkUnknown</dt>
+         <dd>A passed path doesn't point to any network object.</dd>
+         <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
+         <dd>A passed path doesn't point to any network object.</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>AddBlob ( s : name, ay : data ) --> nothing</h3>
+       <p>Adds a blob to the interface.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>s : name</dt>
+         <dd>A name of a blob</dd>
+         <dt>ay : data</dt>
+         <dd>A blob data</dd>
+       </dl>
+       <h4>Possible errors</h4>
+       <dl>
+         <dt>fi.w1.wpa_supplicant1.BlobExists</dt>
+         <dd>A blob with the specified name already exists.</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>RemoveBlob ( s : name ) --> nothing</h3>
+       <p>Removes the blob from the interface.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>s : name</dt>
+         <dd>A name of the blob to remove</dd>
+       </dl>
+       <h4>Possible errors</h4>
+       <dl>
+         <dt>fi.w1.wpa_supplicant1.BlobUnknown</dt>
+         <dd>A blob with the specified name doesn't exist.</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>GetBlob ( s : name ) --> ay : data</h3>
+       <p>Returns the blob data of a previously added blob.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>s : name</dt>
+         <dd>A name of the blob</dd>
+       </dl>
+       <h4>Returns</h4>
+       <dl>
+         <dt>ay : data</dt>
+         <dd>A blob data</dd>
+       </dl>
+       <h4>Possible errors</h4>
+       <dl>
+         <dt>fi.w1.wpa_supplicant1.BlobUnknown</dt>
+         <dd>A blob with the specified name doesn't exist.</dd>
+       </dl>
+      </li>
+    </ul>
+
+\subsection dbus_interface_properties Properties
+
+    <ul>
+      <li>
+       <h3>Capabilities - a{sv} - (read)</h3>
+       <p>Capabilities of the interface. Dictionary contains following entries:</p>
+       <table>
+         <tr><th>Key</th><th>Value type</th><th>Description</th>
+         <tr><td>Pairwise</td><td>as</td><td>Possible array elements: "ccmp", "tkip", "none"</td>
+         <tr><td>Group</td><td>as</td><td>Possible array elements: "ccmp", "tkip", "wep104", "wep40"</td>
+         <tr><td>KeyMgmt</td><td>as</td><td>Possible array elements: "wpa-psk", "wpa-ft-psk", "wpa-psk-sha256", "wpa-eap", "wpa-ft-eap", "wpa-eap-sha256", "ieee8021x", "wpa-none", "wps", "none"</td>
+         <tr><td>Protocol</td><td>as</td><td>Possible array elements: "rsn", "wpa"</td>
+         <tr><td>AuthAlg</td><td>as</td><td>Possible array elements: "open", "shared", "leap"</td>
+         <tr><td>Scan</td><td>as</td><td>Possible array elements: "active", "passive", "ssid"</td>
+         <tr><td>Modes</td><td>as</td><td>Possible array elements: "infrastructure", "ad-hoc", "ap"</td>
+       </table>
+      </li>
+
+      <li>
+       <h3>State - s - (read)</h3>
+       <p>A state of the interface. Possible values are: return "disconnected", "inactive", "scanning", "authenticating", "associating", "associated", "4way_handshake", "group_handshake", "completed","unknown".</p>
+      </li>
+
+      <li>
+       <h3>Scanning - b - (read)</h3>
+       <p>Determines if the interface is already scanning or not</p>
+      </li>
+
+      <li>
+       <h3>ApScan - u - (read/write)</h3>
+       <p>Identical to ap_scan entry in %wpa_supplicant configuration file. Possible values are 0, 1 or 2.</p>
+      </li>
+
+      <li>
+       <h3>Ifname - s - (read)</h3>
+       <p>Name of network interface controlled by the interface, e.g., wlan0.</p>
+      </li>
+
+      <li>
+       <h3>BridgeIfname - s - (read)</h3>
+       <p>Name of bridge network interface controlled by the interface, e.g., br0.</p>
+      </li>
+
+      <li>
+       <h3>Driver - s - (read)</h3>
+       <p>Name of driver used by the interface, e.g., nl80211.</p>
+      </li>
+
+      <li>
+       <h3>CurrentBSS - o - (read)</h3>
+       <p>Path to D-Bus object representing BSS which %wpa_supplicant is associated with, or "/" if is not associated at all.</p>
+      </li>
+
+      <li>
+       <h3>CurrentNetwork - o - (read)</h3>
+       <p>Path to D-Bus object representing configured network which %wpa_supplicant uses at the moment, or "/" if doesn't use any.</p>
+      </li>
+
+      <li>
+       <h3>Blobs - as - (read)</h3>
+       <p>List of blobs names added to the Interface.</p>
+      </li>
+
+      <li>
+       <h3>BSSs - ao - (read)</h3>
+       <p>List of D-Bus objects paths representing BSSs known to the interface, i.e., scan results.</p>
+      </li>
+
+      <li>
+       <h3>Networks - ao - (read)</h3>
+       <p>List of D-Bus objects paths representing configured networks.</p>
+      </li>
+    </ul>
+
+\subsection dbus_interface_signals Signals
+
+    <ul>
+      <li>
+       <h3>ScanDone ( b : success )</h3>
+       <p>Scanning finished. </p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>s : success</dt>
+         <dd>Determines if scanning was successful. If so, results are available.</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>BSSAdded ( o : BSS, a{sv} : properties )</h3>
+       <p>Interface became aware of a new BSS.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>o : BSS</dt>
+         <dd>A D-Bus path to an object representing the new BSS.</dd>
+       </dl>
+       <dl>
+         <dt>a{sv} : properties</dt>
+         <dd>A dictionary containing properties of added BSS.</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>BSSRemoved ( o : BSS )</h3>
+       <p>BSS disappeared.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>o : BSS</dt>
+         <dd>A D-Bus path to an object representing the BSS.</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>BlobAdded ( s : blobName )</h3>
+       <p>A new blob has been added to the interface.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>s : blobName</dt>
+         <dd>A name of the added blob.</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>BlobRemoved ( s : blobName )</h3>
+       <p>A blob has been removed from the interface.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>s : blobName</dt>
+         <dd>A name of the removed blob.</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>NetworkAdded ( o : network, a{sv} : properties )</h3>
+       <p>A new network has been added to the interface.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>o : network</dt>
+         <dd>A D-Bus path to an object representing the added network.</dd>
+       </dl>
+       <dl>
+         <dt>a{sv} : properties</dt>
+         <dd>A dictionary containing properties of added network.</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>NetworkRemoved ( o : network )</h3>
+       <p>The network has been removed from the interface.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>o : network</dt>
+         <dd>A D-Bus path to an object representing the removed network.</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>NetworkSelected ( o : network )</h3>
+       <p>The network has been selected.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>o : network</dt>
+         <dd>A D-Bus path to an object representing the selected network.</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>PropertiesChanged ( a{sv} : properties )</h3>
+       <p>Some properties have changed.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>a{sv} : properties</dt>
+         <dd>A dictionary with pairs of properties names which have changed and theirs new values. Possible dictionary keys are: "ApScan", "Scanning", "State", "CurrentBSS", "CurrentNetwork"</dd>
+       </dl>
+      </li>
+    </ul>
+
+
+\section dbus_wps fi.w1.wpa_supplicant1.Interface.WPS
+
+Interface implemented by objects related to network interface added to
+%wpa_supplicant, i.e., returned by fi.w1.wpa_supplicant1.CreateInterface.
+
+\subsection dbus_wps_methods Methods
+
+    <ul>
+      <li>
+       <h3>Start ( a{sv} : args ) --> a{sv} : output</h3>
+       <p>Starts WPS configuration.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>a{sv} : args</dt>
+         <dd>
+           A dictionary with arguments used to start WPS configuration. The dictionary may contain the following entries:
+           <table>
+             <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th>
+             <tr><td>Role</td><td>s</td><td>The device's role. Possible values are "enrollee" and "registrar".</td><td>Yes</td>
+             <tr><td>Type</td><td>s</td><td>WPS authentication type. Applies only for enrollee role. Possible values are "pin" and "pbc".</td><td>Yes, for enrollee role; otherwise no</td>
+             <tr><td>Pin</td><td>s</td><td>WPS Pin.</td><td>Yes, for registrar role; otherwise optional</td>
+             <tr><td>Bssid</td><td>ay</td><td></td><td>No</td>
+           </table>
+         </dd>
+       </dl>
+       <h4>Returns</h4>
+       <dl>
+         <dt>a{sv} : output</dt>
+         <dd>
+           <table>
+             <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th>
+             <tr><td>Pin</td><td>s</td><td>Newly generated PIN, if not specified for enrollee role and pin authentication type.</td><td>No</td>
+           </table>
+         </dd>
+       </dl>
+       <h4>Possible errors</h4>
+       <dl>
+         <dt>fi.w1.wpa_supplicant1.UnknownError</dt>
+         <dd>Starting WPS configuration failed for an unknown reason.</dd>
+         <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
+         <dd>Invalid entries were found in the passed argument.</dd>
+       </dl>
+      </li>
+    </ul>
+
+\subsection dbus_wps_properties Properties
+
+    <ul>
+      <li>
+       <h3>ProcessCredentials - b - (read/write)</h3>
+       <p>Determines if the interface will process the credentials (credentials_processed configuration file parameter).</p>
+      </li>
+    </ul>
+
+\subsection dbus_wps_signals Signals
+
+    <ul>
+      <li>
+       <h3>Event ( s : name, a{sv} : args )</h3>
+       <p>WPS event occurred.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>s : event</dt>
+         <dd>Event type. Possible values are: "success, "fail" and "m2d"</dd>
+         <dt>a{sv} : args</dt>
+         <dd>
+           Event arguments. Empty for success event, one entry ( "msg" : i ) for fail event and following entries for m2d event:
+           <table>
+             <tr><th>config_methods</th><th>Value type</th>
+             <tr><td>manufacturer</td><td>q</td>
+             <tr><td>model_name</td><td>ay</td>
+             <tr><td>model_number</td><td>ay</td>
+             <tr><td>serial_number</td><td>ay</td>
+             <tr><td>dev_name</td><td>ay</td>
+             <tr><td>primary_dev_type</td><td>ay</td>
+             <tr><td>config_error</td><td>q</td>
+             <tr><td>dev_password_id</td><td>q</td>
+           </table>
+         </dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>Credentials ( a{sv} : credentials )</h3>
+       <p>WPS credentials. Dictionary contains:</p>
+       <table>
+         <tr><th>Key</th><th>Value type</th><th>Description</th>
+         <tr><td>BSSID</td><td>ay</td><td></td>
+         <tr><td>SSID</td><td>s</td><td></td>
+         <tr><td>AuthType</td><td>as</td><td>Possible array elements: "open", "shared", "wpa-psk", "wpa-eap", "wpa2-eap", "wpa2-psk"</td>
+         <tr><td>EncrType</td><td>as</td><td>Possible array elements: "none", "wep", "tkip", "aes"</td>
+         <tr><td>Key</td><td>ay</td><td>Key data</td>
+         <tr><td>KeyIndex</td><td>u</td><td>Key index</td>
+       </table>
+      </li>
+
+      <li>
+       <h3>PropertiesChanged ( a{sv} : properties )</h3>
+       <p>Some properties have changed.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>a{sv} : properties</dt>
+         <dd>A dictionary with pairs of properties names which have changed and theirs new values. Possible dictionary keys are: "ProcessCredentials"</dd>
+       </dl>
+      </li>
+    </ul>
+
+
+\section dbus_bss fi.w1.wpa_supplicant1.BSS
+
+Interface implemented by objects representing a scanned BSSs, i.e.,
+scan results.
+
+\subsection dbus_bss_properties Properties
+
+    <ul>
+      <li>
+       <h3>BSSID - ay - (read)</h3>
+       <p>BSSID of the BSS.</p>
+      </li>
+      <li>
+       <h3>SSID - ay - (read)</h3>
+       <p>SSID of the BSS.</p>
+      </li>
+      <li>
+       <h3>WPA - a{sv} - (read)</h3>
+       <p>WPA information of the BSS. Empty dictionary indicates no WPA support. Dictionary entries are:</p>
+       <table>
+         <tr><td>KeyMgmt</td><td>as</td><td>Key management suite. Possible array elements: "wpa-psk", "wpa-eap", "wpa-none"</td>
+         <tr><td>Pairwise</td><td>as</td><td>Pairwise cipher suites. Possible array elements: "ccmp", "tkip"</td>
+         <tr><td>Group</td><td>s</td><td>Group cipher suite. Possible values are: "ccmp", "tkip", "wep104", "wep40"</td>
+       </table>
+      </li>
+      <li>
+       <h3>RSN - a{sv} - (read)</h3>
+       <p>RSN information of the BSS. Empty dictionary indicates no RSN support. Dictionary entries are:</p>
+       <table>
+         <tr><td>KeyMgmt</td><td>as</td><td>Key management suite. Possible array elements: "wpa-psk", "wpa-eap", "wpa-ft-psk", "wpa-ft-eap", "wpa-psk-sha256", "wpa-eap-sha256",</td>
+         <tr><td>Pairwise</td><td>as</td><td>Pairwise cipher suites. Possible array elements: "ccmp", "tkip"</td>
+         <tr><td>Group</td><td>s</td><td>Group cipher suite. Possible values are: "ccmp", "tkip", "wep104", "wep40"</td>
+         <tr><td>MgmtGroup</td><td>s</td><td>Mangement frames cipher suite. Possible values are: "aes128cmac"</td>
+       </table>
+      </li>
+      <li>
+       <h3>IEs - ay - (read)</h3>
+       <p>All IEs of the BSS as a chain of TLVs</p>
+      </li>
+      <li>
+       <h3>Privacy - b - (read)</h3>
+       <p>Indicates if BSS supports privacy.</p>
+      </li>
+      <li>
+       <h3>Mode - s - (read)</h3>
+       <p>Describes mode of the BSS. Possible values are: "ad-hoc" and "infrastructure".</p>
+      </li>
+      <li>
+       <h3>Frequency - q - (read)</h3>
+       <p>Frequency of the BSS in MHz.</p>
+      </li>
+      <li>
+       <h3>Rates - au - (read)</h3>
+       <p>Descending ordered array of rates supported by the BSS in bits per second.</p>
+      </li>
+      <li>
+       <h3>Signal - n - (read)</h3>
+       <p>Signal strength of the BSS.</p>
+      </li>
+    </ul>
+
+\subsection dbus_bss_signals Signals
+
+    <ul>
+      <li>
+       <h3>PropertiesChanged ( a{sv} : properties )</h3>
+       <p>Some properties have changed.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>a{sv} : properties</dt>
+         <dd>A dictionary with pairs of properties names which have changed and theirs new values.</dd>
+       </dl>
+      </li>
+    </ul>
+
+
+\section dbus_network fi.w1.wpa_supplicant1.Network
+
+Interface implemented by objects representing configured networks,
+i.e., returned by fi.w1.wpa_supplicant1.Interface.AddNetwork.
+
+\subsection dbus_network_properties Properties
+
+    <ul>
+      <li>
+       <h3>Enabled - b - (read/write)</h3>
+       <p>Determines if the configured network is enabled or not.</p>
+      </li>
+
+      <li>
+       <h3>Properties - a{sv} - (read)</h3>
+       <p>Properties of the configured network. Dictionary contains entries from "network" block of %wpa_supplicant configuration file. All values are string type, e.g., frequency is "2437", not 2437.
+      </li>
+    </ul>
+
+\subsection dbus_network_signals Signals
+
+    <ul>
+      <li>
+       <h3>PropertiesChanged ( a{sv} : properties )</h3>
+       <p>Some properties have changed.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>a{sv} : properties</dt>
+         <dd>A dictionary with pairs of properties names which have changed and theirs new values. Possible dictionary keys are: "Enabled"</dd>
+       </dl>
+      </li>
+    </ul>
+
+*/
diff --git a/doc/directories.doxygen b/doc/directories.doxygen
new file mode 100644 (file)
index 0000000..7465afe
--- /dev/null
@@ -0,0 +1,90 @@
+/**
+
+\dir hostapd hostapd
+
+hostapd-specific code for configuration, control interface, and AP
+management.
+
+
+\dir src/common Common functionality
+
+This module includes IEEE 802.11, IEEE 802.1X, and WPA related
+functionality that is shared between AP and station modes.
+
+
+\dir src/crypto Cryptographical functionality and wrappers
+
+This module defines crypto and tls interfaces to provide portability
+layer for different crypto/TLS libraries. Wrappers for number of
+libraries are also included here. In addition, internal implementation
+of various crypto functions are provided as an alternative for an
+external library and to extend some algorithms.
+
+
+\dir src/drivers Driver wrappers
+
+This directory includes the driver interface definition and all the
+driver wrappers that can be used to interact with different drivers
+without making rest of the software dependent on which particular
+driver is used.
+
+
+\dir src/eap_common Common EAP functionality for server and peer
+
+
+\dir src/eap_peer EAP peer
+
+
+\dir src/eap_server EAP server
+
+
+\dir src/eapol_auth EAPOL authenticator
+
+
+\dir src/eapol_supp EAPOL supplicant
+
+
+\dir src/l2_packet Layer 2 packet interface
+
+This module defines an interface for layer 2 (link layer) packet
+sendinf and receiving. All the wrappers for supported mechanisms are
+also included here. This is used to port packet access for new
+operating systems without having to make rest of the source code
+depend on which OS network stack is used.
+
+
+\dir src/radius RADIUS
+
+RADIUS module includes RADIUS message building and parsing
+functionality and separate RADIUS client and server functions.
+
+
+\dir src/rsn_supp IEEE 802.11 RSN and WPA supplicant
+
+
+\dir src/tls Internal TLS server and client implementation
+
+This module can be used as an alternative to using an external TLS
+library.
+
+
+\dir src/utils Utility functions
+
+Independent set of helper functions that most other components
+use. This includes portability wrappers and helpers for common tasks.
+
+
+\dir src/wps Wi-Fi Protected Setup
+
+This directory includes Wi-Fi Protected Setup functions for Registrar
+(both internal in an AP and an External Registrar and
+Enrollee. Minimal UPnP and HTTP functionality is also provided for the
+functionality needed to implement Wi-Fi Protected Setup.
+
+
+\dir wpa_supplicant %wpa_supplicant
+
+%wpa_supplicant-specific code for configuration, control interface, and
+client management.
+
+*/
diff --git a/doc/doxygen.conf b/doc/doxygen.conf
new file mode 100644 (file)
index 0000000..6a1cb3e
--- /dev/null
@@ -0,0 +1,1534 @@
+# Doxyfile 1.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+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
+
+# 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
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = doc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           = doc/doxygen.warnings
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = \
+       doc \
+       hostapd \
+       wpa_supplicant \
+       src/ap \
+       src/common \
+       src/crypto \
+       src/drivers \
+       src/eap_common \
+       src/eapol_auth \
+       src/eapol_supp \
+       src/eap_peer \
+       src/eap_server \
+       src/l2_packet \
+       src/radius \
+       src/rsn_supp \
+       src/tls \
+       src/utils \
+       src/wps
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.c *.h *.cpp *.m *.doxygen
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             = doc
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+# You can download the filter tool from
+# http://w1.fi/tools/kerneldoc2doxygen-hostap.pl
+INPUT_FILTER           = kerneldoc2doxygen-hostap.pl
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 3
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
+# there is already a search function so this one should typically
+# be disabled.
+
+SEARCHENGINE           = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             = IEEE8021X_EAPOL CONFIG_CTRL_IFACE
+
+# 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.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS         = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = NO
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = NO
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = NO
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = NO
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = NO
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/doc/driver_wrapper.doxygen b/doc/driver_wrapper.doxygen
new file mode 100644 (file)
index 0000000..28aea50
--- /dev/null
@@ -0,0 +1,180 @@
+/**
+\page driver_wrapper Driver wrapper implementation (driver.h, drivers.c)
+
+All hardware and driver dependent functionality is in separate C files
+that implement defined wrapper functions. Other parts
+of the %wpa_supplicant are designed to be hardware, driver, and operating
+system independent.
+
+Driver wrappers need to implement whatever calls are used in the
+target operating system/driver for controlling wireless LAN
+devices. As an example, in case of Linux, these are mostly some glue
+code and ioctl() calls and netlink message parsing for Linux Wireless
+Extensions (WE). Since features required for WPA were added only recently to
+Linux Wireless Extensions (in version 18), some driver specific code is used
+in number of driver interface implementations. These driver dependent parts
+can be replaced with generic code in driver_wext.c once the target driver
+includes full support for WE-18. After that, all Linux drivers, at
+least in theory, could use the same driver wrapper code.
+
+A driver wrapper needs to implement some or all of the functions
+defined in driver.h. These functions are registered by filling struct
+wpa_driver_ops with function pointers. Hardware independent parts of
+%wpa_supplicant will call these functions to control the driver/wlan
+card. In addition, support for driver events is required. The event
+callback function, wpa_supplicant_event(), and its parameters are
+documented in driver.h. In addition, a pointer to the 'struct
+wpa_driver_ops' needs to be registered in drivers.c file.
+
+When porting to other operating systems, the driver wrapper should be
+modified to use the native interface of the target OS. It is possible
+that some extra requirements for the interface between the driver
+wrapper and generic %wpa_supplicant code are discovered during porting
+to a new operating system. These will be addressed on case by case
+basis by modifying the interface and updating the other driver
+wrappers for this. The goal is to avoid changing this interface
+without very good reasons in order to limit the number of changes
+needed to other wrappers and hardware independent parts of
+%wpa_supplicant. When changes are required, recommended way is to
+make them in backwards compatible way that allows existing driver
+interface implementations to be compiled without any modification.
+
+Generic Linux Wireless Extensions functions are implemented in
+driver_wext.c. All Linux driver wrappers can use these when the kernel
+driver supports the generic ioctl()s and wireless events. Driver
+specific functions are implemented in separate C files, e.g.,
+driver_hostap.c. These files need to define struct wpa_driver_ops
+entry that will be used in wpa_supplicant.c when calling driver
+functions. struct wpa_driver_ops entries are registered in drivers.c.
+
+In general, it is likely to be useful to first take a look at couple
+of driver interface examples before starting on implementing a new
+one. driver_hostap.c and driver_wext.c include a complete
+implementation for Linux drivers that use %wpa_supplicant-based control
+of WPA IE and roaming. driver_ndis.c (with help from driver_ndis_.c)
+is an example of a complete interface for Windows NDIS interface for
+drivers that generate WPA IE themselves and decide when to roam. These
+example implementations include full support for all security modes.
+
+
+\section driver_req Driver requirements for WPA
+
+WPA introduces new requirements for the device driver. At least some
+of these need to be implemented in order to provide enough support for
+%wpa_supplicant.
+
+\subsection driver_tkip_ccmp TKIP/CCMP
+
+WPA requires that the pairwise cipher suite (encryption algorithm for
+unicast data packets) is TKIP or CCMP. These are new encryption
+protocols and thus, the driver will need to be modified to support
+them. Depending on the used wlan hardware, some parts of these may be
+implemented by the hardware/firmware.
+
+Specification for both TKIP and CCMP is available from IEEE (IEEE
+802.11i amendment). Fully functional, hardware independent
+implementation of both encryption protocols is also available in Host
+AP driver (driver/modules/hostap_{tkip,ccmp}.c). In addition, Linux 2.6
+kernel tree has generic implementations for WEP, TKIP, and CCMP that can
+be used in Linux drivers.
+
+The driver will also need to provide configuration mechanism to allow
+user space programs to configure TKIP and CCMP. Linux Wireless Extensions
+v18 added support for configuring these algorithms and
+individual/non-default keys. If the target kernel does not include WE-18,
+private ioctls can be used to provide similar functionality.
+
+\subsection driver_roaming Roaming control and scanning support
+
+%wpa_supplicant can optionally control AP selection based on the
+information received from Beacon and/or Probe Response frames
+(ap_scan=1 mode in configuration). This means that the driver should
+support external control for scan process. In case of Linux, use of
+new Wireless Extensions scan support (i.e., 'iwlist wlan0 scan') is
+recommended. The current driver wrapper (driver_wext.c) uses this for
+scan results.
+
+Scan results must also include the WPA information element. Support for
+this was added in WE-18. With older versions, a custom event can be used
+to provide the full WPA IE (including element id and length) as a hex
+string that is included in the scan results.
+
+%wpa_supplicant needs to also be able to request the driver to
+associate with a specific BSS. Current Host AP driver and matching
+driver_hostap.c wrapper uses following sequence for this
+request. Similar/identical mechanism should be usable also with other
+drivers.
+
+- set WPA IE for AssocReq with private ioctl
+- set SSID with SIOCSIWESSID
+- set channel/frequency with SIOCSIWFREQ
+- set BSSID with SIOCSIWAP
+  (this last ioctl will trigger the driver to request association)
+
+\subsection driver_wpa_ie WPA IE generation
+
+%wpa_supplicant selects which cipher suites and key management suites
+are used. Based on this information, it generates a WPA IE. This is
+provided to the driver interface in the associate call. This does not
+match with Windows NDIS drivers which generate the WPA IE
+themselves.
+
+%wpa_supplicant allows Windows NDIS-like behavior by providing the
+selected cipher and key management suites in the associate call. If
+the driver generates its own WPA IE and that differs from the one
+generated by %wpa_supplicant, the driver has to inform %wpa_supplicant
+about the used WPA IE (i.e., the one it used in (Re)Associate
+Request). This notification is done using EVENT_ASSOCINFO event (see
+driver.h). %wpa_supplicant is normally configured to use
+ap_scan=2 mode with drivers that control WPA IE generation and roaming.
+
+\subsection driver_events Driver events
+
+%wpa_supplicant needs to receive event callbacks when certain events
+occur (association, disassociation, Michael MIC failure, scan results
+available, PMKSA caching candidate). These events and the callback
+details are defined in driver.h (wpa_supplicant_event() function
+and enum wpa_event_type).
+
+On Linux, association and disassociation can use existing Wireless
+Extensions event that is reporting new AP with SIOCGIWAP
+event. Similarly, completion of a scan can be reported with SIOCGIWSCAN
+event.
+
+Michael MIC failure event was added in WE-18. Older versions of Wireless
+Extensions will need to use a custom event. Host AP driver used a custom
+event with following contents: MLME-MICHAELMICFAILURE.indication(keyid=#
+broadcast/unicast addr=addr2). This is the recommended format until
+the driver can be moved to use WE-18 mechanism.
+
+\subsection driver_wext_summary Summary of Linux Wireless Extensions use
+
+AP selection depends on ap_scan configuration:
+
+ap_scan=1:
+
+- %wpa_supplicant requests scan with SIOCSIWSCAN
+- driver reports scan complete with wireless event SIOCGIWSCAN
+- %wpa_supplicant reads scan results with SIOCGIWSCAN (multiple call if
+  a larget buffer is needed)
+- %wpa_supplicant decides which AP to use based on scan results
+- %wpa_supplicant configures driver to associate with the selected BSS
+  (SIOCSIWMODE, SIOCSIWGENIE, SIOCSIWAUTH, SIOCSIWFREQ,
+   SIOCSIWESSID, SIOCSIWAP)
+
+ap_scan=2:
+
+- %wpa_supplicant configures driver to associate with an SSID
+  (SIOCSIWMODE, SIOCSIWGENIE, SIOCSIWAUTH, SIOCSIWESSID)
+
+
+After this, both modes use similar steps:
+
+- optionally (or required for drivers that generate WPA/RSN IE for
+  (Re)AssocReq), driver reports association parameters (AssocReq IEs)
+  with wireless event IWEVASSOCREQIE (and optionally IWEVASSOCRESPIE)
+- driver reports association with wireless event SIOCGIWAP
+- %wpa_supplicant takes care of EAPOL frame handling (validating
+  information from associnfo and if needed, from scan results if WPA/RSN
+  IE from the Beacon frame is not reported through associnfo)
+*/
diff --git a/doc/eap.doxygen b/doc/eap.doxygen
new file mode 100644 (file)
index 0000000..6a24829
--- /dev/null
@@ -0,0 +1,87 @@
+/**
+\page eap_peer_module EAP peer implementation
+
+Extensible Authentication Protocol (EAP) is an authentication framework
+defined in RFC 3748. %wpa_supplicant uses a separate code module for EAP
+peer implementation. This module was designed to use only a minimal set
+of direct function calls (mainly, to debug/event functions) in order for
+it to be usable in other programs. The design of the EAP
+implementation is based loosely on RFC 4137. The state machine is
+defined in this RFC and so is the interface between the peer state
+machine and methods. As such, this RFC provides useful information for
+understanding the EAP peer implementation in %wpa_supplicant.
+
+Some of the terminology used in EAP state machine is referring to
+EAPOL (IEEE 802.1X), but there is no strict requirement on the lower
+layer being IEEE 802.1X if EAP module is built for other programs than
+%wpa_supplicant. These terms should be understood to refer to the
+lower layer as defined in RFC 4137.
+
+
+\section adding_eap_methods Adding EAP methods
+
+Each EAP method is implemented as a separate module, usually as one C
+file named eap_<name of the method>.c, e.g., eap_md5.c. All EAP
+methods use the same interface between the peer state machine and
+method specific functions. This allows new EAP methods to be added
+without modifying the core EAP state machine implementation.
+
+New EAP methods need to be registered by adding them into the build
+(Makefile) and the EAP method registration list in the
+eap_peer_register_methods() function of eap_methods.c. Each EAP
+method should use a build-time configuration option, e.g., EAP_TLS, in
+order to make it possible to select which of the methods are included
+in the build.
+
+EAP methods must implement the interface defined in eap_i.h. struct
+eap_method defines the needed function pointers that each EAP method
+must provide. In addition, the EAP type and name are registered using
+this structure. This interface is based on section 4.4 of RFC 4137.
+
+It is recommended that the EAP methods would use generic helper
+functions, eap_msg_alloc() and eap_hdr_validate() when processing
+messages. This allows code sharing and can avoid missing some of the
+needed validation steps for received packets. In addition, these
+functions make it easier to change between expanded and legacy EAP
+header, if needed.
+
+When adding an EAP method that uses a vendor specific EAP type
+(Expanded Type as defined in RFC 3748, Chapter 5.7), the new method
+must be registered by passing vendor id instead of EAP_VENDOR_IETF to
+eap_peer_method_alloc(). These methods must not try to emulate
+expanded types by registering a legacy EAP method for type 254. See
+eap_vendor_test.c for an example of an EAP method implementation that
+is implemented as an expanded type.
+
+
+\section used_eap_library Using EAP implementation as a library
+
+The Git repository has an eap_example directory that contains an
+example showing how EAP peer and server code from %wpa_supplicant and
+hostapd can be used as a library. The example program initializes both
+an EAP server and an EAP peer entities and then runs through an
+EAP-PEAP/MSCHAPv2 authentication.
+
+eap_example_peer.c shows the initialization and glue code needed to
+control the EAP peer implementation. eap_example_server.c does the
+same for EAP server. eap_example.c is an example that ties in both the
+EAP server and client parts to allow an EAP authentication to be
+shown.
+
+In this example, the EAP messages are passed between the server and
+the peer are passed by direct function calls within the same process.
+In practice, server and peer functionalities would likely reside in
+separate devices and the EAP messages would be transmitted between the
+devices based on an external protocol. For example, in IEEE 802.11
+uses IEEE 802.1X EAPOL state machines to control the transmission of
+EAP messages and WiMax supports optional PMK EAP authentication
+mechanism that transmits EAP messages as defined in IEEE 802.16e.
+
+The EAP library links in number of helper functions from src/utils and
+src/crypto directories. Most of these are suitable as-is, but it may
+be desirable to replace the debug output code in src/utils/wpa_debug.c
+by dropping this file from the library and re-implementing the
+functions there in a way that better fits in with the main
+application.
+
+*/
diff --git a/doc/eap_server.doxygen b/doc/eap_server.doxygen
new file mode 100644 (file)
index 0000000..4aca53d
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+\page eap_server_module EAP server implementation
+
+Extensible Authentication Protocol (EAP) is an authentication framework
+defined in RFC 3748. hostapd uses a separate code module for EAP server
+implementation. This module was designed to use only a minimal set of
+direct function calls (mainly, to debug/event functions) in order for
+it to be usable in other programs. The design of the EAP
+implementation is based loosely on RFC 4137. The state machine is
+defined in this RFC and so is the interface between the server state
+machine and methods. As such, this RFC provides useful information for
+understanding the EAP server implementation in hostapd.
+
+Some of the terminology used in EAP state machine is referring to
+EAPOL (IEEE 802.1X), but there is no strict requirement on the lower
+layer being IEEE 802.1X if EAP module is built for other programs than
+%wpa_supplicant. These terms should be understood to refer to the
+lower layer as defined in RFC 4137.
+
+
+\section adding_eap_methods Adding EAP methods
+
+Each EAP method is implemented as a separate module, usually as one C
+file named eap_<name of the method>.c, e.g., eap_md5.c. All EAP
+methods use the same interface between the server state machine and
+method specific functions. This allows new EAP methods to be added
+without modifying the core EAP state machine implementation.
+
+New EAP methods need to be registered by adding them into the build
+(Makefile) and the EAP method registration list in the
+eap_server_register_methods() function of eap_methods.c. Each EAP
+method should use a build-time configuration option, e.g., EAP_TLS, in
+order to make it possible to select which of the methods are included
+in the build.
+
+EAP methods must implement the interface defined in eap_i.h. struct
+eap_method defines the needed function pointers that each EAP method
+must provide. In addition, the EAP type and name are registered using
+this structure. This interface is based on section 4.4 of RFC 4137.
+
+It is recommended that the EAP methods would use generic helper
+functions, eap_msg_alloc() and eap_hdr_validate() when processing
+messages. This allows code sharing and can avoid missing some of the
+needed validation steps for received packets. In addition, these
+functions make it easier to change between expanded and legacy EAP
+header, if needed.
+
+When adding an EAP method that uses a vendor specific EAP type
+(Expanded Type as defined in RFC 3748, Chapter 5.7), the new method
+must be registered by passing vendor id instead of EAP_VENDOR_IETF to
+eap_server_method_alloc(). These methods must not try to emulate
+expanded types by registering a legacy EAP method for type 254. See
+eap_vendor_test.c for an example of an EAP method implementation that
+is implemented as an expanded type.
+
+*/
diff --git a/doc/hostapd.fig b/doc/hostapd.fig
new file mode 100644 (file)
index 0000000..af3f0be
--- /dev/null
@@ -0,0 +1,264 @@
+#FIG 3.2
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 1875 4050 2925 4350
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        1875 4050 2925 4050 2925 4350 1875 4350 1875 4050
+4 0 0 50 -1 0 12 0.0000 4 180 735 2025 4275 l2_packet\001
+-6
+6 4725 1200 5925 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        4725 1200 5925 1200 5925 1500 4725 1500 4725 1200
+4 0 0 50 -1 0 12 0.0000 4 135 1005 4800 1425 GUI frontend\001
+-6
+6 6000 2700 7200 3225
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        6000 2700 7200 2700 7200 3225 6000 3225 6000 2700
+4 0 0 50 -1 0 12 0.0000 4 135 975 6075 2925 WPA/WPA2\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 3150 state machine\001
+-6
+6 6000 4950 7200 5475
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        6000 4950 7200 4950 7200 5475 6000 5475 6000 4950
+4 0 0 50 -1 0 12 0.0000 4 135 360 6075 5175 EAP\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 5400 state machine\001
+-6
+6 4350 3900 5025 4425
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        4350 3900 5025 3900 5025 4425 4350 4425 4350 3900
+4 0 0 50 -1 0 12 0.0000 4 105 420 4500 4125 event\001
+4 0 0 50 -1 0 12 0.0000 4 180 315 4500 4350 loop\001
+-6
+6 4275 2550 5100 2850
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        4275 2550 5100 2550 5100 2850 4275 2850 4275 2550
+4 0 0 50 -1 0 12 0.0000 4 135 450 4425 2775 ctrl i/f\001
+-6
+6 6000 3900 7200 4425
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        6000 3900 7200 3900 7200 4425 6000 4425 6000 3900
+4 0 0 50 -1 0 12 0.0000 4 135 600 6075 4125 EAPOL\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 4350 state machine\001
+-6
+6 2775 3150 4050 3450
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        2775 3150 4050 3150 4050 3450 2775 3450 2775 3150
+4 0 0 50 -1 0 12 0.0000 4 180 990 2925 3375 configuration\001
+-6
+6 3450 1200 4575 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        3450 1200 4575 1200 4575 1500 3450 1500 3450 1200
+4 0 0 50 -1 0 12 0.0000 4 180 870 3600 1425 hostapd_cli\001
+-6
+6 3525 7800 5775 8100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        3525 7800 5775 7800 5775 8100 3525 8100 3525 7800
+4 0 0 50 -1 0 12 0.0000 4 135 2145 3600 8025 kernel network device driver\001
+-6
+6 4275 6000 5100 6300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        4275 6000 5100 6000 5100 6300 4275 6300 4275 6000
+4 0 0 50 -1 0 12 0.0000 4 135 630 4350 6225 driver i/f\001
+-6
+6 8175 4725 9225 5025
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        8175 4725 9225 4725 9225 5025 8175 5025 8175 4725
+4 0 0 50 -1 0 12 0.0000 4 135 735 8250 4950 EAP-TLS\001
+-6
+6 9300 4725 10350 5025
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        9300 4725 10350 4725 10350 5025 9300 5025 9300 4725
+4 0 0 50 -1 0 12 0.0000 4 135 810 9375 4950 EAP-MD5\001
+-6
+6 8175 5100 9225 5400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        8175 5100 9225 5100 9225 5400 8175 5400 8175 5100
+4 0 0 50 -1 0 12 0.0000 4 135 885 8250 5325 EAP-PEAP\001
+-6
+6 9300 5100 10350 5400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        9300 5100 10350 5100 10350 5400 9300 5400 9300 5100
+4 0 0 50 -1 0 12 0.0000 4 135 840 9375 5325 EAP-TTLS\001
+-6
+6 8175 5475 9225 5775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        8175 5475 9225 5475 9225 5775 8175 5775 8175 5475
+4 0 0 50 -1 0 12 0.0000 4 135 780 8250 5700 EAP-GTC\001
+-6
+6 8175 5850 9225 6150
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        8175 5850 9225 5850 9225 6150 8175 6150 8175 5850
+4 0 0 50 -1 0 12 0.0000 4 135 750 8250 6075 EAP-SIM\001
+-6
+6 8175 6225 9225 6525
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        8175 6225 9225 6225 9225 6525 8175 6525 8175 6225
+4 0 0 50 -1 0 12 0.0000 4 135 765 8250 6450 EAP-PSK\001
+-6
+6 9300 5850 10350 6150
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        9300 5850 10350 5850 10350 6150 9300 6150 9300 5850
+4 0 0 50 -1 0 12 0.0000 4 135 825 9375 6075 EAP-AKA\001
+-6
+6 9300 5475 10350 5775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        9300 5475 10350 5475 10350 5775 9300 5775 9300 5475
+4 0 0 50 -1 0 12 0.0000 4 135 795 9375 5700 EAP-PAX\001
+-6
+6 8175 6600 9675 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        8175 6600 9675 6600 9675 6900 8175 6900 8175 6600
+4 0 0 50 -1 0 12 0.0000 4 135 1365 8250 6825 EAP-MSCHAPv2\001
+-6
+6 8700 3450 9375 3750
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        8700 3450 9375 3450 9375 3750 8700 3750 8700 3450
+4 0 0 50 -1 0 12 0.0000 4 150 480 8775 3675 crypto\001
+-6
+6 9600 3450 10275 3750
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        9600 3450 10275 3450 10275 3750 9600 3750 9600 3450
+4 0 0 50 -1 0 12 0.0000 4 135 315 9750 3675 TLS\001
+-6
+6 6000 5775 7200 6300
+6 6000 5775 7200 6300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        6000 5775 7200 5775 7200 6300 6000 6300 6000 5775
+4 0 0 50 -1 0 12 0.0000 4 135 690 6075 6000 RADIUS\001
+-6
+4 0 0 50 -1 0 12 0.0000 4 90 480 6075 6225 server\001
+-6
+6 8100 2250 8925 2775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        8100 2250 8925 2250 8925 2775 8100 2775 8100 2250
+4 0 0 50 -1 0 12 0.0000 4 135 690 8175 2475 RADIUS\001
+4 0 0 50 -1 0 12 0.0000 4 135 420 8175 2700 client\001
+-6
+6 3150 5475 4425 5775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        3150 5475 4425 5475 4425 5775 3150 5775 3150 5475
+4 0 0 50 -1 0 12 0.0000 4 135 990 3300 5700 driver events\001
+-6
+6 1950 5550 2625 6075
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        1950 5550 2625 5550 2625 6075 1950 6075 1950 5550
+4 0 0 50 -1 0 12 0.0000 4 135 540 2025 5775 Station\001
+4 0 0 50 -1 0 12 0.0000 4 135 375 2025 6000 table\001
+-6
+6 1875 4725 2925 5250
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        1875 4725 2925 4725 2925 5250 1875 5250 1875 4725
+4 0 0 50 -1 0 12 0.0000 4 135 960 1950 4950 IEEE 802.11\001
+4 0 0 50 -1 0 12 0.0000 4 135 555 1950 5175 MLME\001
+-6
+2 1 1 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2
+        1275 4200 1875 4200
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+        4500 2550 3900 1500
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+        4800 2550 5400 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        2925 4200 4350 4200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        5025 3900 6000 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        5025 4200 6000 4200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        4650 6000 4650 4425
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        6600 4425 6600 4950
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        6600 3225 6600 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        7200 5250 8100 5250
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        9075 4425 9075 3750
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        7200 3000 8700 3525
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        4650 3900 4650 2850
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        7200 4125 8700 3675
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        6000 4350 5025 6000
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        6000 3150 4875 6000
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        1500 2100 10800 2100 10800 7500 1500 7500 1500 2100
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        9900 4425 9900 3750
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 1
+        4350 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        4350 3900 4050 3450
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        4350 4425 4050 5475
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+        2250 7200 4200 7800
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+        7200 7200 5100 7800
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        2775 6900 3675 6900 3675 7200 2775 7200 2775 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        3750 6900 4650 6900 4650 7200 3750 7200 3750 6900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 4
+        2250 6900 2250 6600 7200 6600 7200 6900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        3225 6900 3225 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        4200 6900 4200 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        5175 6900 5175 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        6150 6900 6150 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        4650 6600 4650 6300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        1800 6900 2700 6900 2700 7200 1800 7200 1800 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        4725 6900 5625 6900 5625 7200 4725 7200 4725 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        5700 6900 6600 6900 6600 7200 5700 7200 5700 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        6675 6900 7800 6900 7800 7200 6675 7200 6675 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        8100 6975 10425 6975 10425 4425 8100 4425 8100 6975
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        6600 5475 6600 5775
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        5025 4425 6000 5775
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
+        4800 3900 5925 2550 8100 2550
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        7200 3900 8475 2775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        9450 2250 10425 2250 10425 2775 9450 2775 9450 2250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        8925 2475 9450 2475
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        2325 5550 2325 5250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        2925 4950 4350 4275
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
+        2850 4725 5775 2400 8100 2400
+4 0 0 50 -1 0 12 0.0000 4 135 915 375 3975 EAPOL and\001
+4 0 0 50 -1 0 12 0.0000 4 180 630 375 4200 pre-auth\001
+4 0 0 50 -1 0 12 0.0000 4 180 810 375 4425 ethertypes\001
+4 0 0 50 -1 0 12 0.0000 4 135 1050 375 4650 from/to kernel\001
+4 0 0 50 -1 0 12 0.0000 4 135 1920 3675 1875 frontend control interface\001
+4 0 0 50 -1 2 14 0.0000 4 195 720 1637 2371 hostapd\001
+4 0 0 50 -1 0 12 0.0000 4 180 600 3825 7125 prism54\001
+4 0 0 50 -1 0 12 0.0000 4 180 510 1875 7125 hostap\001
+4 0 0 50 -1 0 12 0.0000 4 135 600 2850 7125 madwifi\001
+4 0 0 50 -1 0 12 0.0000 4 135 270 4800 7125 bsd\001
+4 0 0 50 -1 0 12 0.0000 4 105 300 6750 7125 test\001
+4 0 0 50 -1 0 12 0.0000 4 135 420 5775 7125 wired\001
+4 0 0 50 -1 0 12 0.0000 4 135 1050 8700 4650 EAP methods\001
+4 0 0 50 -1 0 12 0.0000 4 135 690 9525 2475 RADIUS\001
+4 0 0 50 -1 0 12 0.0000 4 180 825 9525 2700 accounting\001
diff --git a/doc/hostapd_ctrl_iface.doxygen b/doc/hostapd_ctrl_iface.doxygen
new file mode 100644 (file)
index 0000000..ae778bc
--- /dev/null
@@ -0,0 +1,66 @@
+/**
+\page hostapd_ctrl_iface_page hostapd control interface
+
+hostapd implements a control interface that can be used by
+external programs to control the operations of the hostapd
+daemon and to get status information and event notifications. There is
+a small C library, in a form of a single C file, wpa_ctrl.c, that
+provides helper functions to facilitate the use of the control
+interface. External programs can link this file into them and then use
+the library functions documented in wpa_ctrl.h to interact with
+%wpa_supplicant. This library can also be used with C++. hostapd_cli.c
+is an example program using this library.
+
+There are multiple mechanisms for inter-process communication. For
+example, Linux version of hostapd is using UNIX domain sockets for the
+control interface. The use of the functions defined in wpa_ctrl.h can
+be used to hide the details of the used IPC from external programs.
+
+
+\section using_ctrl_iface Using the control interface
+
+External programs, e.g., a GUI or a configuration utility, that need to
+communicate with hostapd should link in wpa_ctrl.c. This
+allows them to use helper functions to open connection to the control
+interface with wpa_ctrl_open() and to send commands with
+wpa_ctrl_request().
+
+hostapd uses the control interface for two types of communication:
+commands and unsolicited event messages. Commands are a pair of
+messages, a request from the external program and a response from
+hostapd. These can be executed using wpa_ctrl_request().
+Unsolicited event messages are sent by hostapd to the control
+interface connection without specific request from the external program
+for receiving each message. However, the external program needs to
+attach to the control interface with wpa_ctrl_attach() to receive these
+unsolicited messages.
+
+If the control interface connection is used both for commands and
+unsolicited event messages, there is potential for receiving an
+unsolicited message between the command request and response.
+wpa_ctrl_request() caller will need to supply a callback, msg_cb,
+for processing these messages. Often it is easier to open two
+control interface connections by calling wpa_ctrl_open() twice and
+then use one of the connections for commands and the other one for
+unsolicited messages. This way command request/response pairs will
+not be broken by unsolicited messages. wpa_cli is an example of how
+to use only one connection for both purposes and wpa_gui demonstrates
+how to use two separate connections.
+
+Once the control interface connection is not needed anymore, it should
+be closed by calling wpa_ctrl_close(). If the connection was used for
+unsolicited event messages, it should be first detached by calling
+wpa_ctrl_detach().
+
+
+\section ctrl_iface_cmds Control interface commands
+
+Following commands can be used with wpa_ctrl_request():
+
+\subsection ctrl_iface_PING PING
+
+This command can be used to test whether hostapd is replying
+to the control interface commands. The expected reply is \c PONG if the
+connection is open and hostapd is processing commands.
+
+*/
diff --git a/doc/mainpage.doxygen b/doc/mainpage.doxygen
new file mode 100644 (file)
index 0000000..690b7d6
--- /dev/null
@@ -0,0 +1,95 @@
+/**
+\mainpage Developers' documentation for wpa_supplicant and hostapd
+
+The goal of this documentation and comments in the source code is to
+give enough information for other developers to understand how
+%wpa_supplicant and hostapd have been implemented, how they can be
+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.
+
+The source code and read-only access to the combined %wpa_supplicant
+and hostapd Git repository is available from the project home page at
+http://w1.fi/wpa_supplicant/. This developers' documentation is also
+available as a PDF file from
+http://w1.fi/wpa_supplicant/wpa_supplicant-devel.pdf .
+
+
+\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
+802.1X/WPA component that is used in the client stations. It
+implements key negotiation with a WPA Authenticator and it can optionally
+control roaming and IEEE 802.11 authentication/association of the wlan
+driver.
+
+The design goal for %wpa_supplicant was to use hardware, driver, and
+OS independent, portable C code for all WPA functionality. The source
+code is divided into separate C files as shown on the \ref
+code_structure "code structure page". All hardware/driver specific
+functionality is in separate files that implement a \ref
+driver_wrapper "well-defined driver API". Information about porting
+to different target boards and operating systems is available on
+the \ref porting "porting page".
+
+EAPOL (IEEE 802.1X) state machines are implemented as a separate
+module that interacts with \ref eap_peer_module "EAP peer implementation".
+In addition to programs aimed at normal production use,
+%wpa_supplicant source tree includes number of \ref testing_tools
+"testing and development tools" that make it easier to test the
+programs without having to setup a full test setup with wireless
+cards. These tools can also be used to implement automatic test
+suites.
+
+%wpa_supplicant implements a
+\ref ctrl_iface_page "control interface" that can be used by
+external programs to control the operations of the %wpa_supplicant
+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
+
+
+\section hostapd hostapd
+
+hostapd includes IEEE 802.11 access point management (authentication /
+association), IEEE 802.1X/WPA/WPA2 Authenticator, EAP server, and
+RADIUS authentication server functionality. It can be build with
+various configuration option, e.g., a standalone AP management
+solution or a RADIUS authentication server with support for number of
+EAP methods.
+
+The design goal for hostapd was to use hardware, driver, and
+OS independent, portable C code for all WPA functionality. The source
+code is divided into separate C files as shown on the \ref
+code_structure "code structure page". All hardware/driver specific
+functionality is in separate files that implement a \ref
+driver_wrapper "well-defined driver API". Information about porting
+to different target boards and operating systems is available on
+the \ref porting "porting page".
+
+EAPOL (IEEE 802.1X) state machines are implemented as a separate
+module that interacts with \ref eap_server_module "EAP server implementation".
+Similarly, RADIUS authentication server is in its own separate module.
+Both IEEE 802.1X and RADIUS authentication server can use EAP server
+functionality.
+
+hostapd implements a \ref hostapd_ctrl_iface_page "control interface"
+that can be used by external programs to control the operations of the
+hostapdt 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 hostapd.png "hostapd modules"
+\image latex hostapd.eps "hostapd modules" width=15cm
+
+*/
diff --git a/doc/porting.doxygen b/doc/porting.doxygen
new file mode 100644 (file)
index 0000000..7ea6a34
--- /dev/null
@@ -0,0 +1,208 @@
+/**
+\page porting Porting to different target boards and operating systems
+
+%wpa_supplicant was designed to be easily portable to different
+hardware (board, CPU) and software (OS, drivers) targets. It is
+already used with number of operating systems and numerous wireless
+card models and drivers. The main %wpa_supplicant repository includes
+support for Linux, FreeBSD, and Windows. In addition, the code has been
+ported to number of other operating systems like VxWorks, PalmOS,
+Windows CE, and Windows Mobile. On the hardware
+side, %wpa_supplicant is used on various systems: desktops, laptops,
+PDAs, and embedded devices with CPUs including x86, PowerPC,
+arm/xscale, and MIPS. Both big and little endian configurations are
+supported.
+
+
+\section ansi_c_extra Extra functions on top of ANSI C
+
+%wpa_supplicant is mostly using ANSI C functions that are available on
+most targets. However, couple of additional functions that are common
+on modern UNIX systems are used. Number of these are listed with
+prototypes in common.h (the \verbatim #ifdef CONFIG_ANSI_C_EXTRA \endverbatim
+block). These functions may need to be implemented or at least defined
+as macros to native functions in the target OS or C library.
+
+Many of the common ANSI C functions are used through a wrapper
+definitions in os.h to allow these to be replaced easily with a
+platform specific version in case standard C libraries are not
+available. In addition, os.h defines couple of common platform
+specific functions that are implemented in os_unix.c for UNIX like
+targets and in os_win32.c for Win32 API. If the target platform does
+not support either of these examples, a new os_*.c file may need to be
+added.
+
+Unless OS_NO_C_LIB_DEFINES is defined, the standard ANSI C and POSIX
+functions are used by defining the os_*() wrappers to use them
+directly in order to avoid extra cost in size and speed. If the target
+platform needs different versions of the functions, os.h can be
+modified to define the suitable macros or alternatively,
+OS_NO_C_LIB_DEFINES may be defined for the build and the wrapper
+functions can then be implemented in a new os_*.c wrapper file.
+
+common.h defines number of helper macros for handling integers of
+different size and byte order. Suitable version of these definitions
+may need to be added for the target platform.
+
+
+\section configuration_backend Configuration backend
+
+%wpa_supplicant implements a configuration interface that allows the
+backend to be easily replaced in order to read configuration data from
+a suitable source depending on the target platform. config.c
+implements the generic code that can be shared with all configuration
+backends. Each backend is implemented in its own config_*.c file.
+
+The included config_file.c backend uses a text file for configuration
+and config_winreg.c uses Windows registry. These files can be used as
+an example for a new configuration backend if the target platform uses
+different mechanism for configuration parameters. In addition,
+config_none.c can be used as an empty starting point for building a
+new configuration backend.
+
+
+\section driver_iface_porting Driver interface
+
+Unless the target OS and driver is already supported, most porting
+projects have to implement a driver wrapper. This may be done by
+adding a new driver interface module or modifying an existing module
+(driver_*.c) if the new target is similar to one of them. \ref
+driver_wrapper "Driver wrapper implementation" describes the details
+of the driver interface and discusses the tasks involved in porting
+this part of %wpa_supplicant.
+
+
+\section l2_packet_porting l2_packet (link layer access)
+
+%wpa_supplicant needs to have access to sending and receiving layer 2
+(link layer) packets with two Ethertypes: EAP-over-LAN (EAPOL) 0x888e
+and RSN pre-authentication 0x88c7. l2_packet.h defines the interfaces
+used for this in the core %wpa_supplicant implementation.
+
+If the target operating system supports a generic mechanism for link
+layer access, that is likely the best mechanism for providing the
+needed functionality for %wpa_supplicant. Linux packet socket is an
+example of such a generic mechanism. If this is not available, a
+separate interface may need to be implemented to the network stack or
+driver. This is usually an intermediate or protocol driver that is
+operating between the device driver and the OS network stack. If such
+a mechanism is not feasible, the interface can also be implemented
+directly in the device driver.
+
+The main %wpa_supplicant repository includes l2_packet implementations
+for Linux using packet sockets (l2_packet_linux.c), more portable
+version using libpcap/libdnet libraries (l2_packet_pcap.c; this
+supports WinPcap, too), and FreeBSD specific version of libpcap
+interface (l2_packet_freebsd.c).
+
+If the target operating system is supported by libpcap (receiving) and
+libdnet (sending), l2_packet_pcap.c can likely be used with minimal or
+no changes. If this is not a case or a proprietary interface for link
+layer is required, a new l2_packet module may need to be
+added. Alternatively, struct wpa_driver_ops::send_eapol() handler can
+be used to override the l2_packet library if the link layer access is
+integrated with the driver interface implementation.
+
+
+\section eloop_porting Event loop
+
+%wpa_supplicant uses a single process/thread model and an event loop
+to provide callbacks on events (registered timeout, received packet,
+signal). eloop.h defines the event loop interface. eloop.c is an
+implementation of such an event loop using select() and sockets. This
+is suitable for most UNIX/POSIX systems. When porting to other
+operating systems, it may be necessary to replace that implementation
+with OS specific mechanisms that provide similar functionality.
+
+
+\section ctrl_iface_porting Control interface
+
+%wpa_supplicant uses a \ref ctrl_iface_page "control interface"
+to allow external processed
+to get status information and to control the operations. Currently,
+this is implemented with socket based communication; both UNIX domain
+sockets and UDP sockets are supported. If the target OS does not
+support sockets, this interface will likely need to be modified to use
+another mechanism like message queues. The control interface is
+optional component, so it is also possible to run %wpa_supplicant
+without porting this part.
+
+The %wpa_supplicant side of the control interface is implemented in
+ctrl_iface.c. Matching client side is implemented as a control
+interface library in wpa_ctrl.c.
+
+
+\section entry_point Program entry point
+
+%wpa_supplicant defines a set of functions that can be used to
+initialize main supplicant processing. Each operating system has a
+mechanism for starting new processing or threads. This is usually a
+function with a specific set of arguments and calling convention. This
+function is responsible on initializing %wpa_supplicant.
+
+main.c includes an entry point for UNIX-like operating system, i.e.,
+main() function that uses command line arguments for setting
+parameters for %wpa_supplicant. When porting to other operating
+systems, similar OS-specific entry point implementation is needed. It
+can be implemented in a new file that is then linked with
+%wpa_supplicant instead of main.o. main.c is also a good example on
+how the initialization process should be done.
+
+The supplicant initialization functions are defined in
+wpa_supplicant_i.h. In most cases, the entry point function should
+start by fetching configuration parameters. After this, a global
+%wpa_supplicant context is initialized with a call to
+wpa_supplicant_init(). After this, existing network interfaces can be
+added with wpa_supplicant_add_iface(). wpa_supplicant_run() is then
+used to start the main event loop. Once this returns at program
+termination time, wpa_supplicant_deinit() is used to release global
+context data.
+
+wpa_supplicant_add_iface() and wpa_supplicant_remove_iface() can be
+used dynamically to add and remove interfaces based on when
+%wpa_supplicant processing is needed for them. This can be done, e.g.,
+when hotplug network adapters are being inserted and ejected. It is
+also possible to do this when a network interface is being
+enabled/disabled if it is desirable that %wpa_supplicant processing
+for the interface is fully enabled/disabled at the same time.
+
+
+\section simple_build Simple build example
+
+One way to start a porting project is to begin with a very simple
+build of %wpa_supplicant with WPA-PSK support and once that is
+building correctly, start adding features.
+
+Following command can be used to build very simple version of
+%wpa_supplicant:
+
+\verbatim
+cc -o wpa_supplicant config.c eloop.c common.c md5.c rc4.c sha1.c \
+       config_none.c l2_packet_none.c tls_none.c wpa.c preauth.c \
+       aes_wrap.c wpa_supplicant.c events.c main_none.c drivers.c
+\endverbatim
+
+The end result is not really very useful since it uses empty functions
+for configuration parsing and layer 2 packet access and does not
+include a driver interface. However, this is a good starting point
+since the build is complete in the sense that all functions are
+present and this is easy to configure to a build system by just
+including the listed C files.
+
+Once this version can be build successfully, the end result can be
+made functional by adding a proper program entry point (main*.c),
+driver interface (driver_*.c and matching CONFIG_DRIVER_* define for
+registration in drivers.c), configuration parser/writer (config_*.c),
+and layer 2 packet access implementation (l2_packet_*.c). After these
+components have been added, the end result should be a working
+WPA/WPA2-PSK enabled supplicant.
+
+After the basic functionality has been verified to work, more features
+can be added by linking in more files and defining C pre-processor
+defines. Currently, the best source of information for what options
+are available and which files needs to be included is in the Makefile
+used for building the supplicant with make. Similar configuration will
+be needed for build systems that either use different type of make
+tool or a GUI-based project configuration.
+
+*/
diff --git a/doc/testing_tools.doxygen b/doc/testing_tools.doxygen
new file mode 100644 (file)
index 0000000..01db0b6
--- /dev/null
@@ -0,0 +1,363 @@
+/**
+\page testing_tools Testing and development tools
+
+[ \ref eapol_test "eapol_test" |
+\ref preauth_test "preauth_test" |
+\ref driver_test "driver_test" |
+\ref unit_tests "Unit tests" |
+\ref wpa_trace "Tracing code" ]
+
+%wpa_supplicant source tree includes number of testing and development
+tools that make it easier to test the programs without having to setup
+a full test setup with wireless cards. In addition, these tools can be
+used to implement automatic tests suites.
+
+\section eapol_test eapol_test - EAP peer and RADIUS client testing
+
+eapol_test is a program that links together the same EAP peer
+implementation that %wpa_supplicant is using and the RADIUS
+authentication client code from hostapd. In addition, it has minimal
+glue code to combine these two components in similar ways to IEEE
+802.1X/EAPOL Authenticator state machines. In other words, it
+integrates IEEE 802.1X Authenticator (normally, an access point) and
+IEEE 802.1X Supplicant (normally, a wireless client) together to
+generate a single program that can be used to test EAP methods without
+having to setup an access point and a wireless client.
+
+The main uses for eapol_test are in interoperability testing of EAP
+methods against RADIUS servers and in development testing for new EAP
+methods. It can be easily used to automate EAP testing for
+interoperability and regression since the program can be run from
+shell scripts without require additional test components apart from a
+RADIUS server. For example, the automated EAP tests described in
+eap_testing.txt are implemented with eapol_test. Similarly, eapol_test
+could be used to implement an automated regression test suite for a
+RADIUS authentication server.
+
+eapol_test uses the same build time configuration file, .config, as
+%wpa_supplicant. This file is used to select which EAP methods are
+included in eapol_test. This program is not built with the default
+Makefile target, so a separate make command needs to be used to
+compile the tool:
+
+\verbatim
+make eapol_test
+\endverbatim
+
+The resulting eapol_test binary has following command like options:
+
+\verbatim
+usage:
+eapol_test [-nWS] -c<conf> [-a<AS IP>] [-p<AS port>] [-s<AS secret>] \
+           [-r<count>] [-t<timeout>] [-C<Connect-Info>] \
+           [-M<client MAC address>]
+eapol_test scard
+eapol_test sim <PIN> <num triplets> [debug]
+
+options:
+  -c<conf> = configuration file
+  -a<AS IP> = IP address of the authentication server, default 127.0.0.1
+  -p<AS port> = UDP port of the authentication server, default 1812
+  -s<AS secret> = shared secret with the authentication server, default 'radius'
+  -r<count> = number of re-authentications
+  -W = wait for a control interface monitor before starting
+  -S = save configuration after authentiation
+  -n = no MPPE keys expected
+  -t<timeout> = sets timeout in seconds (default: 30 s)
+  -C<Connect-Info> = RADIUS Connect-Info (default: CONNECT 11Mbps 802.11b)
+  -M<client MAC address> = Set own MAC address (Calling-Station-Id,
+                           default: 02:00:00:00:00:01)
+\endverbatim
+
+
+As an example,
+\verbatim
+eapol_test -ctest.conf -a127.0.0.1 -p1812 -ssecret -r1
+\endverbatim
+tries to complete EAP authentication based on the network
+configuration from test.conf against the RADIUS server running on the
+local host. A re-authentication is triggered to test fast
+re-authentication. The configuration file uses the same format for
+network blocks as %wpa_supplicant.
+
+
+\section preauth_test preauth_test - WPA2 pre-authentication and EAP peer testing
+
+preauth_test is similar to eapol_test in the sense that in combines
+EAP peer implementation with something else, in this case, with WPA2
+pre-authentication. This tool can be used to test pre-authentication
+based on the code that %wpa_supplicant is using. As such, it tests
+both the %wpa_supplicant implementation and the functionality of an
+access point.
+
+preauth_test is built with:
+
+\verbatim
+make preauth_test
+\endverbatim
+
+and it uses following command line arguments:
+
+\verbatim
+usage: preauth_test <conf> <target MAC address> <ifname>
+\endverbatim
+
+For example,
+\verbatim
+preauth_test test.conf 02:11:22:33:44:55 eth0
+\endverbatim
+would use network configuration from test.conf to try to complete
+pre-authentication with AP using BSSID 02:11:22:33:44:55. The
+pre-authentication packets would be sent using the eth0 interface.
+
+
+\section driver_test driver_test - driver interface for testing wpa_supplicant
+
+%wpa_supplicant was designed to support number of different ways to
+communicate with a network device driver. This design uses \ref
+driver_wrapper "driver interface API" and number of driver interface
+implementations. One of these is driver_test.c, i.e., a test driver
+interface that is actually not using any drivers. Instead, it provides
+a mechanism for running %wpa_supplicant without having to have a
+device driver or wireless LAN hardware for that matter.
+
+driver_test can be used to talk directly with hostapd's driver_test
+component to create a test setup where one or more clients and access
+points can be tested within one test host and without having to have
+multiple wireless cards. This makes it easier to test the core code in
+%wpa_supplicant, and hostapd for that matter. Since driver_test uses
+the same driver API than any other driver interface implementation,
+the core code of %wpa_supplicant and hostapd can be tested with the
+same coverage as one would get when using real wireless cards. The
+only area that is not tested is the driver interface implementation
+(driver_*.c).
+
+Having the possibility to use simulated network components makes it
+much easier to do development testing while adding new features and to
+reproduce reported bugs. As such, it is often easiest to just do most
+of the development and bug fixing without using real hardware. Once
+the driver_test setup has been used to implement a new feature or fix
+a bug, the end result can be verified with wireless LAN cards. In many
+cases, this may even be unnecessary, depending on what area the
+feature/bug is relating to. Of course, changes to driver interfaces
+will still require use of real hardware.
+
+Since multiple components can be run within a single host, testing of
+complex network configuration, e.g., large number of clients
+association with an access point, becomes quite easy. All the tests
+can also be automated without having to resort to complex test setup
+using remote access to multiple computers.
+
+driver_test can be included in the %wpa_supplicant build in the same
+way as any other driver interface, i.e., by adding the following line
+into .config:
+
+\verbatim
+CONFIG_DRIVER_TEST=y
+\endverbatim
+
+When running %wpa_supplicant, the test interface is selected by using
+\a -Dtest command line argument. The interface name (\a -i argument)
+can be selected arbitrarily, i.e., it does not need to match with any
+existing network interface. The interface name is used to generate a
+MAC address, so when using multiple clients, each should use a
+different interface, e.g., \a sta1, \a sta2, and so on.
+
+%wpa_supplicant and hostapd are configured in the same way as they
+would be for normal use. Following example shows a simple test setup
+for WPA-PSK.
+
+hostapd is configured with following psk-test.conf configuration file:
+
+\verbatim
+driver=test
+
+interface=ap1
+logger_stdout=-1
+logger_stdout_level=0
+debug=2
+dump_file=/tmp/hostapd.dump
+
+test_socket=/tmp/Test/ap1
+
+ssid=jkm-test-psk
+
+wpa=1
+wpa_key_mgmt=WPA-PSK
+wpa_pairwise=TKIP
+wpa_passphrase=12345678
+\endverbatim
+
+and started with following command:
+
+\verbatim
+hostapd psk-test.conf
+\endverbatim
+
+%wpa_supplicant uses following configuration file:
+
+\verbatim
+driver_param=test_socket=/tmp/Test/ap1
+
+network={
+    ssid="jkm-test-psk"
+    key_mgmt=WPA-PSK
+    psk="12345678"
+}
+\endverbatim
+
+%wpa_supplicant can then be started with following command:
+
+\verbatim
+wpa_supplicant -Dtest -cpsk-test.conf -ista1 -ddK
+\endverbatim
+
+If run without debug information, i.e., with
+
+\verbatim
+wpa_supplicant -Dtest -cpsk-test.conf -ista1
+\endverbatim
+
+%wpa_supplicant completes authentication and prints following events:
+
+\verbatim
+Trying to associate with 02:b8:a6:62:08:5a (SSID='jkm-test-psk' freq=0 MHz)
+Associated with 02:b8:a6:62:08:5a
+WPA: Key negotiation completed with 02:b8:a6:62:08:5a [PTK=TKIP GTK=TKIP]
+CTRL-EVENT-CONNECTED - Connection to 02:b8:a6:62:08:5a completed (auth)
+\endverbatim
+
+If test setup is using multiple clients, it is possible to run
+multiple %wpa_supplicant processes. Alternatively, the support for
+multiple interfaces can be used with just one process to save some
+resources on single-CPU systems. For example, following command runs
+two clients:
+
+\verbatim
+./wpa_supplicant -Dtest -cpsk-test.conf -ista1 \
+       -N -Dtest -cpsk-test.conf -ista2
+\endverbatim
+
+This shows following event log:
+
+\verbatim
+Trying to associate with 02:b8:a6:62:08:5a (SSID='jkm-test-psk' freq=0 MHz)
+Associated with 02:b8:a6:62:08:5a
+WPA: Key negotiation completed with 02:b8:a6:62:08:5a [PTK=TKIP GTK=TKIP]
+CTRL-EVENT-CONNECTED - Connection to 02:b8:a6:62:08:5a completed (auth)
+Trying to associate with 02:b8:a6:62:08:5a (SSID='jkm-test-psk' freq=0 MHz)
+Associated with 02:b8:a6:62:08:5a
+WPA: Key negotiation completed with 02:b8:a6:62:08:5a [PTK=TKIP GTK=TKIP]
+CTRL-EVENT-CONNECTED - Connection to 02:b8:a6:62:08:5a completed (auth)
+\endverbatim
+
+hostapd shows this with following events:
+
+\verbatim
+ap1: STA 02:b5:64:63:30:63 IEEE 802.11: associated
+ap1: STA 02:b5:64:63:30:63 WPA: pairwise key handshake completed (WPA)
+ap1: STA 02:b5:64:63:30:63 WPA: group key handshake completed (WPA)
+ap1: STA 02:2a:c4:18:5b:f3 IEEE 802.11: associated
+ap1: STA 02:2a:c4:18:5b:f3 WPA: pairwise key handshake completed (WPA)
+ap1: STA 02:2a:c4:18:5b:f3 WPA: group key handshake completed (WPA)
+\endverbatim
+
+By default, driver_param is simulating a driver that uses the WPA/RSN
+IE generated by %wpa_supplicant. Driver-generated IE and AssocInfo
+events can be tested by adding \a use_associnfo=1 to the \a driver_param
+line in the configuration file. For example:
+
+\verbatim
+driver_param=test_socket=/tmp/Test/ap1 use_associnfo=1
+\endverbatim
+
+
+\section unit_tests Unit tests
+
+Number of the components (.c files) used in %wpa_supplicant define
+their own unit tests for automated validation of the basic
+functionality. Most of the tests for cryptographic algorithms are
+using standard test vectors to validate functionality. These tests can
+be useful especially when verifying port to a new CPU target.
+
+The test programs are collected in the tests subdirectory. All
+automated unit tests can be run with
+
+\verbatim
+make run-tests
+\endverbatim
+
+This make target builds and runs each test and terminates with zero
+exit code if all tests were completed successfully.
+
+
+\section wpa_trace Tracing code for developer debuggin
+
+%wpa_supplicant and hostapd can be built with tracing code that will
+track and analyze memory allocations and other resource registrations
+and certain API uses. If incorrect use is detected, a backtrace of the
+call location (and/or allocation location) is shown. This can also be
+used to detect certain categories of memory leaks and report them
+automatically when the program is terminated. The report will also
+include information about forgotten eloop events.
+
+The trace code can be enabled with CONFIG_WPA_TRACE=y build
+option. More verbose backtrace information can be generated if libbfd
+is available and the binaries are not stripped of symbol
+information. This is enabled with CONFIG_WPA_TRACE_BFD=y.
+
+For example, a memory leak (forgotten os_free() call) would show up
+like this when the program is terminated:
+
+\verbatim
+MEMLEAK[0x82d200]: len 128
+WPA_TRACE: memleak - START
+[0]: ./wpa_supplicant(os_malloc+0x59) [0x41a5e9]
+     os_malloc() ../src/utils/os_unix.c:359
+[1]: ./wpa_supplicant(os_zalloc+0x16) [0x41a676]
+     os_zalloc() ../src/utils/os_unix.c:418
+[2]: ./wpa_supplicant(wpa_supplicant_init+0x38) [0x48b508]
+     wpa_supplicant_init() wpa_supplicant.c:2315
+[3]: ./wpa_supplicant(main+0x2f3) [0x491073]
+     main() main.c:252
+WPA_TRACE: memleak - END
+MEMLEAK: total 128 bytes
+\endverbatim
+
+Another type of error that can be detected is freeing of memory area
+that was registered for some use and is still be referenced:
+
+\verbatim
+WPA_TRACE: Freeing referenced memory - START
+[2]: ./wpa_supplicant(os_free+0x5c) [0x41a53c]
+     os_free() ../src/utils/os_unix.c:411
+[3]: ./wpa_supplicant(wpa_supplicant_remove_iface+0x30) [0x48b380]
+     wpa_supplicant_remove_iface() wpa_supplicant.c:2259
+[4]: ./wpa_supplicant(wpa_supplicant_deinit+0x20) [0x48b3e0]
+     wpa_supplicant_deinit() wpa_supplicant.c:2430
+[5]: ./wpa_supplicant(main+0x357) [0x4910d7]
+     main() main.c:276
+WPA_TRACE: Freeing referenced memory - END
+WPA_TRACE: Reference registration - START
+[1]: ./wpa_supplicant [0x41c040]
+     eloop_trace_sock_add_ref() ../src/utils/eloop.c:94
+[2]: ./wpa_supplicant(wpa_supplicant_ctrl_iface_deinit+0x17) [0x473247]
+     wpa_supplicant_ctrl_iface_deinit() ctrl_iface_unix.c:436
+[3]: ./wpa_supplicant [0x48b21c]
+     wpa_supplicant_cleanup() wpa_supplicant.c:378
+     wpa_supplicant_deinit_iface() wpa_supplicant.c:2155
+[4]: ./wpa_supplicant(wpa_supplicant_remove_iface+0x30) [0x48b380]
+     wpa_supplicant_remove_iface() wpa_supplicant.c:2259
+[5]: ./wpa_supplicant(wpa_supplicant_deinit+0x20) [0x48b3e0]
+     wpa_supplicant_deinit() wpa_supplicant.c:2430
+[6]: ./wpa_supplicant(main+0x357) [0x4910d7]
+     main() main.c:276
+WPA_TRACE: Reference registration - END
+Aborted
+\endverbatim
+
+This type of error results in showing backtraces for both the location
+where the incorrect freeing happened and the location where the memory
+area was marked referenced.
+
+*/
diff --git a/doc/wpa_supplicant.fig b/doc/wpa_supplicant.fig
new file mode 100644 (file)
index 0000000..06abfb5
--- /dev/null
@@ -0,0 +1,247 @@
+#FIG 3.2
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 1875 4050 2925 4350
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        1875 4050 2925 4050 2925 4350 1875 4350 1875 4050
+4 0 0 50 -1 0 12 0.0000 4 180 735 2025 4275 l2_packet\001
+-6
+6 3450 1200 4275 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        3450 1200 4275 1200 4275 1500 3450 1500 3450 1200
+4 0 0 50 -1 0 12 0.0000 4 180 585 3600 1425 wpa_cli\001
+-6
+6 4725 1200 5925 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        4725 1200 5925 1200 5925 1500 4725 1500 4725 1200
+4 0 0 50 -1 0 12 0.0000 4 135 1005 4800 1425 GUI frontend\001
+-6
+6 6000 2700 7200 3225
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        6000 2700 7200 2700 7200 3225 6000 3225 6000 2700
+4 0 0 50 -1 0 12 0.0000 4 135 975 6075 2925 WPA/WPA2\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 3150 state machine\001
+-6
+6 6000 4950 7200 5475
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        6000 4950 7200 4950 7200 5475 6000 5475 6000 4950
+4 0 0 50 -1 0 12 0.0000 4 135 360 6075 5175 EAP\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 5400 state machine\001
+-6
+6 8700 3000 9375 3300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        8700 3000 9375 3000 9375 3300 8700 3300 8700 3000
+4 0 0 50 -1 0 12 0.0000 4 150 480 8775 3225 crypto\001
+-6
+6 4350 3900 5025 4425
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        4350 3900 5025 3900 5025 4425 4350 4425 4350 3900
+4 0 0 50 -1 0 12 0.0000 4 105 420 4500 4125 event\001
+4 0 0 50 -1 0 12 0.0000 4 180 315 4500 4350 loop\001
+-6
+6 4275 2550 5100 2850
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        4275 2550 5100 2550 5100 2850 4275 2850 4275 2550
+4 0 0 50 -1 0 12 0.0000 4 135 450 4425 2775 ctrl i/f\001
+-6
+6 6000 3900 7200 4425
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        6000 3900 7200 3900 7200 4425 6000 4425 6000 3900
+4 0 0 50 -1 0 12 0.0000 4 135 600 6075 4125 EAPOL\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 4350 state machine\001
+-6
+6 1800 6000 7800 8100
+6 1800 6000 7800 7200
+6 1800 6900 2700 7200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        1800 6900 2700 6900 2700 7200 1800 7200 1800 6900
+4 0 0 50 -1 0 12 0.0000 4 105 375 1875 7125 wext\001
+-6
+6 4725 6900 5625 7200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        4725 6900 5625 6900 5625 7200 4725 7200 4725 6900
+4 0 0 50 -1 0 12 0.0000 4 135 555 4800 7125 hermes\001
+-6
+6 6675 6900 7800 7200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        6675 6900 7800 6900 7800 7200 6675 7200 6675 6900
+4 0 0 50 -1 0 12 0.0000 4 180 930 6750 7125 ndiswrapper\001
+-6
+6 5700 6900 6600 7200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        5700 6900 6600 6900 6600 7200 5700 7200 5700 6900
+4 0 0 50 -1 0 12 0.0000 4 135 420 5775 7125 atmel\001
+-6
+6 4275 6000 5100 6300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        4275 6000 5100 6000 5100 6300 4275 6300 4275 6000
+4 0 0 50 -1 0 12 0.0000 4 135 630 4350 6225 driver i/f\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        2775 6900 3675 6900 3675 7200 2775 7200 2775 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        3750 6900 4650 6900 4650 7200 3750 7200 3750 6900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 4
+        2250 6900 2250 6600 7200 6600 7200 6900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        3225 6900 3225 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        4200 6900 4200 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        5175 6900 5175 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        6150 6900 6150 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        4650 6600 4650 6300
+4 0 0 50 -1 0 12 0.0000 4 180 510 2850 7125 hostap\001
+4 0 0 50 -1 0 12 0.0000 4 135 600 3825 7125 madwifi\001
+-6
+6 3525 7800 5775 8100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        3525 7800 5775 7800 5775 8100 3525 8100 3525 7800
+4 0 0 50 -1 0 12 0.0000 4 135 2145 3600 8025 kernel network device driver\001
+-6
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+        2250 7200 4200 7800
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+        7200 7200 5100 7800
+-6
+6 9600 3000 10275 3300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        9600 3000 10275 3000 10275 3300 9600 3300 9600 3000
+4 0 0 50 -1 0 12 0.0000 4 135 315 9750 3225 TLS\001
+-6
+6 8100 4425 10425 7350
+6 8175 4725 9225 5025
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        8175 4725 9225 4725 9225 5025 8175 5025 8175 4725
+4 0 0 50 -1 0 12 0.0000 4 135 735 8250 4950 EAP-TLS\001
+-6
+6 9300 4725 10350 5025
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        9300 4725 10350 4725 10350 5025 9300 5025 9300 4725
+4 0 0 50 -1 0 12 0.0000 4 135 810 9375 4950 EAP-MD5\001
+-6
+6 8175 5100 9225 5400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        8175 5100 9225 5100 9225 5400 8175 5400 8175 5100
+4 0 0 50 -1 0 12 0.0000 4 135 885 8250 5325 EAP-PEAP\001
+-6
+6 9300 5100 10350 5400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        9300 5100 10350 5100 10350 5400 9300 5400 9300 5100
+4 0 0 50 -1 0 12 0.0000 4 135 840 9375 5325 EAP-TTLS\001
+-6
+6 8175 5475 9225 5775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        8175 5475 9225 5475 9225 5775 8175 5775 8175 5475
+4 0 0 50 -1 0 12 0.0000 4 135 780 8250 5700 EAP-GTC\001
+-6
+6 9300 5475 10350 5775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        9300 5475 10350 5475 10350 5775 9300 5775 9300 5475
+4 0 0 50 -1 0 12 0.0000 4 135 765 9375 5700 EAP-OTP\001
+-6
+6 8175 5850 9225 6150
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        8175 5850 9225 5850 9225 6150 8175 6150 8175 5850
+4 0 0 50 -1 0 12 0.0000 4 135 750 8250 6075 EAP-SIM\001
+-6
+6 9300 6225 10350 6525
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        9300 6225 10350 6225 10350 6525 9300 6525 9300 6225
+4 0 0 50 -1 0 12 0.0000 4 135 465 9375 6450 LEAP\001
+-6
+6 8175 6225 9225 6525
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        8175 6225 9225 6225 9225 6525 8175 6525 8175 6225
+4 0 0 50 -1 0 12 0.0000 4 135 765 8250 6450 EAP-PSK\001
+-6
+6 9300 5850 10350 6150
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        9300 5850 10350 5850 10350 6150 9300 6150 9300 5850
+4 0 0 50 -1 0 12 0.0000 4 135 825 9375 6075 EAP-AKA\001
+-6
+6 8175 6975 9675 7275
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        8175 6975 9675 6975 9675 7275 8175 7275 8175 6975
+4 0 0 50 -1 0 12 0.0000 4 135 1365 8250 7200 EAP-MSCHAPv2\001
+-6
+6 9300 6600 10350 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        9300 6600 10350 6600 10350 6900 9300 6900 9300 6600
+4 0 0 50 -1 0 12 0.0000 4 135 870 9375 6825 EAP-FAST\001
+-6
+6 8175 6600 9225 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        8175 6600 9225 6600 9225 6900 8175 6900 8175 6600
+4 0 0 50 -1 0 12 0.0000 4 135 795 8250 6825 EAP-PAX\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        8100 7350 10425 7350 10425 4425 8100 4425 8100 7350
+4 0 0 50 -1 0 12 0.0000 4 135 1050 8700 4650 EAP methods\001
+-6
+6 2775 5025 4050 5325
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        2775 5025 4050 5025 4050 5325 2775 5325 2775 5025
+4 0 0 50 -1 0 12 0.0000 4 135 990 2925 5250 driver events\001
+-6
+6 2775 3150 4050 3450
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        2775 3150 4050 3150 4050 3450 2775 3450 2775 3150
+4 0 0 50 -1 0 12 0.0000 4 180 990 2925 3375 configuration\001
+-6
+2 1 1 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2
+        1275 4200 1875 4200
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+        4500 2550 3900 1500
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+        4800 2550 5400 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        2925 4200 4350 4200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        5025 3900 6000 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        5025 4200 6000 4200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        4650 6000 4650 4425
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        6600 4425 6600 4950
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        6600 3225 6600 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        7200 5250 8100 5250
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        9075 4425 9075 3300
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        7200 3000 8700 3150
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        4650 3900 4650 2850
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        7200 4125 8700 3300
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        6000 4350 5025 6000
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        6000 3150 4875 6000
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+        1500 2100 10800 2100 10800 7500 1500 7500 1500 2100
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        9900 4425 9900 3300
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 1
+        4350 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        4350 3900 4050 3450
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+        4350 4425 4050 5025
+4 0 0 50 -1 0 12 0.0000 4 135 915 375 3975 EAPOL and\001
+4 0 0 50 -1 0 12 0.0000 4 180 630 375 4200 pre-auth\001
+4 0 0 50 -1 0 12 0.0000 4 180 810 375 4425 ethertypes\001
+4 0 0 50 -1 0 12 0.0000 4 135 1050 375 4650 from/to kernel\001
+4 0 0 50 -1 0 12 0.0000 4 135 1920 3675 1875 frontend control interface\001
+4 0 0 50 -1 2 14 0.0000 4 210 1440 1637 2371 wpa_supplicant\001
diff --git a/eap_example/Makefile b/eap_example/Makefile
new file mode 100644 (file)
index 0000000..0cc19bd
--- /dev/null
@@ -0,0 +1,152 @@
+ALL=eap_example
+
+all: $(ALL)
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef RANLIB
+RANLIB=ranlib
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+
+CFLAGS += -I.
+CFLAGS += -I../src
+CFLAGS += -I../src/utils
+
+
+OBJS_both += ../src/utils/libutils.a
+OBJS_both += ../src/crypto/libcrypto.a
+OBJS_both += ../src/tls/libtls.a
+
+OBJS_both += ../src/eap_common/eap_peap_common.o
+OBJS_both += ../src/eap_common/eap_psk_common.o
+OBJS_both += ../src/eap_common/eap_pax_common.o
+OBJS_both += ../src/eap_common/eap_sake_common.o
+OBJS_both += ../src/eap_common/eap_gpsk_common.o
+OBJS_both += ../src/eap_common/chap.o
+
+OBJS_peer += ../src/eap_peer/eap_tls.o
+OBJS_peer += ../src/eap_peer/eap_peap.o
+OBJS_peer += ../src/eap_peer/eap_ttls.o
+OBJS_peer += ../src/eap_peer/eap_md5.o
+OBJS_peer += ../src/eap_peer/eap_mschapv2.o
+OBJS_peer += ../src/eap_peer/mschapv2.o
+OBJS_peer += ../src/eap_peer/eap_otp.o
+OBJS_peer += ../src/eap_peer/eap_gtc.o
+OBJS_peer += ../src/eap_peer/eap_leap.o
+OBJS_peer += ../src/eap_peer/eap_psk.o
+OBJS_peer += ../src/eap_peer/eap_pax.o
+OBJS_peer += ../src/eap_peer/eap_sake.o
+OBJS_peer += ../src/eap_peer/eap_gpsk.o
+OBJS_peer += ../src/eap_peer/eap.o
+OBJS_peer += ../src/eap_common/eap_common.o
+OBJS_peer += ../src/eap_peer/eap_methods.o
+OBJS_peer += ../src/eap_peer/eap_tls_common.o
+
+CFLAGS += -DEAP_TLS
+CFLAGS += -DEAP_PEAP
+CFLAGS += -DEAP_TTLS
+CFLAGS += -DEAP_MD5
+CFLAGS += -DEAP_MSCHAPv2
+CFLAGS += -DEAP_GTC
+CFLAGS += -DEAP_OTP
+CFLAGS += -DEAP_LEAP
+CFLAGS += -DEAP_PSK
+CFLAGS += -DEAP_PAX
+CFLAGS += -DEAP_SAKE
+CFLAGS += -DEAP_GPSK -DEAP_GPSK_SHA256
+
+CFLAGS += -DEAP_SERVER_IDENTITY
+CFLAGS += -DEAP_SERVER_TLS
+CFLAGS += -DEAP_SERVER_PEAP
+CFLAGS += -DEAP_SERVER_TTLS
+CFLAGS += -DEAP_SERVER_MD5
+CFLAGS += -DEAP_SERVER_MSCHAPV2
+CFLAGS += -DEAP_SERVER_GTC
+CFLAGS += -DEAP_SERVER_PSK
+CFLAGS += -DEAP_SERVER_PAX
+CFLAGS += -DEAP_SERVER_SAKE
+CFLAGS += -DEAP_SERVER_GPSK -DEAP_SERVER_GPSK_SHA256
+
+CFLAGS += -DIEEE8021X_EAPOL
+
+
+# Optional components to add EAP server support
+OBJS_server += ../src/eap_server/eap_server_tls.o
+OBJS_server += ../src/eap_server/eap_server_peap.o
+OBJS_server += ../src/eap_server/eap_server_ttls.o
+OBJS_server += ../src/eap_server/eap_server_md5.o
+OBJS_server += ../src/eap_server/eap_server_mschapv2.o
+OBJS_server += ../src/eap_server/eap_server_gtc.o
+OBJS_server += ../src/eap_server/eap_server_psk.o
+OBJS_server += ../src/eap_server/eap_server_pax.o
+OBJS_server += ../src/eap_server/eap_server_sake.o
+OBJS_server += ../src/eap_server/eap_server_gpsk.o
+OBJS_server += ../src/eap_server/eap_server.o
+OBJS_server += ../src/eap_server/eap_server_identity.o
+OBJS_server += ../src/eap_server/eap_server_methods.o
+OBJS_server += ../src/eap_server/eap_server_tls_common.o
+CFLAGS += -DEAP_SERVER
+
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+Q=@
+E=echo
+ifeq ($(V), 1)
+Q=
+E=true
+endif
+
+%.o: %.c
+       $(Q)$(CC) -c -o $@ $(CFLAGS) $<
+       @$(E) "  CC " $<
+
+
+OBJS_lib=$(OBJS_both) $(OBJS_peer) $(OBJS_server)
+
+OBJS_ex = eap_example.o eap_example_peer.o eap_example_server.o
+
+
+../src/utils/libutils.a:
+       $(MAKE) -C ../src/utils
+
+../src/crypto/libcrypto.a:
+       $(MAKE) -C ../src/crypto
+
+../src/tls/libtls.a:
+       $(MAKE) -C ../src/tls
+
+
+ifneq ($(CONFIG_SOLIB), yes)
+LIBEAP = libeap.a
+libeap.a: $(OBJS_lib)
+       $(AR) crT libeap.a $(OBJS_lib)
+       $(RANLIB) libeap.a
+
+else
+CFLAGS  += -fPIC -DPIC
+LDFLAGS += -shared
+
+LIBEAP  = libeap.so
+libeap.so: $(OBJS_lib)
+       $(LDO) $(LDFLAGS) $(OBJS_lib) -o $(LIBEAP)
+
+endif
+
+eap_example: $(OBJS_ex) $(LIBEAP)
+       $(LDO) $(LDFLAGS) -o eap_example $(OBJS_ex) -L. -leap $(LIBS)
+
+clean:
+       $(MAKE) -C ../src clean
+       rm -f core *~ *.o *.d libeap.a libeap.so $(ALL)
+
+-include $(OBJS:%.o=%.d)
diff --git a/eap_example/README b/eap_example/README
new file mode 100644 (file)
index 0000000..b897ab5
--- /dev/null
@@ -0,0 +1,46 @@
+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.
+
+
+The interfaces of the EAP server/peer implementation are based on RFC
+4137 (EAP State Machines). This RFC is coordinated with the state
+machines defined in IEEE 802.1X-2004. hostapd and wpa_supplicant
+include implementation of the IEEE 802.1X EAPOL state machines and the
+interface between them and EAP. However, the EAP implementation can be
+used with other protocols, too, by providing a compatible interface
+which maps the EAPOL<->EAP variables to another protocol.
+
+This directory contains an example showing how EAP peer and server
+code from wpa_supplicant and hostapd can be used as a library. The
+example program initializes both an EAP server and an EAP peer
+entities and then runs through an EAP-PEAP/MSCHAPv2 authentication.
+
+eap_example_peer.c shows the initialization and glue code needed to
+control the EAP peer implementation. eap_example_server.c does the
+same for EAP server. eap_example.c is an example that ties in both the
+EAP server and client parts to allow an EAP authentication to be
+shown.
+
+In this example, the EAP messages are passed between the server and
+the peer are passed by direct function calls within the same process.
+In practice, server and peer functionalities would likely reside in
+separate devices and the EAP messages would be transmitted between the
+devices based on an external protocol. For example, in IEEE 802.11
+uses IEEE 802.1X EAPOL state machines to control the transmission of
+EAP messages and WiMax supports optional PMK EAP authentication
+mechanism that transmits EAP messages as defined in IEEE 802.16e.
+
+
+The EAP library links in number of helper functions from src/utils and
+src/crypto directories. Most of these are suitable as-is, but it may
+be desirable to replace the debug output code in src/utils/wpa_debug.c
+by dropping this file from the library and re-implementing the
+functions there in a way that better fits in with the main
+application.
diff --git a/eap_example/ca.pem b/eap_example/ca.pem
new file mode 100644 (file)
index 0000000..bfae1cc
--- /dev/null
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDBzCCAnCgAwIBAgIJAIb4NS4TdLXUMA0GCSqGSIb3DQEBBQUAMGExCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMQ4wDAYDVQQKEwV3MS5maTEQMA4G
+A1UEAxMHVGVzdCBDQTEbMBkGCSqGSIb3DQEJARYMdGVzdGNhQHcxLmZpMB4XDTA3
+MTIwOTAzMTQzN1oXDTE3MTIwNjAzMTQzN1owYTELMAkGA1UEBhMCVVMxEzARBgNV
+BAgTCkNhbGlmb3JuaWExDjAMBgNVBAoTBXcxLmZpMRAwDgYDVQQDEwdUZXN0IENB
+MRswGQYJKoZIhvcNAQkBFgx0ZXN0Y2FAdzEuZmkwgZ8wDQYJKoZIhvcNAQEBBQAD
+gY0AMIGJAoGBAO6GoecRclnILh9FTvqnY/yUZmeJDgC+3/PQiicpMDhAzCkWAmi+
+a1LSnqakNN/GdCy3q053TFLFEzhEHkhhRwY/zzj2vZIcFZESoUhr67CzCpcPmTGa
+AfOzsGPjaH6xYcaOR4RZMfXd/EKfAauHxj3LuCusLL5hK/FwxWhQJNJrAgMBAAGj
+gcYwgcMwHQYDVR0OBBYEFKhJuSLJ6JhcB/dRgB8j0h9mOlpKMIGTBgNVHSMEgYsw
+gYiAFKhJuSLJ6JhcB/dRgB8j0h9mOlpKoWWkYzBhMQswCQYDVQQGEwJVUzETMBEG
+A1UECBMKQ2FsaWZvcm5pYTEOMAwGA1UEChMFdzEuZmkxEDAOBgNVBAMTB1Rlc3Qg
+Q0ExGzAZBgkqhkiG9w0BCQEWDHRlc3RjYUB3MS5maYIJAIb4NS4TdLXUMAwGA1Ud
+EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAuU+5Uerq+n8WgiIsiANT3wUoGe2Y
+cnoQi2nVjUHrivgMDufH0tgh1AVfc3wVNNREdGC136qr1KBNqalQx2rKZ76xeNqW
+sQa2LIC2wE7Q7LJsltUcUjPyZHGUhBqWjKsCvlonfNB6JHkEayTEvVvyupgzTsxW
+QuuRdZ0sNv/S8VI=
+-----END CERTIFICATE-----
diff --git a/eap_example/eap_example.c b/eap_example/eap_example.c
new file mode 100644 (file)
index 0000000..b8917c8
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Example application showing how EAP peer and server code from
+ * wpa_supplicant/hostapd can be used as a library. This example program
+ * initializes both an EAP server and an EAP peer entities and then runs
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+
+
+int eap_example_peer_init(void);
+void eap_example_peer_deinit(void);
+int eap_example_peer_step(void);
+
+int eap_example_server_init(void);
+void eap_example_server_deinit(void);
+int eap_example_server_step(void);
+
+
+extern int wpa_debug_level;
+
+int main(int argc, char *argv[])
+{
+       int res_s, res_p;
+
+       wpa_debug_level = 0;
+
+       if (eap_example_peer_init() < 0 ||
+           eap_example_server_init() < 0)
+               return -1;
+
+       do {
+               printf("---[ server ]--------------------------------\n");
+               res_s = eap_example_server_step();
+               printf("---[ peer ]----------------------------------\n");
+               res_p = eap_example_peer_step();
+       } while (res_s || res_p);
+
+       eap_example_peer_deinit();
+       eap_example_server_deinit();
+
+       return 0;
+}
diff --git a/eap_example/eap_example_peer.c b/eap_example/eap_example_peer.c
new file mode 100644 (file)
index 0000000..0b7d417
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * Example application showing how EAP peer code from wpa_supplicant can be
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_peer/eap.h"
+#include "eap_peer/eap_config.h"
+#include "wpabuf.h"
+
+void eap_example_server_rx(const u8 *data, size_t data_len);
+
+
+struct eap_peer_ctx {
+       Boolean eapSuccess;
+       Boolean eapRestart;
+       Boolean eapFail;
+       Boolean eapResp;
+       Boolean eapNoResp;
+       Boolean eapReq;
+       Boolean portEnabled;
+       Boolean altAccept; /* for EAP */
+       Boolean altReject; /* for EAP */
+
+       struct wpabuf *eapReqData; /* for EAP */
+
+       unsigned int idleWhile; /* for EAP state machine */
+
+       struct eap_peer_config eap_config;
+       struct eap_sm *eap;
+};
+
+
+static struct eap_peer_ctx eap_ctx;
+
+
+static struct eap_peer_config * peer_get_config(void *ctx)
+{
+       struct eap_peer_ctx *peer = ctx;
+       return &peer->eap_config;
+}
+
+
+static Boolean peer_get_bool(void *ctx, enum eapol_bool_var variable)
+{
+       struct eap_peer_ctx *peer = ctx;
+       if (peer == NULL)
+               return FALSE;
+       switch (variable) {
+       case EAPOL_eapSuccess:
+               return peer->eapSuccess;
+       case EAPOL_eapRestart:
+               return peer->eapRestart;
+       case EAPOL_eapFail:
+               return peer->eapFail;
+       case EAPOL_eapResp:
+               return peer->eapResp;
+       case EAPOL_eapNoResp:
+               return peer->eapNoResp;
+       case EAPOL_eapReq:
+               return peer->eapReq;
+       case EAPOL_portEnabled:
+               return peer->portEnabled;
+       case EAPOL_altAccept:
+               return peer->altAccept;
+       case EAPOL_altReject:
+               return peer->altReject;
+       }
+       return FALSE;
+}
+
+
+static void peer_set_bool(void *ctx, enum eapol_bool_var variable,
+                         Boolean value)
+{
+       struct eap_peer_ctx *peer = ctx;
+       if (peer == NULL)
+               return;
+       switch (variable) {
+       case EAPOL_eapSuccess:
+               peer->eapSuccess = value;
+               break;
+       case EAPOL_eapRestart:
+               peer->eapRestart = value;
+               break;
+       case EAPOL_eapFail:
+               peer->eapFail = value;
+               break;
+       case EAPOL_eapResp:
+               peer->eapResp = value;
+               break;
+       case EAPOL_eapNoResp:
+               peer->eapNoResp = value;
+               break;
+       case EAPOL_eapReq:
+               peer->eapReq = value;
+               break;
+       case EAPOL_portEnabled:
+               peer->portEnabled = value;
+               break;
+       case EAPOL_altAccept:
+               peer->altAccept = value;
+               break;
+       case EAPOL_altReject:
+               peer->altReject = value;
+               break;
+       }
+}
+
+
+static unsigned int peer_get_int(void *ctx, enum eapol_int_var variable)
+{
+       struct eap_peer_ctx *peer = ctx;
+       if (peer == NULL)
+               return 0;
+       switch (variable) {
+       case EAPOL_idleWhile:
+               return peer->idleWhile;
+       }
+       return 0;
+}
+
+
+static void peer_set_int(void *ctx, enum eapol_int_var variable,
+                        unsigned int value)
+{
+       struct eap_peer_ctx *peer = ctx;
+       if (peer == NULL)
+               return;
+       switch (variable) {
+       case EAPOL_idleWhile:
+               peer->idleWhile = value;
+               break;
+       }
+}
+
+
+static struct wpabuf * peer_get_eapReqData(void *ctx)
+{
+       struct eap_peer_ctx *peer = ctx;
+       if (peer == NULL || peer->eapReqData == NULL)
+               return NULL;
+
+       return peer->eapReqData;
+}
+
+
+static void peer_set_config_blob(void *ctx, struct wpa_config_blob *blob)
+{
+       printf("TODO: %s\n", __func__);
+}
+
+
+static const struct wpa_config_blob *
+peer_get_config_blob(void *ctx, const char *name)
+{
+       printf("TODO: %s\n", __func__);
+       return NULL;
+}
+
+
+static void peer_notify_pending(void *ctx)
+{
+       printf("TODO: %s\n", __func__);
+}
+
+
+static int eap_peer_register_methods(void)
+{
+       int ret = 0;
+
+#ifdef EAP_MD5
+       if (ret == 0)
+               ret = eap_peer_md5_register();
+#endif /* EAP_MD5 */
+
+#ifdef EAP_TLS
+       if (ret == 0)
+               ret = eap_peer_tls_register();
+#endif /* EAP_TLS */
+
+#ifdef EAP_MSCHAPv2
+       if (ret == 0)
+               ret = eap_peer_mschapv2_register();
+#endif /* EAP_MSCHAPv2 */
+
+#ifdef EAP_PEAP
+       if (ret == 0)
+               ret = eap_peer_peap_register();
+#endif /* EAP_PEAP */
+
+#ifdef EAP_TTLS
+       if (ret == 0)
+               ret = eap_peer_ttls_register();
+#endif /* EAP_TTLS */
+
+#ifdef EAP_GTC
+       if (ret == 0)
+               ret = eap_peer_gtc_register();
+#endif /* EAP_GTC */
+
+#ifdef EAP_OTP
+       if (ret == 0)
+               ret = eap_peer_otp_register();
+#endif /* EAP_OTP */
+
+#ifdef EAP_SIM
+       if (ret == 0)
+               ret = eap_peer_sim_register();
+#endif /* EAP_SIM */
+
+#ifdef EAP_LEAP
+       if (ret == 0)
+               ret = eap_peer_leap_register();
+#endif /* EAP_LEAP */
+
+#ifdef EAP_PSK
+       if (ret == 0)
+               ret = eap_peer_psk_register();
+#endif /* EAP_PSK */
+
+#ifdef EAP_AKA
+       if (ret == 0)
+               ret = eap_peer_aka_register();
+#endif /* EAP_AKA */
+
+#ifdef EAP_AKA_PRIME
+       if (ret == 0)
+               ret = eap_peer_aka_prime_register();
+#endif /* EAP_AKA_PRIME */
+
+#ifdef EAP_FAST
+       if (ret == 0)
+               ret = eap_peer_fast_register();
+#endif /* EAP_FAST */
+
+#ifdef EAP_PAX
+       if (ret == 0)
+               ret = eap_peer_pax_register();
+#endif /* EAP_PAX */
+
+#ifdef EAP_SAKE
+       if (ret == 0)
+               ret = eap_peer_sake_register();
+#endif /* EAP_SAKE */
+
+#ifdef EAP_GPSK
+       if (ret == 0)
+               ret = eap_peer_gpsk_register();
+#endif /* EAP_GPSK */
+
+#ifdef EAP_WSC
+       if (ret == 0)
+               ret = eap_peer_wsc_register();
+#endif /* EAP_WSC */
+
+#ifdef EAP_IKEV2
+       if (ret == 0)
+               ret = eap_peer_ikev2_register();
+#endif /* EAP_IKEV2 */
+
+#ifdef EAP_VENDOR_TEST
+       if (ret == 0)
+               ret = eap_peer_vendor_test_register();
+#endif /* EAP_VENDOR_TEST */
+
+#ifdef EAP_TNC
+       if (ret == 0)
+               ret = eap_peer_tnc_register();
+#endif /* EAP_TNC */
+
+       return ret;
+}
+
+
+static struct eapol_callbacks eap_cb;
+static struct eap_config eap_conf;
+
+int eap_example_peer_init(void)
+{
+       if (eap_peer_register_methods() < 0)
+               return -1;
+
+       os_memset(&eap_ctx, 0, sizeof(eap_ctx));
+
+       eap_ctx.eap_config.identity = (u8 *) os_strdup("user");
+       eap_ctx.eap_config.identity_len = 4;
+       eap_ctx.eap_config.password = (u8 *) os_strdup("password");
+       eap_ctx.eap_config.password_len = 8;
+       eap_ctx.eap_config.ca_cert = (u8 *) os_strdup("ca.pem");
+       eap_ctx.eap_config.fragment_size = 1398;
+
+       os_memset(&eap_cb, 0, sizeof(eap_cb));
+       eap_cb.get_config = peer_get_config;
+       eap_cb.get_bool = peer_get_bool;
+       eap_cb.set_bool = peer_set_bool;
+       eap_cb.get_int = peer_get_int;
+       eap_cb.set_int = peer_set_int;
+       eap_cb.get_eapReqData = peer_get_eapReqData;
+       eap_cb.set_config_blob = peer_set_config_blob;
+       eap_cb.get_config_blob = peer_get_config_blob;
+       eap_cb.notify_pending = peer_notify_pending;
+
+       os_memset(&eap_conf, 0, sizeof(eap_conf));
+       eap_ctx.eap = eap_peer_sm_init(&eap_ctx, &eap_cb, &eap_ctx, &eap_conf);
+       if (eap_ctx.eap == NULL)
+               return -1;
+
+       /* Enable "port" to allow authentication */
+       eap_ctx.portEnabled = TRUE;
+
+       return 0;
+}
+
+
+void eap_example_peer_deinit(void)
+{
+       eap_peer_sm_deinit(eap_ctx.eap);
+       eap_peer_unregister_methods();
+       wpabuf_free(eap_ctx.eapReqData);
+       os_free(eap_ctx.eap_config.identity);
+       os_free(eap_ctx.eap_config.password);
+       os_free(eap_ctx.eap_config.ca_cert);
+}
+
+
+int eap_example_peer_step(void)
+{
+       int res;
+       res = eap_peer_sm_step(eap_ctx.eap);
+
+       if (eap_ctx.eapResp) {
+               struct wpabuf *resp;
+               printf("==> Response\n");
+               eap_ctx.eapResp = FALSE;
+               resp = eap_get_eapRespData(eap_ctx.eap);
+               if (resp) {
+                       /* Send EAP response to the server */
+                       eap_example_server_rx(wpabuf_head(resp),
+                                             wpabuf_len(resp));
+                       wpabuf_free(resp);
+               }
+       }
+
+       if (eap_ctx.eapSuccess) {
+               res = 0;
+               if (eap_key_available(eap_ctx.eap)) {
+                       const u8 *key;
+                       size_t key_len;
+                       key = eap_get_eapKeyData(eap_ctx.eap, &key_len);
+                       wpa_hexdump(MSG_DEBUG, "EAP keying material",
+                                   key, key_len);
+               }
+       }
+
+       return res;
+}
+
+
+void eap_example_peer_rx(const u8 *data, size_t data_len)
+{
+       /* Make received EAP message available to the EAP library */
+       eap_ctx.eapReq = TRUE;
+       wpabuf_free(eap_ctx.eapReqData);
+       eap_ctx.eapReqData = wpabuf_alloc_copy(data, data_len);
+}
diff --git a/eap_example/eap_example_server.c b/eap_example/eap_example_server.c
new file mode 100644 (file)
index 0000000..03deb67
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * Example application showing how EAP server code from hostapd can be 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/tls.h"
+#include "eap_server/eap.h"
+#include "wpabuf.h"
+
+void eap_example_peer_rx(const u8 *data, size_t data_len);
+
+
+struct eap_server_ctx {
+       struct eap_eapol_interface *eap_if;
+       struct eap_sm *eap;
+       void *tls_ctx;
+};
+
+static struct eap_server_ctx eap_ctx;
+
+
+static int server_get_eap_user(void *ctx, const u8 *identity,
+                              size_t identity_len, int phase2,
+                              struct eap_user *user)
+{
+       os_memset(user, 0, sizeof(*user));
+
+       if (!phase2) {
+               /* Only allow EAP-PEAP as the Phase 1 method */
+               user->methods[0].vendor = EAP_VENDOR_IETF;
+               user->methods[0].method = EAP_TYPE_PEAP;
+               return 0;
+       }
+
+       if (identity_len != 4 || identity == NULL ||
+           os_memcmp(identity, "user", 4) != 0) {
+               printf("Unknown user\n");
+               return -1;
+       }
+
+       /* Only allow EAP-MSCHAPv2 as the Phase 2 method */
+       user->methods[0].vendor = EAP_VENDOR_IETF;
+       user->methods[0].method = EAP_TYPE_MSCHAPV2;
+       user->password = (u8 *) os_strdup("password");
+       user->password_len = 8;
+
+       return 0;
+}
+
+
+static const char * server_get_eap_req_id_text(void *ctx, size_t *len)
+{
+       *len = 0;
+       return NULL;
+}
+
+
+static struct eapol_callbacks eap_cb;
+static struct eap_config eap_conf;
+
+static int eap_example_server_init_tls(void)
+{
+       struct tls_config tconf;
+       struct tls_connection_params tparams;
+
+       os_memset(&tconf, 0, sizeof(tconf));
+       eap_ctx.tls_ctx = tls_init(&tconf);
+       if (eap_ctx.tls_ctx == NULL)
+               return -1;
+
+       os_memset(&tparams, 0, sizeof(tparams));
+       tparams.ca_cert = "ca.pem";
+       tparams.client_cert = "server.pem";
+       /* tparams.private_key = "server.key"; */
+       tparams.private_key = "server-key.pem";
+       /* tparams.private_key_passwd = "whatever"; */
+
+       if (tls_global_set_params(eap_ctx.tls_ctx, &tparams)) {
+               printf("Failed to set TLS parameters\n");
+               return -1;
+       }
+
+       if (tls_global_set_verify(eap_ctx.tls_ctx, 0)) {
+               printf("Failed to set check_crl\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+
+static int eap_server_register_methods(void)
+{
+       int ret = 0;
+
+#ifdef EAP_SERVER_IDENTITY
+       if (ret == 0)
+               ret = eap_server_identity_register();
+#endif /* EAP_SERVER_IDENTITY */
+
+#ifdef EAP_SERVER_MD5
+       if (ret == 0)
+               ret = eap_server_md5_register();
+#endif /* EAP_SERVER_MD5 */
+
+#ifdef EAP_SERVER_TLS
+       if (ret == 0)
+               ret = eap_server_tls_register();
+#endif /* EAP_SERVER_TLS */
+
+#ifdef EAP_SERVER_MSCHAPV2
+       if (ret == 0)
+               ret = eap_server_mschapv2_register();
+#endif /* EAP_SERVER_MSCHAPV2 */
+
+#ifdef EAP_SERVER_PEAP
+       if (ret == 0)
+               ret = eap_server_peap_register();
+#endif /* EAP_SERVER_PEAP */
+
+#ifdef EAP_SERVER_TLV
+       if (ret == 0)
+               ret = eap_server_tlv_register();
+#endif /* EAP_SERVER_TLV */
+
+#ifdef EAP_SERVER_GTC
+       if (ret == 0)
+               ret = eap_server_gtc_register();
+#endif /* EAP_SERVER_GTC */
+
+#ifdef EAP_SERVER_TTLS
+       if (ret == 0)
+               ret = eap_server_ttls_register();
+#endif /* EAP_SERVER_TTLS */
+
+#ifdef EAP_SERVER_SIM
+       if (ret == 0)
+               ret = eap_server_sim_register();
+#endif /* EAP_SERVER_SIM */
+
+#ifdef EAP_SERVER_AKA
+       if (ret == 0)
+               ret = eap_server_aka_register();
+#endif /* EAP_SERVER_AKA */
+
+#ifdef EAP_SERVER_AKA_PRIME
+       if (ret == 0)
+               ret = eap_server_aka_prime_register();
+#endif /* EAP_SERVER_AKA_PRIME */
+
+#ifdef EAP_SERVER_PAX
+       if (ret == 0)
+               ret = eap_server_pax_register();
+#endif /* EAP_SERVER_PAX */
+
+#ifdef EAP_SERVER_PSK
+       if (ret == 0)
+               ret = eap_server_psk_register();
+#endif /* EAP_SERVER_PSK */
+
+#ifdef EAP_SERVER_SAKE
+       if (ret == 0)
+               ret = eap_server_sake_register();
+#endif /* EAP_SERVER_SAKE */
+
+#ifdef EAP_SERVER_GPSK
+       if (ret == 0)
+               ret = eap_server_gpsk_register();
+#endif /* EAP_SERVER_GPSK */
+
+#ifdef EAP_SERVER_VENDOR_TEST
+       if (ret == 0)
+               ret = eap_server_vendor_test_register();
+#endif /* EAP_SERVER_VENDOR_TEST */
+
+#ifdef EAP_SERVER_FAST
+       if (ret == 0)
+               ret = eap_server_fast_register();
+#endif /* EAP_SERVER_FAST */
+
+#ifdef EAP_SERVER_WSC
+       if (ret == 0)
+               ret = eap_server_wsc_register();
+#endif /* EAP_SERVER_WSC */
+
+#ifdef EAP_SERVER_IKEV2
+       if (ret == 0)
+               ret = eap_server_ikev2_register();
+#endif /* EAP_SERVER_IKEV2 */
+
+#ifdef EAP_SERVER_TNC
+       if (ret == 0)
+               ret = eap_server_tnc_register();
+#endif /* EAP_SERVER_TNC */
+
+       return ret;
+}
+
+
+int eap_example_server_init(void)
+{
+       if (eap_server_register_methods() < 0)
+               return -1;
+
+       os_memset(&eap_ctx, 0, sizeof(eap_ctx));
+
+       if (eap_example_server_init_tls() < 0)
+               return -1;
+
+       os_memset(&eap_cb, 0, sizeof(eap_cb));
+       eap_cb.get_eap_user = server_get_eap_user;
+       eap_cb.get_eap_req_id_text = server_get_eap_req_id_text;
+
+       os_memset(&eap_conf, 0, sizeof(eap_conf));
+       eap_conf.eap_server = 1;
+       eap_conf.ssl_ctx = eap_ctx.tls_ctx;
+
+       eap_ctx.eap = eap_server_sm_init(&eap_ctx, &eap_cb, &eap_conf);
+       if (eap_ctx.eap == NULL)
+               return -1;
+
+       eap_ctx.eap_if = eap_get_interface(eap_ctx.eap);
+
+       /* Enable "port" and request EAP to start authentication. */
+       eap_ctx.eap_if->portEnabled = TRUE;
+       eap_ctx.eap_if->eapRestart = TRUE;
+
+       return 0;
+}
+
+
+void eap_example_server_deinit(void)
+{
+       eap_server_sm_deinit(eap_ctx.eap);
+       eap_server_unregister_methods();
+       tls_deinit(eap_ctx.tls_ctx);
+}
+
+
+int eap_example_server_step(void)
+{
+       int res, process = 0;
+
+       res = eap_server_sm_step(eap_ctx.eap);
+
+       if (eap_ctx.eap_if->eapReq) {
+               printf("==> Request\n");
+               process = 1;
+               eap_ctx.eap_if->eapReq = 0;
+       }
+
+       if (eap_ctx.eap_if->eapSuccess) {
+               printf("==> Success\n");
+               process = 1;
+               res = 0;
+               eap_ctx.eap_if->eapSuccess = 0;
+
+               if (eap_ctx.eap_if->eapKeyAvailable) {
+                       wpa_hexdump(MSG_DEBUG, "EAP keying material",
+                                   eap_ctx.eap_if->eapKeyData,
+                                   eap_ctx.eap_if->eapKeyDataLen);
+               }
+       }
+
+       if (eap_ctx.eap_if->eapFail) {
+               printf("==> Fail\n");
+               process = 1;
+               eap_ctx.eap_if->eapFail = 0;
+       }
+
+       if (process && eap_ctx.eap_if->eapReqData) {
+               /* Send EAP response to the server */
+               eap_example_peer_rx(wpabuf_head(eap_ctx.eap_if->eapReqData),
+                                   wpabuf_len(eap_ctx.eap_if->eapReqData));
+       }
+
+       return res;
+}
+
+
+void eap_example_server_rx(const u8 *data, size_t data_len)
+{
+       /* Make received EAP message available to the EAP library */
+       wpabuf_free(eap_ctx.eap_if->eapRespData);
+       eap_ctx.eap_if->eapRespData = wpabuf_alloc_copy(data, data_len);
+       if (eap_ctx.eap_if->eapRespData)
+               eap_ctx.eap_if->eapResp = TRUE;
+}
diff --git a/eap_example/server-key.pem b/eap_example/server-key.pem
new file mode 100644 (file)
index 0000000..d98c4dd
--- /dev/null
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQDToYuDPmjEWu+/Aj0RVWTSb07sX6dAkPnrTaUjZAG5AhjRqJWz
+zD50kFmVKi+R7GgS5tlGzLUtokdwjuSUAmz8tMXwIwmVeS0HluFDVSi94XbVRczE
++nyoDigg1RGyy1mc3t5RG84bvNatq98OceJag4ngh8L8I4k1qTLRMlyBJwIDAQAB
+AoGAP+v0asDn/h8FeSkg7uJfIJyUNxsxNnRTuHnsXkMvrgTvICyOgw828hhDpqVm
+VuoUCVmG2Tatpsn0UBApBHezGRh0u1syWoGM8fiDvZmoYmhFe5FxKnftg3KNXhDf
+Agk4OxwNNPBXpQFQP+GNxh6Qs7FEkYHLRh/J7vC0+wp3UWECQQDzcTQZXqYPow5M
+uinL819HKfh1n2257w1HGvw8cMCiYbKRyR74Q18TJcxuEyEwnPrg5ZGpMPDKiIOU
+SlgAMLBXAkEA3oxBpRue1Kqb2+Fq6lhZ7PQiZC5F69upIb/wxbk8ByImEl1pUKFW
+rV+YoKujbnj77PmMq1+R0dFkT1ai3zDzsQJBAMa3CUgMMpFhEDMhYyzQJF36rI2W
+7gJwV+5K4MqVXyktho3qFhWhKOKAYDcZ9mWwPjmGKzhocqVgecd6SAsfs1ECQA7r
+xHL3eRy1G6IQaQSxS8YxUCT7XUDFB3/1yITZOIcZ6QeOL8NyLceOA0OyflCn1+w5
+hw7uZ25z5Y/UNTNVquECQEgto3zPneEW06qkEnRz9EbLtWR3nRBS/QGrjOFNUuln
+pNhVUH4RB17Kk35xveUTz4U/Iw/WRfGNjFLHrtR/5xk=
+-----END RSA PRIVATE KEY-----
diff --git a/eap_example/server.key b/eap_example/server.key
new file mode 100644 (file)
index 0000000..4f32591
Binary files /dev/null and b/eap_example/server.key differ
diff --git a/eap_example/server.pem b/eap_example/server.pem
new file mode 100644 (file)
index 0000000..02f6e7b
--- /dev/null
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0zCCAjygAwIBAgIJAIb4NS4TdLXVMA0GCSqGSIb3DQEBBQUAMGExCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMQ4wDAYDVQQKEwV3MS5maTEQMA4G
+A1UEAxMHVGVzdCBDQTEbMBkGCSqGSIb3DQEJARYMdGVzdGNhQHcxLmZpMB4XDTA3
+MTIwOTAzMTUwOFoXDTE3MTIwNjAzMTUwOFoweTELMAkGA1UEBhMCVVMxEzARBgNV
+BAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xDjAMBgNVBAoT
+BXcxLmZpMRAwDgYDVQQDEwdUZXN0IEFTMRswGQYJKoZIhvcNAQkBFgx0ZXN0YXNA
+dzEuZmkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOhi4M+aMRa778CPRFV
+ZNJvTuxfp0CQ+etNpSNkAbkCGNGolbPMPnSQWZUqL5HsaBLm2UbMtS2iR3CO5JQC
+bPy0xfAjCZV5LQeW4UNVKL3hdtVFzMT6fKgOKCDVEbLLWZze3lEbzhu81q2r3w5x
+4lqDieCHwvwjiTWpMtEyXIEnAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4
+QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBRb
+xGTC3mPimgyGb5vYLLV5wyc9ITAfBgNVHSMEGDAWgBSoSbkiyeiYXAf3UYAfI9If
+ZjpaSjANBgkqhkiG9w0BAQUFAAOBgQA9wVGtroz/rsx1EeALJejW01SAr4kpTxoS
+WP6zuWFb+J/lJd7DeVM6/QBYAwZb0fB6nwSpJJCj6XDRZtN/yLeaTd/rCZrfom4Z
+8gbkWMTXDn2Cea2VnCe5W0gK+4dIj5DD5CpPvgt4lYqlwN0WAih6twd7Q4x/tiiJ
+ejNQzlTHOg==
+-----END CERTIFICATE-----
diff --git a/etc/rc.d/init.d/wpa_supplicant b/etc/rc.d/init.d/wpa_supplicant
new file mode 100755 (executable)
index 0000000..a3272c2
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh
+HARDWARE_MODEL=`grep Hardware /proc/cpuinfo | awk "{print \\$3}"`
+/bin/echo "Hardware Model=${HARDWARE_MODEL}"
+
+case $HARDWARE_MODEL in
+               "SLP_PQ")       /bin/echo "This is PQ"
+                       /usr/sbin/wpa_supplicant -u -t -B -ddd -f /var/log/wpa_supplicant.log
+               ;;
+               "U1SLP" | "U1HD")       /bin/echo "This is U1SLP"
+                       /usr/sbin/wpa_supplicant -Dwext -u -t -B -ddd -f /var/log/wpa_supplicant.log
+               ;;
+               "SLP7_C210")    /bin/echo "This is C210"
+                       /usr/sbin/wpa_supplicant -Dwext -u -t -B -ddd -f /var/log/wpa_supplicant.log
+               ;;
+               "SLP10_C210")
+                       /usr/sbin/wpa_supplicant -Dwext -u -t -B -ddd -f /var/log/wpa_supplicant.log
+               ;;
+               *)
+                       /usr/sbin/wpa_supplicant -u -t -B -ddd -f /var/log/wpa_supplicant.log
+               ;;
+esac
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
new file mode 100644 (file)
index 0000000..7f0ba5c
--- /dev/null
@@ -0,0 +1,826 @@
+LOCAL_PATH := $(call my-dir)
+
+WPA_BUILD_HOSTAPD := false
+ifneq ($(BOARD_HOSTAPD_DRIVER),)
+  WPA_BUILD_HOSTAPD := true
+  CONFIG_DRIVER_$(BOARD_HOSTAPD_DRIVER) := y
+endif
+
+ifeq ($(WPA_BUILD_HOSTAPD),true)
+
+include $(LOCAL_PATH)/.config
+
+# To ignore possible wrong network configurations
+L_CFLAGS = -DWPA_IGNORE_CONFIG_ERRORS
+
+# Set Android log name
+L_CFLAGS += -DANDROID_LOG_NAME=\"hostapd\"
+
+# To force sizeof(enum) = 4
+ifeq ($(TARGET_ARCH),arm)
+L_CFLAGS += -mabi=aapcs-linux
+endif
+
+# To allow non-ASCII characters in SSID
+L_CFLAGS += -DWPA_UNICODE_SSID
+
+# OpenSSL is configured without engines on Android
+L_CFLAGS += -DOPENSSL_NO_ENGINE
+
+INCLUDES = $(LOCAL_PATH)
+INCLUDES += $(LOCAL_PATH)/src
+INCLUDES += $(LOCAL_PATH)/src/utils
+INCLUDES += external/openssl/include
+INCLUDES += frameworks/base/cmds/keystore
+ifdef CONFIG_DRIVER_NL80211
+INCLUDES += external/libnl-headers
+endif
+
+
+ifndef CONFIG_OS
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_OS=win32
+else
+CONFIG_OS=unix
+endif
+endif
+
+ifeq ($(CONFIG_OS), internal)
+L_CFLAGS += -DOS_NO_C_LIB_DEFINES
+endif
+
+ifdef CONFIG_NATIVE_WINDOWS
+L_CFLAGS += -DCONFIG_NATIVE_WINDOWS
+LIBS += -lws2_32
+endif
+
+OBJS = main.c
+OBJS += config_file.c
+
+OBJS += src/ap/hostapd.c
+OBJS += src/ap/wpa_auth_glue.c
+OBJS += src/ap/drv_callbacks.c
+OBJS += src/ap/ap_drv_ops.c
+OBJS += src/ap/utils.c
+OBJS += src/ap/authsrv.c
+OBJS += src/ap/ieee802_1x.c
+OBJS += src/ap/ap_config.c
+OBJS += src/ap/ieee802_11_auth.c
+OBJS += src/ap/sta_info.c
+OBJS += src/ap/wpa_auth.c
+OBJS += src/ap/tkip_countermeasures.c
+OBJS += src/ap/ap_mlme.c
+OBJS += src/ap/wpa_auth_ie.c
+OBJS += src/ap/preauth_auth.c
+OBJS += src/ap/pmksa_cache_auth.c
+OBJS += src/ap/ieee802_11_shared.c
+OBJS += src/ap/beacon.c
+OBJS_d =
+OBJS_p =
+LIBS =
+LIBS_c =
+HOBJS =
+LIBS_h =
+
+NEED_RC4=y
+NEED_AES=y
+NEED_MD5=y
+NEED_SHA1=y
+
+OBJS += src/drivers/drivers.c
+L_CFLAGS += -DHOSTAPD
+
+ifdef CONFIG_WPA_TRACE
+L_CFLAGS += -DWPA_TRACE
+OBJS += src/utils/trace.c
+HOBJS += src/utils/trace.c
+LDFLAGS += -rdynamic
+L_CFLAGS += -funwind-tables
+ifdef CONFIG_WPA_TRACE_BFD
+L_CFLAGS += -DWPA_TRACE_BFD
+LIBS += -lbfd
+LIBS_c += -lbfd
+LIBS_h += -lbfd
+endif
+endif
+
+OBJS += src/utils/eloop.c
+OBJS += src/utils/common.c
+OBJS += src/utils/wpa_debug.c
+OBJS += src/utils/wpabuf.c
+OBJS += src/utils/os_$(CONFIG_OS).c
+OBJS += src/utils/ip_addr.c
+
+OBJS += src/common/ieee802_11_common.c
+OBJS += src/common/wpa_common.c
+
+OBJS += src/eapol_auth/eapol_auth_sm.c
+
+
+ifndef CONFIG_NO_DUMP_STATE
+# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to
+# a file (undefine it, if you want to save in binary size)
+L_CFLAGS += -DHOSTAPD_DUMP_STATE
+OBJS += dump_state.c
+OBJS += src/eapol_auth/eapol_auth_dump.c
+endif
+
+ifdef CONFIG_NO_RADIUS
+L_CFLAGS += -DCONFIG_NO_RADIUS
+CONFIG_NO_ACCOUNTING=y
+else
+OBJS += src/radius/radius.c
+OBJS += src/radius/radius_client.c
+endif
+
+ifdef CONFIG_NO_ACCOUNTING
+L_CFLAGS += -DCONFIG_NO_ACCOUNTING
+else
+OBJS += src/ap/accounting.c
+endif
+
+ifdef CONFIG_NO_VLAN
+L_CFLAGS += -DCONFIG_NO_VLAN
+else
+OBJS += src/ap/vlan_init.c
+endif
+
+ifdef CONFIG_NO_CTRL_IFACE
+L_CFLAGS += -DCONFIG_NO_CTRL_IFACE
+else
+OBJS += ctrl_iface.c
+OBJS += src/ap/ctrl_iface_ap.c
+endif
+
+OBJS += src/crypto/md5.c
+
+L_CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
+
+ifdef CONFIG_IAPP
+L_CFLAGS += -DCONFIG_IAPP
+OBJS += src/ap/iapp.c
+endif
+
+ifdef CONFIG_RSN_PREAUTH
+L_CFLAGS += -DCONFIG_RSN_PREAUTH
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_PEERKEY
+L_CFLAGS += -DCONFIG_PEERKEY
+OBJS += src/ap/peerkey_auth.c
+endif
+
+ifdef CONFIG_IEEE80211W
+L_CFLAGS += -DCONFIG_IEEE80211W
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_IEEE80211R
+L_CFLAGS += -DCONFIG_IEEE80211R
+OBJS += src/ap/wpa_auth_ft.c
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+NEED_AES_UNWRAP=y
+endif
+
+ifdef CONFIG_IEEE80211N
+L_CFLAGS += -DCONFIG_IEEE80211N
+endif
+
+include $(LOCAL_PATH)/src/drivers/drivers.mk
+
+OBJS += $(DRV_AP_OBJS)
+L_CFLAGS += $(DRV_AP_CFLAGS)
+LDFLAGS += $(DRV_AP_LDFLAGS)
+LIBS += $(DRV_AP_LIBS)
+
+ifdef CONFIG_L2_PACKET
+ifdef CONFIG_DNET_PCAP
+ifdef CONFIG_L2_FREEBSD
+LIBS += -lpcap
+OBJS += src/l2_packet/l2_packet_freebsd.c
+else
+LIBS += -ldnet -lpcap
+OBJS += src/l2_packet/l2_packet_pcap.c
+endif
+else
+OBJS += src/l2_packet/l2_packet_linux.c
+endif
+else
+OBJS += src/l2_packet/l2_packet_none.c
+endif
+
+
+ifdef CONFIG_EAP_MD5
+L_CFLAGS += -DEAP_SERVER_MD5
+OBJS += src/eap_server/eap_server_md5.c
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_TLS
+L_CFLAGS += -DEAP_SERVER_TLS
+OBJS += src/eap_server/eap_server_tls.c
+TLS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_PEAP
+L_CFLAGS += -DEAP_SERVER_PEAP
+OBJS += src/eap_server/eap_server_peap.c
+OBJS += src/eap_common/eap_peap_common.c
+TLS_FUNCS=y
+CONFIG_EAP_MSCHAPV2=y
+endif
+
+ifdef CONFIG_EAP_TTLS
+L_CFLAGS += -DEAP_SERVER_TTLS
+OBJS += src/eap_server/eap_server_ttls.c
+TLS_FUNCS=y
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_MSCHAPV2
+L_CFLAGS += -DEAP_SERVER_MSCHAPV2
+OBJS += src/eap_server/eap_server_mschapv2.c
+MS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_GTC
+L_CFLAGS += -DEAP_SERVER_GTC
+OBJS += src/eap_server/eap_server_gtc.c
+endif
+
+ifdef CONFIG_EAP_SIM
+L_CFLAGS += -DEAP_SERVER_SIM
+OBJS += src/eap_server/eap_server_sim.c
+CONFIG_EAP_SIM_COMMON=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_AKA
+L_CFLAGS += -DEAP_SERVER_AKA
+OBJS += src/eap_server/eap_server_aka.c
+CONFIG_EAP_SIM_COMMON=y
+NEED_SHA256=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_AKA_PRIME
+L_CFLAGS += -DEAP_SERVER_AKA_PRIME
+endif
+
+ifdef CONFIG_EAP_SIM_COMMON
+OBJS += src/eap_common/eap_sim_common.c
+# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
+# replaced with another file implementating the interface specified in
+# eap_sim_db.h.
+OBJS += src/eap_server/eap_sim_db.c
+NEED_FIPS186_2_PRF=y
+endif
+
+ifdef CONFIG_EAP_PAX
+L_CFLAGS += -DEAP_SERVER_PAX
+OBJS += src/eap_server/eap_server_pax.c src/eap_common/eap_pax_common.c
+endif
+
+ifdef CONFIG_EAP_PSK
+L_CFLAGS += -DEAP_SERVER_PSK
+OBJS += src/eap_server/eap_server_psk.c src/eap_common/eap_psk_common.c
+NEED_AES_OMAC1=y
+NEED_AES_ENCBLOCK=y
+NEED_AES_EAX=y
+endif
+
+ifdef CONFIG_EAP_SAKE
+L_CFLAGS += -DEAP_SERVER_SAKE
+OBJS += src/eap_server/eap_server_sake.c src/eap_common/eap_sake_common.c
+endif
+
+ifdef CONFIG_EAP_GPSK
+L_CFLAGS += -DEAP_SERVER_GPSK
+OBJS += src/eap_server/eap_server_gpsk.c src/eap_common/eap_gpsk_common.c
+ifdef CONFIG_EAP_GPSK_SHA256
+L_CFLAGS += -DEAP_SERVER_GPSK_SHA256
+endif
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_EAP_PWD
+L_CFLAGS += -DEAP_SERVER_PWD
+OBJS += src/eap_server/eap_server_pwd.c src/eap_common/eap_pwd_common.c
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_EAP_VENDOR_TEST
+L_CFLAGS += -DEAP_SERVER_VENDOR_TEST
+OBJS += src/eap_server/eap_server_vendor_test.c
+endif
+
+ifdef CONFIG_EAP_FAST
+L_CFLAGS += -DEAP_SERVER_FAST
+OBJS += src/eap_server/eap_server_fast.c
+OBJS += src/eap_common/eap_fast_common.c
+TLS_FUNCS=y
+NEED_T_PRF=y
+NEED_AES_UNWRAP=y
+endif
+
+ifdef CONFIG_WPS
+ifdef CONFIG_WPS2
+L_CFLAGS += -DCONFIG_WPS2
+endif
+
+L_CFLAGS += -DCONFIG_WPS -DEAP_SERVER_WSC
+OBJS += src/utils/uuid.c
+OBJS += src/ap/wps_hostapd.c
+OBJS += src/eap_server/eap_server_wsc.c src/eap_common/eap_wsc_common.c
+OBJS += src/wps/wps.c
+OBJS += src/wps/wps_common.c
+OBJS += src/wps/wps_attr_parse.c
+OBJS += src/wps/wps_attr_build.c
+OBJS += src/wps/wps_attr_process.c
+OBJS += src/wps/wps_dev_attr.c
+OBJS += src/wps/wps_enrollee.c
+OBJS += src/wps/wps_registrar.c
+NEED_DH_GROUPS=y
+NEED_SHA256=y
+NEED_BASE64=y
+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
+L_CFLAGS += -DCONFIG_WPS_OOB
+endif
+
+ifdef CONFIG_WPS_UPNP
+L_CFLAGS += -DCONFIG_WPS_UPNP
+OBJS += src/wps/wps_upnp.c
+OBJS += src/wps/wps_upnp_ssdp.c
+OBJS += src/wps/wps_upnp_web.c
+OBJS += src/wps/wps_upnp_event.c
+OBJS += src/wps/wps_upnp_ap.c
+OBJS += src/wps/upnp_xml.c
+OBJS += src/wps/httpread.c
+OBJS += src/wps/http_client.c
+OBJS += src/wps/http_server.c
+endif
+
+ifdef CONFIG_WPS_STRICT
+L_CFLAGS += -DCONFIG_WPS_STRICT
+OBJS += src/wps/wps_validate.c
+endif
+
+ifdef CONFIG_WPS_TESTING
+L_CFLAGS += -DCONFIG_WPS_TESTING
+endif
+
+endif
+
+ifdef CONFIG_EAP_IKEV2
+L_CFLAGS += -DEAP_SERVER_IKEV2
+OBJS += src/eap_server/eap_server_ikev2.c src/eap_server/ikev2.c
+OBJS += src/eap_common/eap_ikev2_common.c src/eap_common/ikev2_common.c
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+NEED_MODEXP=y
+NEED_CIPHER=y
+endif
+
+ifdef CONFIG_EAP_TNC
+L_CFLAGS += -DEAP_SERVER_TNC
+OBJS += src/eap_server/eap_server_tnc.c
+OBJS += src/eap_server/tncs.c
+NEED_BASE64=y
+ifndef CONFIG_DRIVER_BSD
+LIBS += -ldl
+endif
+endif
+
+# Basic EAP functionality is needed for EAPOL
+OBJS += eap_register.c
+OBJS += src/eap_server/eap_server.c
+OBJS += src/eap_common/eap_common.c
+OBJS += src/eap_server/eap_server_methods.c
+OBJS += src/eap_server/eap_server_identity.c
+L_CFLAGS += -DEAP_SERVER_IDENTITY
+
+ifdef CONFIG_EAP
+L_CFLAGS += -DEAP_SERVER
+endif
+
+ifdef CONFIG_PKCS12
+L_CFLAGS += -DPKCS12_FUNCS
+endif
+
+ifdef MS_FUNCS
+OBJS += src/crypto/ms_funcs.c
+NEED_DES=y
+NEED_MD4=y
+endif
+
+ifdef CHAP
+OBJS += src/eap_common/chap.c
+endif
+
+ifdef TLS_FUNCS
+NEED_DES=y
+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
+L_CFLAGS += -DEAP_TLS_FUNCS
+OBJS += src/eap_server/eap_server_tls_common.c
+NEED_TLS_PRF=y
+endif
+
+ifndef CONFIG_TLS
+CONFIG_TLS=openssl
+endif
+
+ifeq ($(CONFIG_TLS), openssl)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_openssl.c
+LIBS += -lssl
+endif
+OBJS += src/crypto/crypto_openssl.c
+HOBJS += src/crypto/crypto_openssl.c
+ifdef NEED_FIPS186_2_PRF
+OBJS += src/crypto/fips_prf_openssl.c
+endif
+LIBS += -lcrypto
+LIBS_h += -lcrypto
+endif
+
+ifeq ($(CONFIG_TLS), gnutls)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_gnutls.c
+LIBS += -lgnutls -lgpg-error
+ifdef CONFIG_GNUTLS_EXTRA
+L_CFLAGS += -DCONFIG_GNUTLS_EXTRA
+LIBS += -lgnutls-extra
+endif
+endif
+OBJS += src/crypto/crypto_gnutls.c
+HOBJS += src/crypto/crypto_gnutls.c
+ifdef NEED_FIPS186_2_PRF
+OBJS += src/crypto/fips_prf_gnutls.c
+endif
+LIBS += -lgcrypt
+LIBS_h += -lgcrypt
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), schannel)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_schannel.c
+endif
+OBJS += src/crypto/crypto_cryptoapi.c
+OBJS_p += src/crypto/crypto_cryptoapi.c
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), nss)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_nss.c
+LIBS += -lssl3
+endif
+OBJS += src/crypto/crypto_nss.c
+ifdef NEED_FIPS186_2_PRF
+OBJS += src/crypto/fips_prf_nss.c
+endif
+LIBS += -lnss3
+LIBS_h += -lnss3
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), internal)
+ifndef CONFIG_CRYPTO
+CONFIG_CRYPTO=internal
+endif
+ifdef TLS_FUNCS
+OBJS += src/crypto/crypto_internal-rsa.c
+OBJS += src/crypto/tls_internal.c
+OBJS += src/tls/tlsv1_common.c
+OBJS += src/tls/tlsv1_record.c
+OBJS += src/tls/tlsv1_cred.c
+OBJS += src/tls/tlsv1_server.c
+OBJS += src/tls/tlsv1_server_write.c
+OBJS += src/tls/tlsv1_server_read.c
+OBJS += src/tls/asn1.c
+OBJS += src/tls/rsa.c
+OBJS += src/tls/x509v3.c
+OBJS += src/tls/pkcs1.c
+OBJS += src/tls/pkcs5.c
+OBJS += src/tls/pkcs8.c
+NEED_SHA256=y
+NEED_BASE64=y
+NEED_TLS_PRF=y
+NEED_MODEXP=y
+NEED_CIPHER=y
+L_CFLAGS += -DCONFIG_TLS_INTERNAL
+L_CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
+endif
+ifdef NEED_CIPHER
+NEED_DES=y
+OBJS += src/crypto/crypto_internal-cipher.c
+endif
+ifdef NEED_MODEXP
+OBJS += src/crypto/crypto_internal-modexp.c
+OBJS += src/tls/bignum.c
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+OBJS += src/crypto/crypto_libtomcrypt.c
+LIBS += -ltomcrypt -ltfm
+LIBS_h += -ltomcrypt -ltfm
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+OBJS += src/crypto/crypto_internal.c
+NEED_AES_DEC=y
+L_CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+ifdef CONFIG_INTERNAL_LIBTOMMATH
+L_CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST
+L_CFLAGS += -DLTM_FAST
+endif
+else
+LIBS += -ltommath
+LIBS_h += -ltommath
+endif
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_DES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+OBJS += src/crypto/crypto_cryptoapi.c
+OBJS_p += src/crypto/crypto_cryptoapi.c
+L_CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+ifeq ($(CONFIG_TLS), none)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_none.c
+L_CFLAGS += -DEAP_TLS_NONE
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+endif
+OBJS += src/crypto/crypto_none.c
+OBJS_p += src/crypto/crypto_none.c
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+
+ifndef TLS_FUNCS
+OBJS += src/crypto/tls_none.c
+ifeq ($(CONFIG_TLS), internal)
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+AESOBJS = # none so far
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += src/crypto/aes-internal.c src/crypto/aes-internal-enc.c
+endif
+
+AESOBJS += src/crypto/aes-wrap.c
+ifdef NEED_AES_EAX
+AESOBJS += src/crypto/aes-eax.c
+NEED_AES_CTR=y
+endif
+ifdef NEED_AES_CTR
+AESOBJS += src/crypto/aes-ctr.c
+endif
+ifdef NEED_AES_ENCBLOCK
+AESOBJS += src/crypto/aes-encblock.c
+endif
+ifdef NEED_AES_OMAC1
+AESOBJS += src/crypto/aes-omac1.c
+endif
+ifdef NEED_AES_UNWRAP
+NEED_AES_DEC=y
+AESOBJS += src/crypto/aes-unwrap.c
+endif
+ifdef NEED_AES_CBC
+NEED_AES_DEC=y
+AESOBJS += src/crypto/aes-cbc.c
+endif
+ifdef NEED_AES_DEC
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += src/crypto/aes-internal-dec.c
+endif
+endif
+ifdef NEED_AES
+OBJS += $(AESOBJS)
+endif
+
+SHA1OBJS =
+ifdef NEED_SHA1
+SHA1OBJS += src/crypto/sha1.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
+SHA1OBJS += src/crypto/sha1-pbkdf2.c
+ifdef NEED_T_PRF
+SHA1OBJS += src/crypto/sha1-tprf.c
+endif
+ifdef NEED_TLS_PRF
+SHA1OBJS += src/crypto/sha1-tlsprf.c
+endif
+endif
+
+ifdef NEED_SHA1
+OBJS += $(SHA1OBJS)
+endif
+
+ifdef NEED_MD5
+ifdef CONFIG_INTERNAL_MD5
+OBJS += src/crypto/md5-internal.c
+HOBJS += src/crypto/md5-internal.c
+endif
+endif
+
+ifdef NEED_MD4
+ifdef CONFIG_INTERNAL_MD4
+OBJS += src/crypto/md4-internal.c
+endif
+endif
+
+ifdef NEED_DES
+ifdef CONFIG_INTERNAL_DES
+OBJS += src/crypto/des-internal.c
+endif
+endif
+
+ifdef NEED_RC4
+ifdef CONFIG_INTERNAL_RC4
+OBJS += src/crypto/rc4.c
+endif
+endif
+
+ifdef NEED_SHA256
+OBJS += src/crypto/sha256.c
+ifdef CONFIG_INTERNAL_SHA256
+OBJS += src/crypto/sha256-internal.c
+endif
+endif
+
+ifdef NEED_DH_GROUPS
+OBJS += src/crypto/dh_groups.c
+endif
+ifdef NEED_DH_GROUPS_ALL
+L_CFLAGS += -DALL_DH_GROUPS
+endif
+ifdef CONFIG_INTERNAL_DH_GROUP5
+ifdef NEED_DH_GROUPS
+OBJS += src/crypto/dh_group5.c
+endif
+endif
+
+ifdef CONFIG_NO_RANDOM_POOL
+L_CFLAGS += -DCONFIG_NO_RANDOM_POOL
+else
+OBJS += src/crypto/random.c
+HOBJS += src/crypto/random.c
+HOBJS += $(SHA1OBJS)
+HOBJS += src/crypto/md5.c
+endif
+
+ifdef CONFIG_RADIUS_SERVER
+L_CFLAGS += -DRADIUS_SERVER
+OBJS += src/radius/radius_server.c
+endif
+
+ifdef CONFIG_IPV6
+L_CFLAGS += -DCONFIG_IPV6
+endif
+
+ifdef CONFIG_DRIVER_RADIUS_ACL
+L_CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL
+endif
+
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+# define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges
+# and vlan interfaces for the vlan feature.
+L_CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN
+endif
+
+ifdef NEED_BASE64
+OBJS += src/utils/base64.c
+endif
+
+ifdef NEED_AP_MLME
+OBJS += src/ap/wmm.c
+OBJS += src/ap/ap_list.c
+OBJS += src/ap/ieee802_11.c
+OBJS += src/ap/hw_features.c
+L_CFLAGS += -DNEED_AP_MLME
+endif
+ifdef CONFIG_IEEE80211N
+OBJS += src/ap/ieee802_11_ht.c
+endif
+
+ifdef CONFIG_P2P_MANAGER
+L_CFLAGS += -DCONFIG_P2P_MANAGER
+OBJS += src/ap/p2p_hostapd.c
+endif
+
+OBJS += src/drivers/driver_common.c
+
+ifdef CONFIG_NO_STDOUT_DEBUG
+L_CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
+endif
+
+ifdef CONFIG_DEBUG_FILE
+L_CFLAGS += -DCONFIG_DEBUG_FILE
+endif
+
+ifdef CONFIG_ANDROID_LOG
+L_CFLAGS += -DCONFIG_ANDROID_LOG
+endif
+
+OBJS_c = hostapd_cli.c src/common/wpa_ctrl.c src/utils/os_$(CONFIG_OS).c
+OBJS_c += src/utils/eloop.c
+ifdef CONFIG_WPA_TRACE
+OBJS_c += src/utils/trace.c
+endif
+OBJS_c += src/utils/wpa_debug.c
+ifdef CONFIG_WPA_CLI_EDIT
+OBJS_c += src/utils/edit.c
+else
+OBJS_c += src/utils/edit_simple.c
+endif
+
+########################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := hostapd_cli
+LOCAL_MODULE_TAGS := debug
+LOCAL_SHARED_LIBRARIES := libc libcutils
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_SRC_FILES := $(OBJS_c)
+LOCAL_C_INCLUDES := $(INCLUDES)
+include $(BUILD_EXECUTABLE)
+
+########################
+include $(CLEAR_VARS)
+LOCAL_MODULE := hostapd
+LOCAL_MODULE_TAGS := optional
+ifdef CONFIG_DRIVER_CUSTOM
+LOCAL_STATIC_LIBRARIES := libCustomWifi
+endif
+ifneq ($(BOARD_HOSTAPD_PRIVATE_LIB),)
+LOCAL_STATIC_LIBRARIES += $(BOARD_HOSTAPD_PRIVATE_LIB)
+endif
+LOCAL_SHARED_LIBRARIES := libc libcutils libcrypto libssl
+ifdef CONFIG_DRIVER_NL80211
+LOCAL_STATIC_LIBRARIES += libnl_2
+endif
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_SRC_FILES := $(OBJS)
+LOCAL_C_INCLUDES := $(INCLUDES)
+include $(BUILD_EXECUTABLE)
+
+endif # ifeq ($(WPA_BUILD_HOSTAPD),true)
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
new file mode 100644 (file)
index 0000000..47f2423
--- /dev/null
@@ -0,0 +1,647 @@
+ChangeLog for hostapd
+
+2010-04-18 - v0.7.2
+       * fix WPS internal Registrar use when an external Registrar is also
+         active
+       * bsd: Cleaned up driver wrapper and added various low-level
+         configuration options
+       * TNC: fixed issues with fragmentation
+       * EAP-TNC: add Flags field into fragment acknowledgement (needed to
+         interoperate with other implementations; may potentially breaks
+         compatibility with older wpa_supplicant/hostapd versions)
+       * cleaned up driver wrapper API for multi-BSS operations
+       * nl80211: fix multi-BSS and VLAN operations
+       * fix number of issues with IEEE 802.11r/FT; this version is not
+         backwards compatible with old versions
+       * add SA Query Request processing in AP mode (IEEE 802.11w)
+       * fix IGTK PN in group rekeying (IEEE 802.11w)
+       * fix WPS PBC session overlap detection to use correct attribute
+       * hostapd_notif_Assoc() can now be called with all IEs to simplify
+         driver wrappers
+       * work around interoperability issue with some WPS External Registrar
+         implementations
+       * nl80211: fix WPS IE update
+       * hostapd_cli: add support for action script operations (run a script
+         on hostapd events)
+       * fix DH padding with internal crypto code (mainly, for WPS)
+       * fix WPS association with both WPS IE and WPA/RSN IE present with
+         driver wrappers that use hostapd MLME (e.g., nl80211)
+
+2010-01-16 - v0.7.1
+       * cleaned up driver wrapper API (struct wpa_driver_ops); the new API
+         is not fully backwards compatible, so out-of-tree driver wrappers
+         will need modifications
+       * cleaned up various module interfaces
+       * merge hostapd and wpa_supplicant developers' documentation into a
+         single document
+       * fixed HT Capabilities IE with nl80211 drivers
+       * moved generic AP functionality code into src/ap
+       * WPS: handle Selected Registrar as union of info from all Registrars
+       * remove obsolte Prism54.org driver wrapper
+       * added internal debugging mechanism with backtrace support and memory
+         allocation/freeing validation, etc. tests (CONFIG_WPA_TRACE=y)
+       * EAP-FAST server: piggyback Phase 2 start with the end of Phase 1
+       * WPS: add support for dynamically selecting whether to provision the
+         PSK as an ASCII passphrase or PSK
+       * added support for WDS (4-address frame) mode with per-station virtual
+         interfaces (wds_sta=1 in config file; only supported with
+         driver=nl80211 for now)
+       * fixed WPS Probe Request processing to handle missing required
+         attribute
+       * fixed PKCS#12 use with OpenSSL 1.0.0
+       * detect bridge interface automatically so that bridge parameter in
+         hostapd.conf becomes optional (though, it may now be used to
+         automatically add then WLAN interface into a bridge with
+         driver=nl80211)
+
+2009-11-21 - v0.7.0
+       * increased hostapd_cli ping interval to 5 seconds and made this
+         configurable with a new command line options (-G<seconds>)
+       * driver_nl80211: use Linux socket filter to improve performance
+       * added support for external Registrars with WPS (UPnP transport)
+       * 802.11n: scan for overlapping BSSes before starting 20/40 MHz channel
+       * driver_nl80211: fixed STA accounting data collection (TX/RX bytes
+         reported correctly; TX/RX packets not yet available from kernel)
+       * added support for WPS USBA out-of-band mechanism with USB Flash
+         Drives (UFD) (CONFIG_WPS_UFD=y)
+       * fixed EAPOL/EAP reauthentication when using an external RADIUS
+         authentication server
+       * fixed TNC with EAP-TTLS
+       * fixed IEEE 802.11r key derivation function to match with the standard
+         (note: this breaks interoperability with previous version) [Bug 303]
+       * fixed SHA-256 based key derivation function to match with the
+         standard when using CCMP (for IEEE 802.11r and IEEE 802.11w)
+         (note: this breaks interoperability with previous version) [Bug 307]
+       * added number of code size optimizations to remove unnecessary
+         functionality from the program binary based on build configuration
+         (part of this automatic; part configurable with CONFIG_NO_* build
+         options)
+       * use shared driver wrapper files with wpa_supplicant
+       * driver_nl80211: multiple updates to provide support for new Linux
+         nl80211/mac80211 functionality
+       * updated management frame protection to use IEEE Std 802.11w-2009
+       * fixed number of small WPS issues and added workarounds to
+         interoperate with common deployed broken implementations
+       * added some IEEE 802.11n co-existence rules to disable 40 MHz channels
+         or modify primary/secondary channels if needed based on neighboring
+         networks
+       * added support for NFC out-of-band mechanism with WPS
+       * added preliminary support for IEEE 802.11r RIC processing
+
+2009-01-06 - v0.6.7
+       * added support for Wi-Fi Protected Setup (WPS)
+         (hostapd can now be configured to act as an integrated WPS Registrar
+         and provision credentials for WPS Enrollees using PIN and PBC
+         methods; external wireless Registrar can configure the AP, but
+         external WLAN Manager Registrars are not supported); WPS support can
+         be enabled by adding CONFIG_WPS=y into .config and setting the
+         runtime configuration variables in hostapd.conf (see WPS section in
+         the example configuration file); new hostapd_cli commands wps_pin and
+         wps_pbc are used to configure WPS negotiation; see README-WPS for
+         more details
+       * added IEEE 802.11n HT capability configuration (ht_capab)
+       * added support for generating Country IE based on nl80211 regulatory
+         information (added if ieee80211d=1 in configuration)
+       * fixed WEP authentication (both Open System and Shared Key) with
+         mac80211
+       * added support for EAP-AKA' (draft-arkko-eap-aka-kdf)
+       * added support for using driver_test over UDP socket
+       * changed EAP-GPSK to use the IANA assigned EAP method type 51
+       * updated management frame protection to use IEEE 802.11w/D7.0
+       * fixed retransmission of EAP requests if no response is received
+
+2008-11-23 - v0.6.6
+       * added a new configuration option, wpa_ptk_rekey, that can be used to
+         enforce frequent PTK rekeying, e.g., to mitigate some attacks against
+         TKIP deficiencies
+       * updated OpenSSL code for EAP-FAST to use an updated version of the
+         session ticket overriding API that was included into the upstream
+         OpenSSL 0.9.9 tree on 2008-11-15 (no additional OpenSSL patch is
+         needed with that version anymore)
+       * changed channel flags configuration to read the information from
+         the driver (e.g., via driver_nl80211 when using mac80211) instead of
+         using hostapd as the source of the regulatory information (i.e.,
+         information from CRDA is now used with mac80211); this allows 5 GHz
+         channels to be used with hostapd (if allowed in the current
+         regulatory domain)
+       * fixed EAP-TLS message processing for the last TLS message if it is
+         large enough to require fragmentation (e.g., if a large Session
+         Ticket data is included)
+       * fixed listen interval configuration for nl80211 drivers
+
+2008-11-01 - v0.6.5
+       * added support for SHA-256 as X.509 certificate digest when using the
+         internal X.509/TLSv1 implementation
+       * fixed EAP-FAST PAC-Opaque padding (0.6.4 broke this for some peer
+         identity lengths)
+       * fixed internal TLSv1 implementation for abbreviated handshake (used
+         by EAP-FAST server)
+       * added support for setting VLAN ID for STAs based on local MAC ACL
+         (accept_mac_file) as an alternative for RADIUS server-based
+         configuration
+       * updated management frame protection to use IEEE 802.11w/D6.0
+         (adds a new association ping to protect against unauthenticated
+         authenticate or (re)associate request frames dropping association)
+       * added support for using SHA256-based stronger key derivation for WPA2
+         (IEEE 802.11w)
+       * added new "driver wrapper" for RADIUS-only configuration
+         (driver=none in hostapd.conf; CONFIG_DRIVER_NONE=y in .config)
+       * fixed WPA/RSN IE validation to verify that the proto (WPA vs. WPA2)
+         is enabled in configuration
+       * changed EAP-FAST configuration to use separate fields for A-ID and
+         A-ID-Info (eap_fast_a_id_info) to allow A-ID to be set to a fixed
+         16-octet len binary value for better interoperability with some peer
+         implementations; eap_fast_a_id is now configured as a hex string
+       * driver_nl80211: Updated to match the current Linux mac80211 AP mode
+         configuration (wireless-testing.git and Linux kernel releases
+         starting from 2.6.29)
+
+2008-08-10 - v0.6.4
+       * added peer identity into EAP-FAST PAC-Opaque and skip Phase 2
+         Identity Request if identity is already known
+       * added support for EAP Sequences in EAP-FAST Phase 2
+       * added support for EAP-TNC (Trusted Network Connect)
+         (this version implements the EAP-TNC method and EAP-TTLS/EAP-FAST
+         changes needed to run two methods in sequence (IF-T) and the IF-IMV
+         and IF-TNCCS interfaces from TNCS)
+       * added support for optional cryptobinding with PEAPv0
+       * added fragmentation support for EAP-TNC
+       * added support for fragmenting EAP-TTLS/PEAP/FAST Phase 2 (tunneled)
+         data
+       * added support for opportunistic key caching (OKC)
+
+2008-02-22 - v0.6.3
+       * fixed Reassociation Response callback processing when using internal
+         MLME (driver_{hostap,nl80211,test}.c)
+       * updated FT support to use the latest draft, IEEE 802.11r/D9.0
+       * copy optional Proxy-State attributes into RADIUS response when acting
+         as a RADIUS authentication server
+       * fixed EAPOL state machine to handle a case in which no response is
+         received from the RADIUS authentication server; previous version
+         could have triggered a crash in some cases after a timeout
+       * fixed EAP-SIM/AKA realm processing to allow decorated usernames to
+         be used
+       * added a workaround for EAP-SIM/AKA peers that include incorrect null
+         termination in the username
+       * fixed EAP-SIM/AKA protected result indication to include AT_COUNTER
+         attribute in notification messages only when using fast
+         reauthentication
+       * fixed EAP-SIM Start response processing for fast reauthentication
+         case
+       * added support for pending EAP processing in EAP-{PEAP,TTLS,FAST}
+         phase 2 to allow EAP-SIM and EAP-AKA to be used as the Phase 2 method
+
+2008-01-01 - v0.6.2
+       * fixed EAP-SIM and EAP-AKA message parser to validate attribute
+         lengths properly to avoid potential crash caused by invalid messages
+       * added data structure for storing allocated buffers (struct wpabuf);
+         this does not affect hostapd usage, but many of the APIs changed
+         and various interfaces (e.g., EAP) is not compatible with old
+         versions
+       * added support for protecting EAP-AKA/Identity messages with
+         AT_CHECKCODE (optional feature in RFC 4187)
+       * added support for protected result indication with AT_RESULT_IND for
+         EAP-SIM and EAP-AKA (eap_sim_aka_result_ind=1)
+       * added support for configuring EAP-TTLS phase 2 non-EAP methods in
+         EAP server configuration; previously all four were enabled for every
+         phase 2 user, now all four are disabled by default and need to be
+         enabled with new method names TTLS-PAP, TTLS-CHAP, TTLS-MSCHAP,
+         TTLS-MSCHAPV2
+       * removed old debug printing mechanism and the related 'debug'
+         parameter in the configuration file; debug verbosity is now set with
+         -d (or -dd) command line arguments
+       * added support for EAP-IKEv2 (draft-tschofenig-eap-ikev2-15.txt);
+         only shared key/password authentication is supported in this version
+
+2007-11-24 - v0.6.1
+       * added experimental, integrated TLSv1 server implementation with the
+         needed X.509/ASN.1/RSA/bignum processing (this can be enabled by
+         setting CONFIG_TLS=internal and CONFIG_INTERNAL_LIBTOMMATH=y in
+         .config); this can be useful, e.g., if the target system does not
+         have a suitable TLS library and a minimal code size is required
+       * added support for EAP-FAST server method to the integrated EAP
+         server
+       * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+         draft (draft-ietf-emu-eap-gpsk-07.txt)
+       * added a new configuration parameter, rsn_pairwise, to allow different
+         pairwise cipher suites to be enabled for WPA and RSN/WPA2
+         (note: if wpa_pairwise differs from rsn_pairwise, the driver will
+         either need to support this or will have to use the WPA/RSN IEs from
+         hostapd; currently, the included madwifi and bsd driver interfaces do
+         not have support for this)
+       * updated FT support to use the latest draft, IEEE 802.11r/D8.0
+
+2007-05-28 - v0.6.0
+       * added experimental IEEE 802.11r/D6.0 support
+       * updated EAP-SAKE to RFC 4763 and the IANA-allocated EAP type 48
+       * updated EAP-PSK to use the IANA-allocated EAP type 47
+       * fixed EAP-PSK bit ordering of the Flags field
+       * fixed configuration reloading (SIGHUP) to re-initialize WPA PSKs
+         by reading wpa_psk_file [Bug 181]
+       * fixed EAP-TTLS AVP parser processing for too short AVP lengths
+       * fixed IPv6 connection to RADIUS accounting server
+       * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+         draft (draft-ietf-emu-eap-gpsk-04.txt)
+       * hlr_auc_gw: read GSM triplet file into memory and rotate through the
+         entries instead of only using the same three triplets every time
+         (this does not work properly with tests using multiple clients, but
+         provides bit better triplet data for testing a single client; anyway,
+         if a better quality triplets are needed, GSM-Milenage should be used
+         instead of hardcoded triplet file)
+       * fixed EAP-MSCHAPv2 server to use a space between S and M parameters
+         in Success Request [Bug 203]
+       * added support for sending EAP-AKA Notifications in error cases
+       * updated to use IEEE 802.11w/D2.0 for management frame protection
+         (still experimental)
+       * RADIUS server: added support for processing duplicate messages
+         (retransmissions from RADIUS client) by replying with the previous
+         reply
+
+2006-11-24 - v0.5.6
+       * added support for configuring and controlling multiple BSSes per
+         radio interface (bss=<ifname> in hostapd.conf); this is only
+         available with Devicescape and test driver interfaces
+       * fixed PMKSA cache update in the end of successful RSN
+         pre-authentication
+       * added support for dynamic VLAN configuration (i.e., selecting VLAN-ID
+         for each STA based on RADIUS Access-Accept attributes); this requires
+         VLAN support from the kernel driver/802.11 stack and this is
+         currently only available with Devicescape and test driver interfaces
+       * driver_madwifi: fixed configuration of unencrypted modes (plaintext
+         and IEEE 802.1X without WEP)
+       * removed STAKey handshake since PeerKey handshake has replaced it in
+         IEEE 802.11ma and there are no known deployments of STAKey
+       * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+         draft (draft-ietf-emu-eap-gpsk-01.txt)
+       * added preliminary implementation of IEEE 802.11w/D1.0 (management
+         frame protection)
+         (Note: this requires driver support to work properly.)
+         (Note2: IEEE 802.11w is an unapproved draft and subject to change.)
+       * hlr_auc_gw: added support for GSM-Milenage (for EAP-SIM)
+       * hlr_auc_gw: added support for reading per-IMSI Milenage keys and
+         parameters from a text file to make it possible to implement proper
+         GSM/UMTS authentication server for multiple SIM/USIM cards using
+         EAP-SIM/EAP-AKA
+       * fixed session timeout processing with drivers that do not use
+         ieee802_11.c (e.g., madwifi)
+
+2006-08-27 - v0.5.5
+       * added 'hostapd_cli new_sta <addr>' command for adding a new STA into
+         hostapd (e.g., to initialize wired network authentication based on an
+         external signal)
+       * fixed hostapd to add PMKID KDE into 4-Way Handshake Message 1 when
+         using WPA2 even if PMKSA caching is not used
+       * added -P<pid file> argument for hostapd to write the current process
+         id into a file
+       * added support for RADIUS Authentication Server MIB (RFC 2619)
+
+2006-06-20 - v0.5.4
+       * fixed nt_password_hash build [Bug 144]
+       * added PeerKey handshake implementation for IEEE 802.11e
+         direct link setup (DLS) to replace STAKey handshake
+       * added support for EAP Generalized Pre-Shared Key (EAP-GPSK,
+         draft-clancy-emu-eap-shared-secret-00.txt)
+       * fixed a segmentation fault when RSN pre-authentication was completed
+         successfully [Bug 152]
+
+2006-04-27 - v0.5.3
+       * do not build nt_password_hash and hlr_auc_gw by default to avoid
+         requiring a TLS library for a successful build; these programs can be
+         build with 'make nt_password_hash' and 'make hlr_auc_gw'
+       * added a new configuration option, eapol_version, that can be used to
+         set EAPOL version to 1 (default is 2) to work around broken client
+         implementations that drop EAPOL frames which use version number 2
+         [Bug 89]
+       * added support for EAP-SAKE (no EAP method number allocated yet, so
+         this is using the same experimental type 255 as EAP-PSK)
+       * fixed EAP-MSCHAPv2 message length validation
+
+2006-03-19 - v0.5.2
+       * fixed stdarg use in hostapd_logger(): if both stdout and syslog
+         logging was enabled, hostapd could trigger a segmentation fault in
+         vsyslog on some CPU -- C library combinations
+       * moved HLR/AuC gateway implementation for EAP-SIM/AKA into an external
+         program to make it easier to use for implementing real SS7 gateway;
+         eap_sim_db is not anymore used as a file name for GSM authentication
+         triplets; instead, it is path to UNIX domain socket that will be used
+         to communicate with the external gateway program (e.g., hlr_auc_gw)
+       * added example HLR/AuC gateway implementation, hlr_auc_gw, that uses
+         local information (GSM authentication triplets from a text file and
+         hardcoded AKA authentication data); this can be used to test EAP-SIM
+         and EAP-AKA
+       * added Milenage algorithm (example 3GPP AKA algorithm) to hlr_auc_gw
+         to make it possible to test EAP-AKA with real USIM cards (this is
+         disabled by default; define AKA_USE_MILENAGE when building hlr_auc_gw
+         to enable this)
+       * driver_madwifi: added support for getting station RSN IE from
+         madwifi-ng svn r1453 and newer; this fixes RSN that was apparently
+         broken with earlier change (r1357) in the driver
+       * changed EAP method registration to use a dynamic list of methods
+         instead of a static list generated at build time
+       * fixed WPA message 3/4 not to encrypt Key Data field (WPA IE)
+         [Bug 125]
+       * added ap_max_inactivity configuration parameter
+
+2006-01-29 - v0.5.1
+       * driver_test: added better support for multiple APs and STAs by using
+         a directory with sockets that include MAC address for each device in
+         the name (test_socket=DIR:/tmp/test)
+       * added support for EAP expanded type (vendor specific EAP methods)
+
+2005-12-18 - v0.5.0 (beginning of 0.5.x development releases)
+       * added experimental STAKey handshake implementation for IEEE 802.11e
+         direct link setup (DLS); note: this is disabled by default in both
+         build and runtime configuration (can be enabled with CONFIG_STAKEY=y
+         and stakey=1)
+       * added support for EAP methods to use callbacks to external programs
+         by buffering a pending request and processing it after the EAP method
+         is ready to continue
+       * improved EAP-SIM database interface to allow external request to GSM
+         HLR/AuC without blocking hostapd process
+       * added support for using EAP-SIM pseudonyms and fast re-authentication
+       * added support for EAP-AKA in the integrated EAP authenticator
+       * added support for matching EAP identity prefixes (e.g., "1"*) in EAP
+         user database to allow EAP-SIM/AKA selection without extra roundtrip
+         for EAP-Nak negotiation
+       * added support for storing EAP user password as NtPasswordHash instead
+         of plaintext password when using MSCHAP or MSCHAPv2 for
+         authentication (hash:<16-octet hex value>); added nt_password_hash
+         tool for hashing password to generate NtPasswordHash
+
+2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases)
+       * driver_wired: fixed EAPOL sending to optionally use PAE group address
+         as the destination instead of supplicant MAC address; this is
+         disabled by default, but should be enabled with use_pae_group_addr=1
+         in configuration file if the wired interface is used by only one
+         device at the time (common switch configuration)
+       * driver_madwifi: configure driver to use TKIP countermeasures in order
+         to get correct behavior (IEEE 802.11 association failing; previously,
+         association succeeded, but hostpad forced disassociation immediately)
+       * driver_madwifi: added support for madwifi-ng
+
+2005-10-27 - v0.4.6
+       * added support for replacing user identity from EAP with RADIUS
+         User-Name attribute from Access-Accept message, if that is included,
+         for the RADIUS accounting messages (e.g., for EAP-PEAP/TTLS to get
+         tunneled identity into accounting messages when the RADIUS server
+         does not support better way of doing this with Class attribute)
+       * driver_madwifi: fixed EAPOL packet receive for configuration where
+         ath# is part of a bridge interface
+       * added a configuration file and log analyzer script for logwatch
+       * fixed EAPOL state machine step function to process all state
+         transitions before processing new events; this resolves a race
+         condition in which EAPOL-Start message could trigger hostapd to send
+         two EAP-Response/Identity frames to the authentication server
+
+2005-09-25 - v0.4.5
+       * added client CA list to the TLS certificate request in order to make
+         it easier for the client to select which certificate to use
+       * added experimental support for EAP-PSK
+       * added support for WE-19 (hostap, madwifi)
+
+2005-08-21 - v0.4.4
+       * fixed build without CONFIG_RSN_PREAUTH
+       * fixed FreeBSD build
+
+2005-06-26 - v0.4.3
+       * fixed PMKSA caching to copy User-Name and Class attributes so that
+         RADIUS accounting gets correct information
+       * start RADIUS accounting only after successful completion of WPA
+         4-Way Handshake if WPA-PSK is used
+       * fixed PMKSA caching for the case where STA (re)associates without
+         first disassociating
+
+2005-06-12 - v0.4.2
+       * EAP-PAX is now registered as EAP type 46
+       * fixed EAP-PAX MAC calculation
+       * fixed EAP-PAX CK and ICK key derivation
+       * renamed eap_authenticator configuration variable to eap_server to
+         better match with RFC 3748 (EAP) terminology
+       * driver_test: added support for testing hostapd with wpa_supplicant
+         by using test driver interface without any kernel drivers or network
+         cards
+
+2005-05-22 - v0.4.1
+       * fixed RADIUS server initialization when only auth or acct server
+         is configured and the other one is left empty
+       * driver_madwifi: added support for RADIUS accounting
+       * driver_madwifi: added preliminary support for compiling against 'BSD'
+         branch of madwifi CVS tree
+       * driver_madwifi: fixed pairwise key removal to allow WPA reauth
+         without disassociation
+       * added support for reading additional certificates from PKCS#12 files
+         and adding them to the certificate chain
+       * fixed RADIUS Class attribute processing to only use Access-Accept
+         packets to update Class; previously, other RADIUS authentication
+         packets could have cleared Class attribute
+       * added support for more than one Class attribute in RADIUS packets
+       * added support for verifying certificate revocation list (CRL) when
+         using integrated EAP authenticator for EAP-TLS; new hostapd.conf
+         options 'check_crl'; CRL must be included in the ca_cert file for now
+
+2005-04-25 - v0.4.0 (beginning of 0.4.x development releases)
+       * added support for including network information into
+         EAP-Request/Identity message (ASCII-0 (nul) in eap_message)
+         (e.g., to implement draft-adrange-eap-network-discovery-07.txt)
+       * fixed a bug which caused some RSN pre-authentication cases to use
+         freed memory and potentially crash hostapd
+       * fixed private key loading for cases where passphrase is not set
+       * added support for sending TLS alerts and aborting authentication
+         when receiving a TLS alert
+       * fixed WPA2 to add PMKSA cache entry when using integrated EAP
+         authenticator
+       * fixed PMKSA caching (EAP authentication was not skipped correctly
+         with the new state machine changes from IEEE 802.1X draft)
+       * added support for RADIUS over IPv6; own_ip_addr, auth_server_addr,
+         and acct_server_addr can now be IPv6 addresses (CONFIG_IPV6=y needs
+         to be added to .config to include IPv6 support); for RADIUS server,
+         radius_server_ipv6=1 needs to be set in hostapd.conf and addresses
+         in RADIUS clients file can then use IPv6 format
+       * added experimental support for EAP-PAX
+       * replaced hostapd control interface library (hostapd_ctrl.[ch]) with
+         the same implementation that wpa_supplicant is using (wpa_ctrl.[ch])
+
+2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases)
+
+2005-01-23 - v0.3.5
+       * added support for configuring a forced PEAP version based on the
+         Phase 1 identity
+       * fixed PEAPv1 to use tunneled EAP-Success/Failure instead of EAP-TLV
+         to terminate authentication
+       * fixed EAP identifier duplicate processing with the new IEEE 802.1X
+         draft
+       * clear accounting data in the driver when starting a new accounting
+         session
+       * driver_madwifi: filter wireless events based on ifindex to allow more
+         than one network interface to be used
+       * fixed WPA message 2/4 processing not to cancel timeout for TimeoutEvt
+         setting if the packet does not pass MIC verification (e.g., due to
+         incorrect PSK); previously, message 1/4 was not tried again if an
+         invalid message 2/4 was received
+       * fixed reconfiguration of RADIUS client retransmission timer when
+         adding a new message to the pending list; previously, timer was not
+         updated at this point and if there was a pending message with long
+         time for the next retry, the new message needed to wait that long for
+         its first retry, too
+
+2005-01-09 - v0.3.4
+       * added support for configuring multiple allowed EAP types for Phase 2
+         authentication (EAP-PEAP, EAP-TTLS)
+       * fixed EAPOL-Start processing to trigger WPA reauthentication
+         (previously, only EAPOL authentication was done)
+
+2005-01-02 - v0.3.3
+       * added support for EAP-PEAP in the integrated EAP authenticator
+       * added support for EAP-GTC in the integrated EAP authenticator
+       * added support for configuring list of EAP methods for Phase 1 so that
+         the integrated EAP authenticator can, e.g., use the wildcard entry
+         for EAP-TLS and EAP-PEAP
+       * added support for EAP-TTLS in the integrated EAP authenticator
+       * added support for EAP-SIM in the integrated EAP authenticator
+       * added support for using hostapd as a RADIUS authentication server
+         with the integrated EAP authenticator taking care of EAP
+         authentication (new hostapd.conf options: radius_server_clients and
+         radius_server_auth_port); this is not included in default build; use
+         CONFIG_RADIUS_SERVER=y in .config to include
+
+2004-12-19 - v0.3.2
+       * removed 'daemonize' configuration file option since it has not really
+         been used at all for more than year
+       * driver_madwifi: fixed group key setup and added get_ssid method
+       * added support for EAP-MSCHAPv2 in the integrated EAP authenticator
+
+2004-12-12 - v0.3.1
+       * added support for integrated EAP-TLS authentication (new hostapd.conf
+         variables: ca_cert, server_cert, private_key, private_key_passwd);
+         this enabled dynamic keying (WPA2/WPA/IEEE 802.1X/WEP) without
+         external RADIUS server
+       * added support for reading PKCS#12 (PFX) files (as a replacement for
+         PEM/DER) to get certificate and private key (CONFIG_PKCS12)
+
+2004-12-05 - v0.3.0 (beginning of 0.3.x development releases)
+       * added support for Acct-{Input,Output}-Gigawords
+       * added support for Event-Timestamp (in RADIUS Accounting-Requests)
+       * added support for RADIUS Authentication Client MIB (RFC2618)
+       * added support for RADIUS Accounting Client MIB (RFC2620)
+       * made EAP re-authentication period configurable (eap_reauth_period)
+       * fixed EAPOL reauthentication to trigger WPA/WPA2 reauthentication
+       * fixed EAPOL state machine to stop if STA is removed during
+         eapol_sm_step(); this fixes at least one segfault triggering bug with
+         IEEE 802.11i pre-authentication
+       * added support for multiple WPA pre-shared keys (e.g., one for each
+         client MAC address or keys shared by a group of clients);
+         new hostapd.conf field wpa_psk_file for setting path to a text file
+         containing PSKs, see hostapd.wpa_psk for an example
+       * added support for multiple driver interfaces to allow hostapd to be
+         used with other drivers
+       * added wired authenticator driver interface (driver=wired in
+         hostapd.conf, see wired.conf for example configuration)
+       * added madwifi driver interface (driver=madwifi in hostapd.conf, see
+         madwifi.conf for example configuration; Note: include files from
+         madwifi project is needed for building and a configuration file,
+         .config, needs to be created in hostapd directory with
+         CONFIG_DRIVER_MADWIFI=y to include this driver interface in hostapd
+         build)
+       * fixed an alignment issue that could cause SHA-1 to fail on some
+         platforms (e.g., Intel ixp425 with a compiler that does not 32-bit
+         align variables)
+       * fixed RADIUS reconnection after an error in sending interim
+         accounting packets
+       * added hostapd control interface for external programs and an example
+         CLI, hostapd_cli (like wpa_cli for wpa_supplicant)
+       * started adding dot11, dot1x, radius MIBs ('hostapd_cli mib',
+         'hostapd_cli sta <addr>')
+       * finished update from IEEE 802.1X-2001 to IEEE 802.1X-REV (now d11)
+       * added support for strict GTK rekeying (wpa_strict_rekey in
+         hostapd.conf)
+       * updated IAPP to use UDP port 3517 and multicast address 224.0.1.178
+         (instead of broadcast) for IAPP ADD-notify (moved from draft 3 to
+         IEEE 802.11F-2003)
+       * added Prism54 driver interface (driver=prism54 in hostapd.conf;
+         note: .config needs to be created in hostapd directory with
+         CONFIG_DRIVER_PRISM54=y to include this driver interface in hostapd
+         build)
+       * dual-licensed hostapd (GPLv2 and BSD licenses)
+       * fixed RADIUS accounting to generate a new session id for cases where
+         a station reassociates without first being complete deauthenticated
+       * fixed STA disassociation handler to mark next timeout state to
+         deauthenticate the station, i.e., skip long wait for inactivity poll
+         and extra disassociation, if the STA disassociates without
+         deauthenticating
+       * added integrated EAP authenticator that can be used instead of
+         external RADIUS authentication server; currently, only EAP-MD5 is
+         supported, so this cannot yet be used for key distribution; the EAP
+         method interface is generic, though, so adding new EAP methods should
+         be straightforward; new hostapd.conf variables: 'eap_authenticator'
+         and 'eap_user_file'; this obsoletes "minimal authentication server"
+         ('minimal_eap' in hostapd.conf) which is now removed
+       * added support for FreeBSD and driver interface for the BSD net80211
+         layer (driver=bsd in hostapd.conf and CONFIG_DRIVER_BSD=y in
+         .config); please note that some of the required kernel mods have not
+         yet been committed
+
+2004-07-17 - v0.2.4 (beginning of 0.2.x stable releases)
+       * fixed some accounting cases where Accounting-Start was sent when
+         IEEE 802.1X port was being deauthorized
+
+2004-06-20 - v0.2.3
+       * modified RADIUS client to re-connect the socket in case of certain
+         error codes that are generated when a network interface state is
+         changes (e.g., when IP address changes or the interface is set UP)
+       * fixed couple of cases where EAPOL state for a station was freed
+         twice causing a segfault for hostapd
+       * fixed couple of bugs in processing WPA deauthentication (freed data
+         was used)
+
+2004-05-31 - v0.2.2
+       * fixed WPA/WPA2 group rekeying to use key index correctly (GN/GM)
+       * fixed group rekeying to send zero TSC in EAPOL-Key messages to fix
+         cases where STAs dropped multicast frames as replay attacks
+       * added support for copying RADIUS Attribute 'Class' from
+         authentication messages into accounting messages
+       * send canned EAP failure if RADIUS server sends Access-Reject without
+         EAP message (previously, Supplicant was not notified in this case)
+       * fixed mixed WPA-PSK and WPA-EAP mode to work with WPA-PSK (i.e., do
+         not start EAPOL state machines if the STA selected to use WPA-PSK)
+
+2004-05-06 - v0.2.1
+       * added WPA and IEEE 802.11i/RSN (WPA2) Authenticator functionality
+         - based on IEEE 802.11i/D10.0 but modified to interoperate with WPA
+           (i.e., IEEE 802.11i/D3.0)
+         - supports WPA-only, RSN-only, and mixed WPA/RSN mode
+         - both WPA-PSK and WPA-RADIUS/EAP are supported
+         - PMKSA caching and pre-authentication
+         - new hostapd.conf variables: wpa, wpa_psk, wpa_passphrase,
+           wpa_key_mgmt, wpa_pairwise, wpa_group_rekey, wpa_gmk_rekey,
+           rsn_preauth, rsn_preauth_interfaces
+       * fixed interim accounting to remove any pending accounting messages
+         to the STA before sending a new one
+
+2004-02-15 - v0.2.0
+       * added support for Acct-Interim-Interval:
+         - draft-ietf-radius-acct-interim-01.txt
+         - use Acct-Interim-Interval attribute from Access-Accept if local
+           'radius_acct_interim_interval' is not set
+         - allow different update intervals for each STA
+       * fixed event loop to call signal handlers only after returning from
+         the real signal handler
+       * reset sta->timeout_next after successful association to make sure
+         that the previously registered inactivity timer will not remove the
+         STA immediately (e.g., if STA deauthenticates and re-associates
+         before the timer is triggered).
+       * added new hostapd.conf variable, nas_identifier, that can be used to
+         add an optional RADIUS Attribute, NAS-Identifier, into authentication
+         and accounting messages
+       * added support for Accounting-On and Accounting-Off messages
+       * fixed accounting session handling to send Accounting-Start only once
+         per session and not to send Accounting-Stop if the session was not
+         initialized properly
+       * fixed Accounting-Stop statistics in cases where the message was
+         previously sent after the kernel entry for the STA (and/or IEEE
+         802.1X data) was removed
+
+
+Note:
+
+Older changes up to and including v0.1.0 are included in the ChangeLog
+of the Host AP driver.
diff --git a/hostapd/Makefile b/hostapd/Makefile
new file mode 100644 (file)
index 0000000..22c09c1
--- /dev/null
@@ -0,0 +1,867 @@
+ifndef CC
+CC=gcc
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+CFLAGS += -I../src
+CFLAGS += -I../src/utils
+
+# Uncomment following line and set the path to your kernel tree include
+# directory if your C library does not include all header files.
+# CFLAGS += -DUSE_KERNEL_HEADERS -I/usr/src/linux/include
+
+-include .config
+
+ifndef CONFIG_OS
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_OS=win32
+else
+CONFIG_OS=unix
+endif
+endif
+
+ifeq ($(CONFIG_OS), internal)
+CFLAGS += -DOS_NO_C_LIB_DEFINES
+endif
+
+ifdef CONFIG_NATIVE_WINDOWS
+CFLAGS += -DCONFIG_NATIVE_WINDOWS
+LIBS += -lws2_32
+endif
+
+OBJS += main.o
+OBJS += config_file.o
+
+OBJS += ../src/ap/hostapd.o
+OBJS += ../src/ap/wpa_auth_glue.o
+OBJS += ../src/ap/drv_callbacks.o
+OBJS += ../src/ap/ap_drv_ops.o
+OBJS += ../src/ap/utils.o
+OBJS += ../src/ap/authsrv.o
+OBJS += ../src/ap/ieee802_1x.o
+OBJS += ../src/ap/ap_config.o
+OBJS += ../src/ap/ieee802_11_auth.o
+OBJS += ../src/ap/sta_info.o
+OBJS += ../src/ap/wpa_auth.o
+OBJS += ../src/ap/tkip_countermeasures.o
+OBJS += ../src/ap/ap_mlme.o
+OBJS += ../src/ap/wpa_auth_ie.o
+OBJS += ../src/ap/preauth_auth.o
+OBJS += ../src/ap/pmksa_cache_auth.o
+OBJS += ../src/ap/ieee802_11_shared.o
+OBJS += ../src/ap/beacon.o
+
+OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
+
+NEED_RC4=y
+NEED_AES=y
+NEED_MD5=y
+NEED_SHA1=y
+
+OBJS += ../src/drivers/drivers.o
+CFLAGS += -DHOSTAPD
+
+ifdef CONFIG_WPA_TRACE
+CFLAGS += -DWPA_TRACE
+OBJS += ../src/utils/trace.o
+HOBJS += ../src/utils/trace.o
+LDFLAGS += -rdynamic
+CFLAGS += -funwind-tables
+ifdef CONFIG_WPA_TRACE_BFD
+CFLAGS += -DWPA_TRACE_BFD
+LIBS += -lbfd
+LIBS_c += -lbfd
+LIBS_h += -lbfd
+endif
+endif
+
+ifndef CONFIG_ELOOP
+CONFIG_ELOOP=eloop
+endif
+OBJS += ../src/utils/$(CONFIG_ELOOP).o
+OBJS_c += ../src/utils/$(CONFIG_ELOOP).o
+OBJS += ../src/utils/common.o
+OBJS += ../src/utils/wpa_debug.o
+OBJS_c += ../src/utils/wpa_debug.o
+OBJS += ../src/utils/wpabuf.o
+OBJS += ../src/utils/os_$(CONFIG_OS).o
+OBJS += ../src/utils/ip_addr.o
+
+OBJS += ../src/common/ieee802_11_common.o
+OBJS += ../src/common/wpa_common.o
+
+OBJS += ../src/eapol_auth/eapol_auth_sm.o
+
+
+ifndef CONFIG_NO_DUMP_STATE
+# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to
+# a file (undefine it, if you want to save in binary size)
+CFLAGS += -DHOSTAPD_DUMP_STATE
+OBJS += dump_state.o
+OBJS += ../src/eapol_auth/eapol_auth_dump.o
+endif
+
+ifdef CONFIG_NO_RADIUS
+CFLAGS += -DCONFIG_NO_RADIUS
+CONFIG_NO_ACCOUNTING=y
+else
+OBJS += ../src/radius/radius.o
+OBJS += ../src/radius/radius_client.o
+endif
+
+ifdef CONFIG_NO_ACCOUNTING
+CFLAGS += -DCONFIG_NO_ACCOUNTING
+else
+OBJS += ../src/ap/accounting.o
+endif
+
+ifdef CONFIG_NO_VLAN
+CFLAGS += -DCONFIG_NO_VLAN
+else
+OBJS += ../src/ap/vlan_init.o
+endif
+
+ifdef CONFIG_NO_CTRL_IFACE
+CFLAGS += -DCONFIG_NO_CTRL_IFACE
+else
+OBJS += ctrl_iface.o
+OBJS += ../src/ap/ctrl_iface_ap.o
+endif
+
+OBJS += ../src/crypto/md5.o
+
+CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
+
+ifdef CONFIG_IAPP
+CFLAGS += -DCONFIG_IAPP
+OBJS += ../src/ap/iapp.o
+endif
+
+ifdef CONFIG_RSN_PREAUTH
+CFLAGS += -DCONFIG_RSN_PREAUTH
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_PEERKEY
+CFLAGS += -DCONFIG_PEERKEY
+OBJS += ../src/ap/peerkey_auth.o
+endif
+
+ifdef CONFIG_IEEE80211W
+CFLAGS += -DCONFIG_IEEE80211W
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_IEEE80211R
+CFLAGS += -DCONFIG_IEEE80211R
+OBJS += ../src/ap/wpa_auth_ft.o
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+NEED_AES_UNWRAP=y
+endif
+
+ifdef CONFIG_IEEE80211N
+CFLAGS += -DCONFIG_IEEE80211N
+endif
+
+include ../src/drivers/drivers.mak
+OBJS += $(DRV_AP_OBJS)
+CFLAGS += $(DRV_AP_CFLAGS)
+LDFLAGS += $(DRV_AP_LDFLAGS)
+LIBS += $(DRV_AP_LIBS)
+
+ifdef CONFIG_L2_PACKET
+ifdef CONFIG_DNET_PCAP
+ifdef CONFIG_L2_FREEBSD
+LIBS += -lpcap
+OBJS += ../src/l2_packet/l2_packet_freebsd.o
+else
+LIBS += -ldnet -lpcap
+OBJS += ../src/l2_packet/l2_packet_pcap.o
+endif
+else
+OBJS += ../src/l2_packet/l2_packet_linux.o
+endif
+else
+OBJS += ../src/l2_packet/l2_packet_none.o
+endif
+
+
+ifdef CONFIG_EAP_MD5
+CFLAGS += -DEAP_SERVER_MD5
+OBJS += ../src/eap_server/eap_server_md5.o
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_TLS
+CFLAGS += -DEAP_SERVER_TLS
+OBJS += ../src/eap_server/eap_server_tls.o
+TLS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_PEAP
+CFLAGS += -DEAP_SERVER_PEAP
+OBJS += ../src/eap_server/eap_server_peap.o
+OBJS += ../src/eap_common/eap_peap_common.o
+TLS_FUNCS=y
+CONFIG_EAP_MSCHAPV2=y
+endif
+
+ifdef CONFIG_EAP_TTLS
+CFLAGS += -DEAP_SERVER_TTLS
+OBJS += ../src/eap_server/eap_server_ttls.o
+TLS_FUNCS=y
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_MSCHAPV2
+CFLAGS += -DEAP_SERVER_MSCHAPV2
+OBJS += ../src/eap_server/eap_server_mschapv2.o
+MS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_GTC
+CFLAGS += -DEAP_SERVER_GTC
+OBJS += ../src/eap_server/eap_server_gtc.o
+endif
+
+ifdef CONFIG_EAP_SIM
+CFLAGS += -DEAP_SERVER_SIM
+OBJS += ../src/eap_server/eap_server_sim.o
+CONFIG_EAP_SIM_COMMON=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_AKA
+CFLAGS += -DEAP_SERVER_AKA
+OBJS += ../src/eap_server/eap_server_aka.o
+CONFIG_EAP_SIM_COMMON=y
+NEED_SHA256=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_AKA_PRIME
+CFLAGS += -DEAP_SERVER_AKA_PRIME
+endif
+
+ifdef CONFIG_EAP_SIM_COMMON
+OBJS += ../src/eap_common/eap_sim_common.o
+# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
+# replaced with another file implementating the interface specified in
+# eap_sim_db.h.
+OBJS += ../src/eap_server/eap_sim_db.o
+NEED_FIPS186_2_PRF=y
+endif
+
+ifdef CONFIG_EAP_PAX
+CFLAGS += -DEAP_SERVER_PAX
+OBJS += ../src/eap_server/eap_server_pax.o ../src/eap_common/eap_pax_common.o
+endif
+
+ifdef CONFIG_EAP_PSK
+CFLAGS += -DEAP_SERVER_PSK
+OBJS += ../src/eap_server/eap_server_psk.o ../src/eap_common/eap_psk_common.o
+NEED_AES_OMAC1=y
+NEED_AES_ENCBLOCK=y
+NEED_AES_EAX=y
+endif
+
+ifdef CONFIG_EAP_SAKE
+CFLAGS += -DEAP_SERVER_SAKE
+OBJS += ../src/eap_server/eap_server_sake.o ../src/eap_common/eap_sake_common.o
+endif
+
+ifdef CONFIG_EAP_GPSK
+CFLAGS += -DEAP_SERVER_GPSK
+OBJS += ../src/eap_server/eap_server_gpsk.o ../src/eap_common/eap_gpsk_common.o
+ifdef CONFIG_EAP_GPSK_SHA256
+CFLAGS += -DEAP_SERVER_GPSK_SHA256
+endif
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_EAP_PWD
+CFLAGS += -DEAP_SERVER_PWD
+OBJS += ../src/eap_server/eap_server_pwd.o ../src/eap_common/eap_pwd_common.o
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_EAP_VENDOR_TEST
+CFLAGS += -DEAP_SERVER_VENDOR_TEST
+OBJS += ../src/eap_server/eap_server_vendor_test.o
+endif
+
+ifdef CONFIG_EAP_FAST
+CFLAGS += -DEAP_SERVER_FAST
+OBJS += ../src/eap_server/eap_server_fast.o
+OBJS += ../src/eap_common/eap_fast_common.o
+TLS_FUNCS=y
+NEED_T_PRF=y
+NEED_AES_UNWRAP=y
+endif
+
+ifdef CONFIG_WPS
+ifdef CONFIG_WPS2
+CFLAGS += -DCONFIG_WPS2
+endif
+
+CFLAGS += -DCONFIG_WPS -DEAP_SERVER_WSC
+OBJS += ../src/utils/uuid.o
+OBJS += ../src/ap/wps_hostapd.o
+OBJS += ../src/eap_server/eap_server_wsc.o ../src/eap_common/eap_wsc_common.o
+OBJS += ../src/wps/wps.o
+OBJS += ../src/wps/wps_common.o
+OBJS += ../src/wps/wps_attr_parse.o
+OBJS += ../src/wps/wps_attr_build.o
+OBJS += ../src/wps/wps_attr_process.o
+OBJS += ../src/wps/wps_dev_attr.o
+OBJS += ../src/wps/wps_enrollee.o
+OBJS += ../src/wps/wps_registrar.o
+NEED_DH_GROUPS=y
+NEED_SHA256=y
+NEED_BASE64=y
+NEED_AES_CBC=y
+NEED_MODEXP=y
+CONFIG_EAP=y
+
+ifdef CONFIG_WPS_UFD
+CFLAGS += -DCONFIG_WPS_UFD
+OBJS += ../src/wps/wps_ufd.o
+NEED_WPS_OOB=y
+endif
+
+ifdef CONFIG_WPS_NFC
+CFLAGS += -DCONFIG_WPS_NFC
+OBJS += ../src/wps/ndef.o
+OBJS += ../src/wps/wps_nfc.o
+NEED_WPS_OOB=y
+ifdef CONFIG_WPS_NFC_PN531
+PN531_PATH ?= /usr/local/src/nfc
+CFLAGS += -DCONFIG_WPS_NFC_PN531
+CFLAGS += -I${PN531_PATH}/inc
+OBJS += ../src/wps/wps_nfc_pn531.o
+LIBS += ${PN531_PATH}/lib/wpsnfc.dll
+LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
+endif
+endif
+
+ifdef NEED_WPS_OOB
+CFLAGS += -DCONFIG_WPS_OOB
+endif
+
+ifdef CONFIG_WPS_UPNP
+CFLAGS += -DCONFIG_WPS_UPNP
+OBJS += ../src/wps/wps_upnp.o
+OBJS += ../src/wps/wps_upnp_ssdp.o
+OBJS += ../src/wps/wps_upnp_web.o
+OBJS += ../src/wps/wps_upnp_event.o
+OBJS += ../src/wps/wps_upnp_ap.o
+OBJS += ../src/wps/upnp_xml.o
+OBJS += ../src/wps/httpread.o
+OBJS += ../src/wps/http_client.o
+OBJS += ../src/wps/http_server.o
+endif
+
+ifdef CONFIG_WPS_STRICT
+CFLAGS += -DCONFIG_WPS_STRICT
+OBJS += ../src/wps/wps_validate.o
+endif
+
+ifdef CONFIG_WPS_TESTING
+CFLAGS += -DCONFIG_WPS_TESTING
+endif
+
+endif
+
+ifdef CONFIG_EAP_IKEV2
+CFLAGS += -DEAP_SERVER_IKEV2
+OBJS += ../src/eap_server/eap_server_ikev2.o ../src/eap_server/ikev2.o
+OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+NEED_MODEXP=y
+NEED_CIPHER=y
+endif
+
+ifdef CONFIG_EAP_TNC
+CFLAGS += -DEAP_SERVER_TNC
+OBJS += ../src/eap_server/eap_server_tnc.o
+OBJS += ../src/eap_server/tncs.o
+NEED_BASE64=y
+ifndef CONFIG_DRIVER_BSD
+LIBS += -ldl
+endif
+endif
+
+# Basic EAP functionality is needed for EAPOL
+OBJS += eap_register.o
+OBJS += ../src/eap_server/eap_server.o
+OBJS += ../src/eap_common/eap_common.o
+OBJS += ../src/eap_server/eap_server_methods.o
+OBJS += ../src/eap_server/eap_server_identity.o
+CFLAGS += -DEAP_SERVER_IDENTITY
+
+ifdef CONFIG_EAP
+CFLAGS += -DEAP_SERVER
+endif
+
+ifdef CONFIG_PKCS12
+CFLAGS += -DPKCS12_FUNCS
+endif
+
+ifdef MS_FUNCS
+OBJS += ../src/crypto/ms_funcs.o
+NEED_DES=y
+NEED_MD4=y
+endif
+
+ifdef CHAP
+OBJS += ../src/eap_common/chap.o
+endif
+
+ifdef TLS_FUNCS
+NEED_DES=y
+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
+CFLAGS += -DEAP_TLS_FUNCS
+OBJS += ../src/eap_server/eap_server_tls_common.o
+NEED_TLS_PRF=y
+endif
+
+ifndef CONFIG_TLS
+CONFIG_TLS=openssl
+endif
+
+ifdef CONFIG_TLSV11
+CFLAGS += -DCONFIG_TLSV11
+endif
+
+ifdef CONFIG_TLSV12
+CFLAGS += -DCONFIG_TLSV12
+NEED_SHA256=y
+endif
+
+ifeq ($(CONFIG_TLS), openssl)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_openssl.o
+LIBS += -lssl
+endif
+OBJS += ../src/crypto/crypto_openssl.o
+HOBJS += ../src/crypto/crypto_openssl.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_openssl.o
+endif
+LIBS += -lcrypto
+LIBS_h += -lcrypto
+endif
+
+ifeq ($(CONFIG_TLS), gnutls)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_gnutls.o
+LIBS += -lgnutls -lgpg-error
+endif
+OBJS += ../src/crypto/crypto_gnutls.o
+HOBJS += ../src/crypto/crypto_gnutls.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_gnutls.o
+endif
+LIBS += -lgcrypt
+LIBS_h += -lgcrypt
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), schannel)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_schannel.o
+endif
+OBJS += ../src/crypto/crypto_cryptoapi.o
+OBJS_p += ../src/crypto/crypto_cryptoapi.o
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), nss)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_nss.o
+LIBS += -lssl3
+endif
+OBJS += ../src/crypto/crypto_nss.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_nss.o
+endif
+LIBS += -lnss3
+LIBS_h += -lnss3
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), internal)
+ifndef CONFIG_CRYPTO
+CONFIG_CRYPTO=internal
+endif
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/crypto_internal-rsa.o
+OBJS += ../src/crypto/tls_internal.o
+OBJS += ../src/tls/tlsv1_common.o
+OBJS += ../src/tls/tlsv1_record.o
+OBJS += ../src/tls/tlsv1_cred.o
+OBJS += ../src/tls/tlsv1_server.o
+OBJS += ../src/tls/tlsv1_server_write.o
+OBJS += ../src/tls/tlsv1_server_read.o
+OBJS += ../src/tls/asn1.o
+OBJS += ../src/tls/rsa.o
+OBJS += ../src/tls/x509v3.o
+OBJS += ../src/tls/pkcs1.o
+OBJS += ../src/tls/pkcs5.o
+OBJS += ../src/tls/pkcs8.o
+NEED_SHA256=y
+NEED_BASE64=y
+NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
+NEED_MODEXP=y
+NEED_CIPHER=y
+CFLAGS += -DCONFIG_TLS_INTERNAL
+CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
+endif
+ifdef NEED_CIPHER
+NEED_DES=y
+OBJS += ../src/crypto/crypto_internal-cipher.o
+endif
+ifdef NEED_MODEXP
+OBJS += ../src/crypto/crypto_internal-modexp.o
+OBJS += ../src/tls/bignum.o
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+OBJS += ../src/crypto/crypto_libtomcrypt.o
+LIBS += -ltomcrypt -ltfm
+LIBS_h += -ltomcrypt -ltfm
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+OBJS += ../src/crypto/crypto_internal.o
+NEED_AES_DEC=y
+CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+ifdef CONFIG_INTERNAL_LIBTOMMATH
+CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST
+CFLAGS += -DLTM_FAST
+endif
+else
+LIBS += -ltommath
+LIBS_h += -ltommath
+endif
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_DES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+OBJS += ../src/crypto/crypto_cryptoapi.o
+OBJS_p += ../src/crypto/crypto_cryptoapi.o
+CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+ifeq ($(CONFIG_TLS), none)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_none.o
+CFLAGS += -DEAP_TLS_NONE
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+endif
+OBJS += ../src/crypto/crypto_none.o
+OBJS_p += ../src/crypto/crypto_none.o
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+
+ifndef TLS_FUNCS
+OBJS += ../src/crypto/tls_none.o
+ifeq ($(CONFIG_TLS), internal)
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+AESOBJS = # none so far
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-enc.o
+endif
+
+AESOBJS += ../src/crypto/aes-wrap.o
+ifdef NEED_AES_EAX
+AESOBJS += ../src/crypto/aes-eax.o
+NEED_AES_CTR=y
+endif
+ifdef NEED_AES_CTR
+AESOBJS += ../src/crypto/aes-ctr.o
+endif
+ifdef NEED_AES_ENCBLOCK
+AESOBJS += ../src/crypto/aes-encblock.o
+endif
+ifdef NEED_AES_OMAC1
+AESOBJS += ../src/crypto/aes-omac1.o
+endif
+ifdef NEED_AES_UNWRAP
+NEED_AES_DEC=y
+AESOBJS += ../src/crypto/aes-unwrap.o
+endif
+ifdef NEED_AES_CBC
+NEED_AES_DEC=y
+AESOBJS += ../src/crypto/aes-cbc.o
+endif
+ifdef NEED_AES_DEC
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += ../src/crypto/aes-internal-dec.o
+endif
+endif
+ifdef NEED_AES
+OBJS += $(AESOBJS)
+endif
+
+ifdef NEED_SHA1
+SHA1OBJS += ../src/crypto/sha1.o
+ifdef CONFIG_INTERNAL_SHA1
+SHA1OBJS += ../src/crypto/sha1-internal.o
+ifdef NEED_FIPS186_2_PRF
+SHA1OBJS += ../src/crypto/fips_prf_internal.o
+endif
+endif
+SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
+ifdef NEED_T_PRF
+SHA1OBJS += ../src/crypto/sha1-tprf.o
+endif
+ifdef NEED_TLS_PRF
+SHA1OBJS += ../src/crypto/sha1-tlsprf.o
+endif
+endif
+
+ifdef NEED_SHA1
+OBJS += $(SHA1OBJS)
+endif
+
+ifdef NEED_MD5
+ifdef CONFIG_INTERNAL_MD5
+OBJS += ../src/crypto/md5-internal.o
+HOBJS += ../src/crypto/md5-internal.o
+endif
+endif
+
+ifdef NEED_MD4
+ifdef CONFIG_INTERNAL_MD4
+OBJS += ../src/crypto/md4-internal.o
+endif
+endif
+
+ifdef NEED_DES
+ifdef CONFIG_INTERNAL_DES
+OBJS += ../src/crypto/des-internal.o
+endif
+endif
+
+ifdef NEED_RC4
+ifdef CONFIG_INTERNAL_RC4
+OBJS += ../src/crypto/rc4.o
+endif
+endif
+
+ifdef NEED_SHA256
+CFLAGS += -DCONFIG_SHA256
+OBJS += ../src/crypto/sha256.o
+ifdef CONFIG_INTERNAL_SHA256
+OBJS += ../src/crypto/sha256-internal.o
+endif
+ifdef NEED_TLS_PRF_SHA256
+OBJS += ../src/crypto/sha256-tlsprf.o
+endif
+endif
+
+ifdef NEED_DH_GROUPS
+OBJS += ../src/crypto/dh_groups.o
+endif
+ifdef NEED_DH_GROUPS_ALL
+CFLAGS += -DALL_DH_GROUPS
+endif
+ifdef CONFIG_INTERNAL_DH_GROUP5
+ifdef NEED_DH_GROUPS
+OBJS += ../src/crypto/dh_group5.o
+endif
+endif
+
+ifdef CONFIG_NO_RANDOM_POOL
+CFLAGS += -DCONFIG_NO_RANDOM_POOL
+else
+OBJS += ../src/crypto/random.o
+HOBJS += ../src/crypto/random.o
+HOBJS += ../src/utils/eloop.o
+HOBJS += $(SHA1OBJS)
+HOBJS += ../src/crypto/md5.o
+endif
+
+ifdef CONFIG_RADIUS_SERVER
+CFLAGS += -DRADIUS_SERVER
+OBJS += ../src/radius/radius_server.o
+endif
+
+ifdef CONFIG_IPV6
+CFLAGS += -DCONFIG_IPV6
+endif
+
+ifdef CONFIG_DRIVER_RADIUS_ACL
+CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL
+endif
+
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+# define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges
+# and vlan interfaces for the vlan feature.
+CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN
+endif
+
+ifdef NEED_BASE64
+OBJS += ../src/utils/base64.o
+endif
+
+ifdef NEED_AP_MLME
+OBJS += ../src/ap/wmm.o
+OBJS += ../src/ap/ap_list.o
+OBJS += ../src/ap/ieee802_11.o
+OBJS += ../src/ap/hw_features.o
+CFLAGS += -DNEED_AP_MLME
+endif
+ifdef CONFIG_IEEE80211N
+OBJS += ../src/ap/ieee802_11_ht.o
+endif
+
+ifdef CONFIG_P2P_MANAGER
+CFLAGS += -DCONFIG_P2P_MANAGER
+OBJS += ../src/ap/p2p_hostapd.o
+endif
+
+ifdef CONFIG_INTERWORKING
+CFLAGS += -DCONFIG_INTERWORKING
+endif
+
+OBJS += ../src/drivers/driver_common.o
+
+ifdef CONFIG_WPA_CLI_EDIT
+OBJS_c += ../src/utils/edit.o
+else
+OBJS_c += ../src/utils/edit_simple.o
+endif
+
+ifdef CONFIG_NO_STDOUT_DEBUG
+CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
+endif
+
+ifdef CONFIG_DEBUG_FILE
+CFLAGS += -DCONFIG_DEBUG_FILE
+endif
+
+ALL=hostapd hostapd_cli
+
+all: verify_config $(ALL)
+
+Q=@
+E=echo
+ifeq ($(V), 1)
+Q=
+E=true
+endif
+
+%.o: %.c
+       $(Q)$(CC) -c -o $@ $(CFLAGS) $<
+       @$(E) "  CC " $<
+
+verify_config:
+       @if [ ! -r .config ]; then \
+               echo 'Building hostapd requires a configuration file'; \
+               echo '(.config). See README for more instructions. You can'; \
+               echo 'run "cp defconfig .config" to create an example'; \
+               echo 'configuration.'; \
+               exit 1; \
+       fi
+
+install: all
+       mkdir -p $(DESTDIR)/usr/local/bin
+       for i in $(ALL); do cp -f $$i $(DESTDIR)/usr/local/bin/$$i; done
+
+../src/drivers/build.hostapd:
+       @if [ -f ../src/drivers/build.wpa_supplicant ]; then \
+               $(MAKE) -C ../src/drivers clean; \
+       fi
+       @touch ../src/drivers/build.hostapd
+
+BCHECK=../src/drivers/build.hostapd
+
+hostapd: $(BCHECK) $(OBJS)
+       $(Q)$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS)
+       @$(E) "  LD " $@
+
+ifdef CONFIG_WPA_TRACE
+OBJS_c += ../src/utils/trace.o
+endif
+hostapd_cli: $(OBJS_c)
+       $(Q)$(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c) $(LIBS_c)
+       @$(E) "  LD " $@
+
+NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o $(SHA1OBJS) ../src/crypto/md5.o
+ifdef NEED_RC4
+ifdef CONFIG_INTERNAL_RC4
+NOBJS += ../src/crypto/rc4.o
+endif
+endif
+ifdef CONFIG_INTERNAL_MD5
+NOBJS += ../src/crypto/md5-internal.o
+endif
+NOBJS += ../src/crypto/crypto_openssl.o ../src/utils/os_$(CONFIG_OS).o
+NOBJS += ../src/utils/wpa_debug.o
+NOBJS += ../src/utils/wpabuf.o
+ifdef CONFIG_WPA_TRACE
+NOBJS += ../src/utils/trace.o
+LIBS_n += -lbfd
+endif
+ifdef TLS_FUNCS
+LIBS_n += -lcrypto
+endif
+
+HOBJS += hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/utils/wpabuf.o ../src/crypto/milenage.o
+HOBJS += ../src/crypto/aes-encblock.o
+ifdef CONFIG_INTERNAL_AES
+HOBJS += ../src/crypto/aes-internal.o
+HOBJS += ../src/crypto/aes-internal-enc.o
+endif
+
+nt_password_hash: $(NOBJS)
+       $(Q)$(CC) $(LDFLAGS) -o nt_password_hash $(NOBJS) $(LIBS_n)
+       @$(E) "  LD " $@
+
+hlr_auc_gw: $(HOBJS)
+       $(Q)$(CC) $(LDFLAGS) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
+       @$(E) "  LD " $@
+
+clean:
+       $(MAKE) -C ../src clean
+       rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw
+       rm -f *.d
+
+-include $(OBJS:%.o=%.d)
diff --git a/hostapd/README b/hostapd/README
new file mode 100644 (file)
index 0000000..a211cdd
--- /dev/null
@@ -0,0 +1,387 @@
+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
+All Rights Reserved.
+
+This program is dual-licensed under both the GPL version 2 and BSD
+license. Either license may be used at your option.
+
+
+
+License
+-------
+
+GPL v2:
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+(this copy of the license is in COPYING file)
+
+
+Alternatively, this software may be distributed, used, and modified
+under the terms of BSD license:
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. Neither the name(s) of the above-listed copyright holder(s) nor the
+   names of its contributors may be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+Introduction
+============
+
+Originally, hostapd was an optional user space component for Host AP
+driver. It adds more features to the basic IEEE 802.11 management
+included in the kernel driver: using external RADIUS authentication
+server for MAC address based access control, IEEE 802.1X Authenticator
+and dynamic WEP keying, RADIUS accounting, WPA/WPA2 (IEEE 802.11i/RSN)
+Authenticator and dynamic TKIP/CCMP keying.
+
+The current version includes support for other drivers, an integrated
+EAP server (i.e., allow full authentication without requiring
+an external RADIUS authentication server), and RADIUS authentication
+server for EAP authentication.
+
+
+Requirements
+------------
+
+Current hardware/software requirements:
+- drivers:
+       Host AP driver for Prism2/2.5/3.
+       (http://hostap.epitest.fi/)
+       Please note that station firmware version needs to be 1.7.0 or newer
+       to work in WPA mode.
+
+       madwifi driver for cards based on Atheros chip set (ar521x)
+       (http://sourceforge.net/projects/madwifi/)
+       Please note that you will need to add the correct path for
+       madwifi driver root directory in .config (see defconfig file for
+       an example: CFLAGS += -I<path>)
+
+       mac80211-based drivers that support AP mode (with driver=nl80211).
+       This includes drivers for Atheros (ath9k) and Broadcom (b43)
+       chipsets.
+
+       Any wired Ethernet driver for wired IEEE 802.1X authentication
+       (experimental code)
+
+       FreeBSD -current (with some kernel mods that have not yet been
+       committed when hostapd v0.3.0 was released)
+       BSD net80211 layer (e.g., Atheros driver)
+
+
+Build configuration
+-------------------
+
+In order to be able to build hostapd, you will need to create a build
+time configuration file, .config that selects which optional
+components are included. See defconfig file for example configuration
+and list of available options.
+
+
+
+IEEE 802.1X
+===========
+
+IEEE Std 802.1X-2001 is a standard for port-based network access
+control. In case of IEEE 802.11 networks, a "virtual port" is used
+between each associated station and the AP. IEEE 802.11 specifies
+minimal authentication mechanism for stations, whereas IEEE 802.1X
+introduces a extensible mechanism for authenticating and authorizing
+users.
+
+IEEE 802.1X uses elements called Supplicant, Authenticator, Port
+Access Entity, and Authentication Server. Supplicant is a component in
+a station and it performs the authentication with the Authentication
+Server. An access point includes an Authenticator that relays the packets
+between a Supplicant and an Authentication Server. In addition, it has a
+Port Access Entity (PAE) with Authenticator functionality for
+controlling the virtual port authorization, i.e., whether to accept
+packets from or to the station.
+
+IEEE 802.1X uses Extensible Authentication Protocol (EAP). The frames
+between a Supplicant and an Authenticator are sent using EAP over LAN
+(EAPOL) and the Authenticator relays these frames to the Authentication
+Server (and similarly, relays the messages from the Authentication
+Server to the Supplicant). The Authentication Server can be colocated with the
+Authenticator, in which case there is no need for additional protocol
+for EAP frame transmission. However, a more common configuration is to
+use an external Authentication Server and encapsulate EAP frame in the
+frames used by that server. RADIUS is suitable for this, but IEEE
+802.1X would also allow other mechanisms.
+
+Host AP driver includes PAE functionality in the kernel driver. It
+is a relatively simple mechanism for denying normal frames going to
+or coming from an unauthorized port. PAE allows IEEE 802.1X related
+frames to be passed between the Supplicant and the Authenticator even
+on an unauthorized port.
+
+User space daemon, hostapd, includes Authenticator functionality. It
+receives 802.1X (EAPOL) frames from the Supplicant using the wlan#ap
+device that is also used with IEEE 802.11 management frames. The
+frames to the Supplicant are sent using the same device.
+
+The normal configuration of the Authenticator would use an external
+Authentication Server. hostapd supports RADIUS encapsulation of EAP
+packets, so the Authentication Server should be a RADIUS server, like
+FreeRADIUS (http://www.freeradius.org/). The Authenticator in hostapd
+relays the frames between the Supplicant and the Authentication
+Server. It also controls the PAE functionality in the kernel driver by
+controlling virtual port authorization, i.e., station-AP
+connection, based on the IEEE 802.1X state.
+
+When a station would like to use the services of an access point, it
+will first perform IEEE 802.11 authentication. This is normally done
+with open systems authentication, so there is no security. After
+this, IEEE 802.11 association is performed. If IEEE 802.1X is
+configured to be used, the virtual port for the station is set in
+Unauthorized state and only IEEE 802.1X frames are accepted at this
+point. The Authenticator will then ask the Supplicant to authenticate
+with the Authentication Server. After this is completed successfully,
+the virtual port is set to Authorized state and frames from and to the
+station are accepted.
+
+Host AP configuration for IEEE 802.1X
+-------------------------------------
+
+The user space daemon has its own configuration file that can be used to
+define AP options. Distribution package contains an example
+configuration file (hostapd/hostapd.conf) that can be used as a basis
+for configuration. It includes examples of all supported configuration
+options and short description of each option. hostapd should be started
+with full path to the configuration file as the command line argument,
+e.g., './hostapd /etc/hostapd.conf'. If you have more that one wireless
+LAN card, you can use one hostapd process for multiple interfaces by
+giving a list of configuration files (one per interface) in the command
+line.
+
+hostapd includes a minimal co-located IEEE 802.1X server which can be
+used to test IEEE 802.1X authentication. However, it should not be
+used in normal use since it does not provide any security. This can be
+configured by setting ieee8021x and minimal_eap options in the
+configuration file.
+
+An external Authentication Server (RADIUS) is configured with
+auth_server_{addr,port,shared_secret} options. In addition,
+ieee8021x and own_ip_addr must be set for this mode. With such
+configuration, the co-located Authentication Server is not used and EAP
+frames will be relayed using EAPOL between the Supplicant and the
+Authenticator and RADIUS encapsulation between the Authenticator and
+the Authentication Server. Other than this, the functionality is similar
+to the case with the co-located Authentication Server.
+
+Authentication Server and Supplicant
+------------------------------------
+
+Any RADIUS server supporting EAP should be usable as an IEEE 802.1X
+Authentication Server with hostapd Authenticator. FreeRADIUS
+(http://www.freeradius.org/) has been successfully tested with hostapd
+Authenticator and both Xsupplicant (http://www.open1x.org) and Windows
+XP Supplicants. EAP/TLS was used with Xsupplicant and
+EAP/MD5-Challenge with Windows XP.
+
+http://www.missl.cs.umd.edu/wireless/eaptls/ has useful information
+about using EAP/TLS with FreeRADIUS and Xsupplicant (just replace
+Cisco access point with Host AP driver, hostapd daemon, and a Prism2
+card ;-). http://www.freeradius.org/doc/EAP-MD5.html has information
+about using EAP/MD5 with FreeRADIUS, including instructions for WinXP
+configuration. http://www.denobula.com/EAPTLS.pdf has a HOWTO on
+EAP/TLS use with WinXP Supplicant.
+
+Automatic WEP key configuration
+-------------------------------
+
+EAP/TLS generates a session key that can be used to send WEP keys from
+an AP to authenticated stations. The Authenticator in hostapd can be
+configured to automatically select a random default/broadcast key
+(shared by all authenticated stations) with wep_key_len_broadcast
+option (5 for 40-bit WEP or 13 for 104-bit WEP). In addition,
+wep_key_len_unicast option can be used to configure individual unicast
+keys for stations. This requires support for individual keys in the
+station driver.
+
+WEP keys can be automatically updated by configuring rekeying. This
+will improve security of the network since same WEP key will only be
+used for a limited period of time. wep_rekey_period option sets the
+interval for rekeying in seconds.
+
+
+WPA/WPA2
+========
+
+Features
+--------
+
+Supported WPA/IEEE 802.11i features:
+- WPA-PSK ("WPA-Personal")
+- WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise")
+- key management for CCMP, TKIP, WEP104, WEP40
+- RSN/WPA2 (IEEE 802.11i), including PMKSA caching and pre-authentication
+
+WPA
+---
+
+The original security mechanism of IEEE 802.11 standard was not
+designed to be strong and has proved to be insufficient for most
+networks that require some kind of security. Task group I (Security)
+of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked
+to address the flaws of the base standard and has in practice
+completed its work in May 2004. The IEEE 802.11i amendment to the IEEE
+802.11 standard was approved in June 2004 and this amendment is likely
+to be published in July 2004.
+
+Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the
+IEEE 802.11i work (draft 3.0) to define a subset of the security
+enhancements that can be implemented with existing wlan hardware. This
+is called Wi-Fi Protected Access<TM> (WPA). This has now become a
+mandatory component of interoperability testing and certification done
+by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web
+site (http://www.wi-fi.org/OpenSection/protected_access.asp).
+
+IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm
+for protecting wireless networks. WEP uses RC4 with 40-bit keys,
+24-bit initialization vector (IV), and CRC32 to protect against packet
+forgery. All these choices have proven to be insufficient: key space is
+too small against current attacks, RC4 key scheduling is insufficient
+(beginning of the pseudorandom stream should be skipped), IV space is
+too small and IV reuse makes attacks easier, there is no replay
+protection, and non-keyed authentication does not protect against bit
+flipping packet data.
+
+WPA is an intermediate solution for the security issues. It uses
+Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a
+compromise on strong security and possibility to use existing
+hardware. It still uses RC4 for the encryption like WEP, but with
+per-packet RC4 keys. In addition, it implements replay protection,
+keyed packet authentication mechanism (Michael MIC).
+
+Keys can be managed using two different mechanisms. WPA can either use
+an external authentication server (e.g., RADIUS) and EAP just like
+IEEE 802.1X is using or pre-shared keys without need for additional
+servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal",
+respectively. Both mechanisms will generate a master session key for
+the Authenticator (AP) and Supplicant (client station).
+
+WPA implements a new key handshake (4-Way Handshake and Group Key
+Handshake) for generating and exchanging data encryption keys between
+the Authenticator and Supplicant. This handshake is also used to
+verify that both Authenticator and Supplicant know the master session
+key. These handshakes are identical regardless of the selected key
+management mechanism (only the method for generating master session
+key changes).
+
+
+IEEE 802.11i / WPA2
+-------------------
+
+The design for parts of IEEE 802.11i that were not included in WPA has
+finished (May 2004) and this amendment to IEEE 802.11 was approved in
+June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new
+version of WPA called WPA2. This includes, e.g., support for more
+robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC)
+to replace TKIP and optimizations for handoff (reduced number of
+messages in initial key handshake, pre-authentication, and PMKSA caching).
+
+Some wireless LAN vendors are already providing support for CCMP in
+their WPA products. There is no "official" interoperability
+certification for CCMP and/or mixed modes using both TKIP and CCMP, so
+some interoperability issues can be expected even though many
+combinations seem to be working with equipment from different vendors.
+Testing for WPA2 is likely to start during the second half of 2004.
+
+hostapd configuration for WPA/WPA2
+----------------------------------
+
+TODO
+
+# Enable WPA. Setting this variable configures the AP to require WPA (either
+# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
+# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
+# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
+# RADIUS authentication server must be configured, and WPA-EAP must be included
+# in wpa_key_mgmt.
+# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
+# and/or WPA2 (full IEEE 802.11i/RSN):
+# bit0 = WPA
+# bit1 = IEEE 802.11i/RSN (WPA2)
+#wpa=1
+
+# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
+# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
+# (8..63 characters) that will be converted to PSK. This conversion uses SSID
+# so the PSK changes when ASCII passphrase is used and the SSID is changed.
+#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+#wpa_passphrase=secret passphrase
+
+# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
+# entries are separated with a space.
+#wpa_key_mgmt=WPA-PSK WPA-EAP
+
+# Set of accepted cipher suites (encryption algorithms) for pairwise keys
+# (unicast packets). This is a space separated list of algorithms:
+# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i]
+# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i]
+# Group cipher suite (encryption algorithm for broadcast and multicast frames)
+# is automatically selected based on this configuration. If only CCMP is
+# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
+# TKIP will be used as the group cipher.
+#wpa_pairwise=TKIP CCMP
+
+# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
+# seconds.
+#wpa_group_rekey=600
+
+# Time interval for rekeying GMK (master key used internally to generate GTKs
+# (in seconds).
+#wpa_gmk_rekey=86400
+
+# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
+# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
+# authentication and key handshake before actually associating with a new AP.
+#rsn_preauth=1
+#
+# Space separated list of interfaces from which pre-authentication frames are
+# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all
+# interface that are used for connections to other APs. This could include
+# wired interfaces and WDS links. The normal wireless data interface towards
+# associated stations (e.g., wlan0) should not be added, since
+# pre-authentication is only used with APs other than the currently associated
+# one.
+#rsn_preauth_interfaces=eth0
diff --git a/hostapd/README-WPS b/hostapd/README-WPS
new file mode 100644 (file)
index 0000000..17988d4
--- /dev/null
@@ -0,0 +1,291 @@
+hostapd and Wi-Fi Protected Setup (WPS)
+=======================================
+
+This document describes how the WPS implementation in hostapd can be
+configured and how an external component on an AP (e.g., web UI) is
+used to enable enrollment of client devices.
+
+
+Introduction to WPS
+-------------------
+
+Wi-Fi Protected Setup (WPS) is a mechanism for easy configuration of a
+wireless network. It allows automated generation of random keys (WPA
+passphrase/PSK) and configuration of an access point and client
+devices. WPS includes number of methods for setting up connections
+with PIN method and push-button configuration (PBC) being the most
+commonly deployed options.
+
+While WPS can enable more home networks to use encryption in the
+wireless network, it should be noted that the use of the PIN and
+especially PBC mechanisms for authenticating the initial key setup is
+not very secure. As such, use of WPS may not be suitable for
+environments that require secure network access without chance for
+allowing outsiders to gain access during the setup phase.
+
+WPS uses following terms to describe the entities participating in the
+network setup:
+- access point: the WLAN access point
+- Registrar: a device that control a network and can authorize
+  addition of new devices); this may be either in the AP ("internal
+  Registrar") or in an external device, e.g., a laptop, ("external
+  Registrar")
+- Enrollee: a device that is being authorized to use the network
+
+It should also be noted that the AP and a client device may change
+roles (i.e., AP acts as an Enrollee and client device as a Registrar)
+when WPS is used to configure the access point.
+
+
+More information about WPS is available from Wi-Fi Alliance:
+http://www.wi-fi.org/wifi-protected-setup
+
+
+hostapd implementation
+----------------------
+
+hostapd includes an optional WPS component that can be used as an
+internal WPS Registrar to manage addition of new WPS enabled clients
+to the network. In addition, WPS Enrollee functionality in hostapd can
+be used to allow external WPS Registrars to configure the access
+point, e.g., for initial network setup. In addition, hostapd can proxy a
+WPS registration between a wireless Enrollee and an external Registrar
+(e.g., Microsoft Vista or Atheros JumpStart) with UPnP.
+
+
+hostapd configuration
+---------------------
+
+WPS is an optional component that needs to be enabled in hostapd build
+configuration (.config). Here is an example configuration that
+includes WPS support and uses madwifi driver interface:
+
+CONFIG_DRIVER_MADWIFI=y
+CFLAGS += -I/usr/src/madwifi-0.9.3
+CONFIG_WPS=y
+CONFIG_WPS2=y
+CONFIG_WPS_UPNP=y
+
+
+Following section shows an example runtime configuration
+(hostapd.conf) that enables WPS:
+
+# Configure the driver and network interface
+driver=madwifi
+interface=ath0
+
+# WPA2-Personal configuration for the AP
+ssid=wps-test
+wpa=2
+wpa_key_mgmt=WPA-PSK
+wpa_pairwise=CCMP
+# Default WPA passphrase for legacy (non-WPS) clients
+wpa_passphrase=12345678
+# Enable random per-device PSK generation for WPS clients
+# Please note that the file has to exists for hostapd to start (i.e., create an
+# empty file as a starting point).
+wpa_psk_file=/etc/hostapd.psk
+
+# Enable control interface for PBC/PIN entry
+ctrl_interface=/var/run/hostapd
+
+# Enable internal EAP server for EAP-WSC (part of Wi-Fi Protected Setup)
+eap_server=1
+
+# WPS configuration (AP configured, do not allow external WPS Registrars)
+wps_state=2
+ap_setup_locked=1
+# If UUID is not configured, it will be generated based on local MAC address.
+uuid=87654321-9abc-def0-1234-56789abc0000
+wps_pin_requests=/var/run/hostapd.pin-req
+device_name=Wireless AP
+manufacturer=Company
+model_name=WAP
+model_number=123
+serial_number=12345
+device_type=6-0050F204-1
+os_version=01020300
+config_methods=label display push_button keypad
+
+# if external Registrars are allowed, UPnP support could be added:
+#upnp_iface=br0
+#friendly_name=WPS Access Point
+
+
+External operations
+-------------------
+
+WPS requires either a device PIN code (usually, 8-digit number) or a
+pushbutton event (for PBC) to allow a new WPS Enrollee to join the
+network. hostapd uses the control interface as an input channel for
+these events.
+
+The PIN value used in the commands must be processed by an UI to
+remove non-digit characters and potentially, to verify the checksum
+digit. "hostapd_cli wps_check_pin <PIN>" can be used to do such
+processing. It returns FAIL if the PIN is invalid, or FAIL-CHECKSUM if
+the checksum digit is incorrect, or the processed PIN (non-digit
+characters removed) if the PIN is valid.
+
+When a client device (WPS Enrollee) connects to hostapd (WPS
+Registrar) in order to start PIN mode negotiation for WPS, an
+identifier (Enrollee UUID) is sent. hostapd will need to be configured
+with a device password (PIN) for this Enrollee. This is an operation
+that requires user interaction (assuming there are no pre-configured
+PINs on the AP for a set of Enrollee).
+
+The PIN request with information about the device is appended to the
+wps_pin_requests file (/var/run/hostapd.pin-req in this example). In
+addition, hostapd control interface event is sent as a notification of
+a new device. The AP could use, e.g., a web UI for showing active
+Enrollees to the user and request a PIN for an Enrollee.
+
+The PIN request file has one line for every Enrollee that connected to
+the AP, but for which there was no PIN. Following information is
+provided for each Enrollee (separated with tabulators):
+- timestamp (seconds from 1970-01-01)
+- Enrollee UUID
+- MAC address
+- Device name
+- Manufacturer
+- Model Name
+- Model Number
+- Serial Number
+- Device category
+
+Example line in the /var/run/hostapd.pin-req file:
+1200188391     53b63a98-d29e-4457-a2ed-094d7e6a669c    Intel(R) Centrino(R)    Intel Corporation       Intel(R) Centrino(R)    -       -       1-0050F204-1
+
+Control interface data:
+WPS-PIN-NEEDED [UUID-E|MAC Address|Device Name|Manufacturer|Model Name|Model Number|Serial Number|Device Category]
+For example:
+<2>WPS-PIN-NEEDED [53b63a98-d29e-4457-a2ed-094d7e6a669c|02:12:34:56:78:9a|Device|Manuf|Model|Model Number|Serial Number|1-0050F204-1]
+
+When the user enters a PIN for a pending Enrollee, e.g., on the web
+UI), hostapd needs to be notified of the new PIN over the control
+interface. This can be done either by using the UNIX domain socket
+-based control interface directly (src/common/wpa_ctrl.c provides
+helper functions for using the interface) or by calling hostapd_cli.
+
+Example command to add a PIN (12345670) for an Enrollee:
+
+hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c 12345670
+
+If the UUID-E is not available (e.g., Enrollee waits for the Registrar
+to be selected before connecting), wildcard UUID may be used to allow
+the PIN to be used once with any UUID:
+
+hostapd_cli wps_pin any 12345670
+
+To reduce likelihood of PIN being used with other devices or of
+forgetting an active PIN available for potential attackers, expiration
+time in seconds can be set for the new PIN (value 0 indicates no
+expiration):
+
+hostapd_cli wps_pin any 12345670 300
+
+If the MAC address of the enrollee is known, it should be configured
+to allow the AP to advertise list of authorized enrollees:
+
+hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c \
+       12345670 300 00:11:22:33:44:55
+
+
+After this, the Enrollee can connect to the AP again and complete WPS
+negotiation. At that point, a new, random WPA PSK is generated for the
+client device and the client can then use that key to connect to the
+AP to access the network.
+
+
+If the AP includes a pushbutton, WPS PBC mode can be used. It is
+enabled by pushing a button on both the AP and the client at about the
+same time (2 minute window). hostapd needs to be notified about the AP
+button pushed event over the control interface, e.g., by calling
+hostapd_cli:
+
+hostapd_cli wps_pbc
+
+At this point, the client has two minutes to complete WPS negotiation
+which will generate a new WPA PSK in the same way as the PIN method
+described above.
+
+
+When an external Registrar is used, the AP can act as an Enrollee and
+use its AP PIN. A static AP PIN (e.g., one one a label in the AP
+device) can be configured in hostapd.conf (ap_pin parameter). A more
+secure option is to use hostapd_cli wps_ap_pin command to enable the
+AP PIN only based on user action (and even better security by using a
+random AP PIN for each session, i.e., by using "wps_ap_pin random"
+command with a timeout value). Following commands are available for
+managing the dynamic AP PIN operations:
+
+hostapd_cli wps_ap_pin disable
+- disable AP PIN (i.e., do not allow external Registrars to use it to
+  learn the current AP settings or to reconfigure the AP)
+
+hostapd_cli wps_ap_pin random [timeout]
+- generate a random AP PIN and enable it
+- if the optional timeout parameter is given, the AP PIN will be enabled
+  for the specified number of seconds
+
+hostapd_cli wps_ap_pin get
+- fetch the current AP PIN
+
+hostapd_cli wps_ap_pin set <PIN> [timeout]
+- set the AP PIN and enable it
+- if the optional timeout parameter is given, the AP PIN will be enabled
+  for the specified number of seconds
+
+hostapd_cli get_config
+- display the current configuration
+
+hostapd_cli wps_config <new SSID> <auth> <encr> <new key>
+examples:
+  hostapd_cli wps_config testing WPA2PSK CCMP 12345678
+  hostapd_cli wps_config "no security" OPEN NONE ""
+
+<auth> must be one of the following: OPEN WPAPSK WPA2PSK
+<encr> must be one of the following: NONE WEP TKIP CCMP
+
+
+Credential generation and configuration changes
+-----------------------------------------------
+
+By default, hostapd generates credentials for Enrollees and processing
+AP configuration updates internally. However, it is possible to
+control these operations from external programs, if desired.
+
+The internal credential generation can be disabled with
+skip_cred_build=1 option in the configuration. extra_cred option will
+then need to be used to provide pre-configured Credential attribute(s)
+for hostapd to use. The exact data from this binary file will be sent,
+i.e., it will have to include valid WPS attributes. extra_cred can
+also be used to add additional networks if the Registrar is used to
+configure credentials for multiple networks.
+
+Processing of received configuration updates can be disabled with
+wps_cred_processing=1 option. When this is used, an external program
+is responsible for creating hostapd configuration files and processing
+configuration updates based on messages received from hostapd over
+control interface. This will also include the initial configuration on
+first successful registration if the AP is initially set in
+unconfigured state.
+
+Following control interface messages are sent out for external programs:
+
+WPS-REG-SUCCESS <Enrollee MAC address <UUID-E>
+For example:
+<2>WPS-REG-SUCCESS 02:66:a0:ee:17:27 2b7093f1-d6fb-5108-adbb-bea66bb87333
+
+This can be used to trigger change from unconfigured to configured
+state (random configuration based on the first successful WPS
+registration). In addition, this can be used to update AP UI about the
+status of WPS registration progress.
+
+
+WPS-NEW-AP-SETTINGS <hexdump of AP Setup attributes>
+For example:
+<2>WPS-NEW-AP-SETTINGS 10260001011045000c6a6b6d2d7770732d74657374100300020020100f00020008102700403065346230343536633236366665306433396164313535346131663462663731323433376163666462376633393965353466316631623032306164343438623510200006024231cede15101e000844
+
+This can be used to update the externally stored AP configuration and
+then update hostapd configuration (followed by restarting of hostapd).
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
new file mode 100644 (file)
index 0000000..ca79695
--- /dev/null
@@ -0,0 +1,2261 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+#ifndef CONFIG_NATIVE_WINDOWS
+#include <grp.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include "utils/common.h"
+#include "utils/uuid.h"
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+#include "eap_server/eap.h"
+#include "radius/radius_client.h"
+#include "ap/wpa_auth.h"
+#include "ap/ap_config.h"
+#include "config_file.h"
+
+
+extern struct wpa_driver_ops *wpa_drivers[];
+
+
+#ifndef CONFIG_NO_VLAN
+static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
+                                        const char *fname)
+{
+       FILE *f;
+       char buf[128], *pos, *pos2;
+       int line = 0, vlan_id;
+       struct hostapd_vlan *vlan;
+
+       f = fopen(fname, "r");
+       if (!f) {
+               wpa_printf(MSG_ERROR, "VLAN file '%s' not readable.", fname);
+               return -1;
+       }
+
+       while (fgets(buf, sizeof(buf), f)) {
+               line++;
+
+               if (buf[0] == '#')
+                       continue;
+               pos = buf;
+               while (*pos != '\0') {
+                       if (*pos == '\n') {
+                               *pos = '\0';
+                               break;
+                       }
+                       pos++;
+               }
+               if (buf[0] == '\0')
+                       continue;
+
+               if (buf[0] == '*') {
+                       vlan_id = VLAN_ID_WILDCARD;
+                       pos = buf + 1;
+               } else {
+                       vlan_id = strtol(buf, &pos, 10);
+                       if (buf == pos || vlan_id < 1 ||
+                           vlan_id > MAX_VLAN_ID) {
+                               wpa_printf(MSG_ERROR, "Invalid VLAN ID at "
+                                          "line %d in '%s'", line, fname);
+                               fclose(f);
+                               return -1;
+                       }
+               }
+
+               while (*pos == ' ' || *pos == '\t')
+                       pos++;
+               pos2 = pos;
+               while (*pos2 != ' ' && *pos2 != '\t' && *pos2 != '\0')
+                       pos2++;
+               *pos2 = '\0';
+               if (*pos == '\0' || os_strlen(pos) > IFNAMSIZ) {
+                       wpa_printf(MSG_ERROR, "Invalid VLAN ifname at line %d "
+                                  "in '%s'", line, fname);
+                       fclose(f);
+                       return -1;
+               }
+
+               vlan = os_malloc(sizeof(*vlan));
+               if (vlan == NULL) {
+                       wpa_printf(MSG_ERROR, "Out of memory while reading "
+                                  "VLAN interfaces from '%s'", fname);
+                       fclose(f);
+                       return -1;
+               }
+
+               os_memset(vlan, 0, sizeof(*vlan));
+               vlan->vlan_id = vlan_id;
+               os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
+               if (bss->vlan_tail)
+                       bss->vlan_tail->next = vlan;
+               else
+                       bss->vlan = vlan;
+               bss->vlan_tail = vlan;
+       }
+
+       fclose(f);
+
+       return 0;
+}
+#endif /* CONFIG_NO_VLAN */
+
+
+static int hostapd_acl_comp(const void *a, const void *b)
+{
+       const struct mac_acl_entry *aa = a;
+       const struct mac_acl_entry *bb = b;
+       return os_memcmp(aa->addr, bb->addr, sizeof(macaddr));
+}
+
+
+static int hostapd_config_read_maclist(const char *fname,
+                                      struct mac_acl_entry **acl, int *num)
+{
+       FILE *f;
+       char buf[128], *pos;
+       int line = 0;
+       u8 addr[ETH_ALEN];
+       struct mac_acl_entry *newacl;
+       int vlan_id;
+
+       if (!fname)
+               return 0;
+
+       f = fopen(fname, "r");
+       if (!f) {
+               wpa_printf(MSG_ERROR, "MAC list file '%s' not found.", fname);
+               return -1;
+       }
+
+       while (fgets(buf, sizeof(buf), f)) {
+               line++;
+
+               if (buf[0] == '#')
+                       continue;
+               pos = buf;
+               while (*pos != '\0') {
+                       if (*pos == '\n') {
+                               *pos = '\0';
+                               break;
+                       }
+                       pos++;
+               }
+               if (buf[0] == '\0')
+                       continue;
+
+               if (hwaddr_aton(buf, addr)) {
+                       wpa_printf(MSG_ERROR, "Invalid MAC address '%s' at "
+                                  "line %d in '%s'", buf, line, fname);
+                       fclose(f);
+                       return -1;
+               }
+
+               vlan_id = 0;
+               pos = buf;
+               while (*pos != '\0' && *pos != ' ' && *pos != '\t')
+                       pos++;
+               while (*pos == ' ' || *pos == '\t')
+                       pos++;
+               if (*pos != '\0')
+                       vlan_id = atoi(pos);
+
+               newacl = os_realloc(*acl, (*num + 1) * sizeof(**acl));
+               if (newacl == NULL) {
+                       wpa_printf(MSG_ERROR, "MAC list reallocation failed");
+                       fclose(f);
+                       return -1;
+               }
+
+               *acl = newacl;
+               os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
+               (*acl)[*num].vlan_id = vlan_id;
+               (*num)++;
+       }
+
+       fclose(f);
+
+       qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
+
+       return 0;
+}
+
+
+#ifdef EAP_SERVER
+static int hostapd_config_read_eap_user(const char *fname,
+                                       struct hostapd_bss_config *conf)
+{
+       FILE *f;
+       char buf[512], *pos, *start, *pos2;
+       int line = 0, ret = 0, num_methods;
+       struct hostapd_eap_user *user, *tail = NULL;
+
+       if (!fname)
+               return 0;
+
+       f = fopen(fname, "r");
+       if (!f) {
+               wpa_printf(MSG_ERROR, "EAP user file '%s' not found.", fname);
+               return -1;
+       }
+
+       /* Lines: "user" METHOD,METHOD2 "password" (password optional) */
+       while (fgets(buf, sizeof(buf), f)) {
+               line++;
+
+               if (buf[0] == '#')
+                       continue;
+               pos = buf;
+               while (*pos != '\0') {
+                       if (*pos == '\n') {
+                               *pos = '\0';
+                               break;
+                       }
+                       pos++;
+               }
+               if (buf[0] == '\0')
+                       continue;
+
+               user = NULL;
+
+               if (buf[0] != '"' && buf[0] != '*') {
+                       wpa_printf(MSG_ERROR, "Invalid EAP identity (no \" in "
+                                  "start) on line %d in '%s'", line, fname);
+                       goto failed;
+               }
+
+               user = os_zalloc(sizeof(*user));
+               if (user == NULL) {
+                       wpa_printf(MSG_ERROR, "EAP user allocation failed");
+                       goto failed;
+               }
+               user->force_version = -1;
+
+               if (buf[0] == '*') {
+                       pos = buf;
+               } else {
+                       pos = buf + 1;
+                       start = pos;
+                       while (*pos != '"' && *pos != '\0')
+                               pos++;
+                       if (*pos == '\0') {
+                               wpa_printf(MSG_ERROR, "Invalid EAP identity "
+                                          "(no \" in end) on line %d in '%s'",
+                                          line, fname);
+                               goto failed;
+                       }
+
+                       user->identity = os_malloc(pos - start);
+                       if (user->identity == NULL) {
+                               wpa_printf(MSG_ERROR, "Failed to allocate "
+                                          "memory for EAP identity");
+                               goto failed;
+                       }
+                       os_memcpy(user->identity, start, pos - start);
+                       user->identity_len = pos - start;
+
+                       if (pos[0] == '"' && pos[1] == '*') {
+                               user->wildcard_prefix = 1;
+                               pos++;
+                       }
+               }
+               pos++;
+               while (*pos == ' ' || *pos == '\t')
+                       pos++;
+
+               if (*pos == '\0') {
+                       wpa_printf(MSG_ERROR, "No EAP method on line %d in "
+                                  "'%s'", line, fname);
+                       goto failed;
+               }
+
+               start = pos;
+               while (*pos != ' ' && *pos != '\t' && *pos != '\0')
+                       pos++;
+               if (*pos == '\0') {
+                       pos = NULL;
+               } else {
+                       *pos = '\0';
+                       pos++;
+               }
+               num_methods = 0;
+               while (*start) {
+                       char *pos3 = os_strchr(start, ',');
+                       if (pos3) {
+                               *pos3++ = '\0';
+                       }
+                       user->methods[num_methods].method =
+                               eap_server_get_type(
+                                       start,
+                                       &user->methods[num_methods].vendor);
+                       if (user->methods[num_methods].vendor ==
+                           EAP_VENDOR_IETF &&
+                           user->methods[num_methods].method == EAP_TYPE_NONE)
+                       {
+                               if (os_strcmp(start, "TTLS-PAP") == 0) {
+                                       user->ttls_auth |= EAP_TTLS_AUTH_PAP;
+                                       goto skip_eap;
+                               }
+                               if (os_strcmp(start, "TTLS-CHAP") == 0) {
+                                       user->ttls_auth |= EAP_TTLS_AUTH_CHAP;
+                                       goto skip_eap;
+                               }
+                               if (os_strcmp(start, "TTLS-MSCHAP") == 0) {
+                                       user->ttls_auth |=
+                                               EAP_TTLS_AUTH_MSCHAP;
+                                       goto skip_eap;
+                               }
+                               if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) {
+                                       user->ttls_auth |=
+                                               EAP_TTLS_AUTH_MSCHAPV2;
+                                       goto skip_eap;
+                               }
+                               wpa_printf(MSG_ERROR, "Unsupported EAP type "
+                                          "'%s' on line %d in '%s'",
+                                          start, line, fname);
+                               goto failed;
+                       }
+
+                       num_methods++;
+                       if (num_methods >= EAP_MAX_METHODS)
+                               break;
+               skip_eap:
+                       if (pos3 == NULL)
+                               break;
+                       start = pos3;
+               }
+               if (num_methods == 0 && user->ttls_auth == 0) {
+                       wpa_printf(MSG_ERROR, "No EAP types configured on "
+                                  "line %d in '%s'", line, fname);
+                       goto failed;
+               }
+
+               if (pos == NULL)
+                       goto done;
+
+               while (*pos == ' ' || *pos == '\t')
+                       pos++;
+               if (*pos == '\0')
+                       goto done;
+
+               if (os_strncmp(pos, "[ver=0]", 7) == 0) {
+                       user->force_version = 0;
+                       goto done;
+               }
+
+               if (os_strncmp(pos, "[ver=1]", 7) == 0) {
+                       user->force_version = 1;
+                       goto done;
+               }
+
+               if (os_strncmp(pos, "[2]", 3) == 0) {
+                       user->phase2 = 1;
+                       goto done;
+               }
+
+               if (*pos == '"') {
+                       pos++;
+                       start = pos;
+                       while (*pos != '"' && *pos != '\0')
+                               pos++;
+                       if (*pos == '\0') {
+                               wpa_printf(MSG_ERROR, "Invalid EAP password "
+                                          "(no \" in end) on line %d in '%s'",
+                                          line, fname);
+                               goto failed;
+                       }
+
+                       user->password = os_malloc(pos - start);
+                       if (user->password == NULL) {
+                               wpa_printf(MSG_ERROR, "Failed to allocate "
+                                          "memory for EAP password");
+                               goto failed;
+                       }
+                       os_memcpy(user->password, start, pos - start);
+                       user->password_len = pos - start;
+
+                       pos++;
+               } else if (os_strncmp(pos, "hash:", 5) == 0) {
+                       pos += 5;
+                       pos2 = pos;
+                       while (*pos2 != '\0' && *pos2 != ' ' &&
+                              *pos2 != '\t' && *pos2 != '#')
+                               pos2++;
+                       if (pos2 - pos != 32) {
+                               wpa_printf(MSG_ERROR, "Invalid password hash "
+                                          "on line %d in '%s'", line, fname);
+                               goto failed;
+                       }
+                       user->password = os_malloc(16);
+                       if (user->password == NULL) {
+                               wpa_printf(MSG_ERROR, "Failed to allocate "
+                                          "memory for EAP password hash");
+                               goto failed;
+                       }
+                       if (hexstr2bin(pos, user->password, 16) < 0) {
+                               wpa_printf(MSG_ERROR, "Invalid hash password "
+                                          "on line %d in '%s'", line, fname);
+                               goto failed;
+                       }
+                       user->password_len = 16;
+                       user->password_hash = 1;
+                       pos = pos2;
+               } else {
+                       pos2 = pos;
+                       while (*pos2 != '\0' && *pos2 != ' ' &&
+                              *pos2 != '\t' && *pos2 != '#')
+                               pos2++;
+                       if ((pos2 - pos) & 1) {
+                               wpa_printf(MSG_ERROR, "Invalid hex password "
+                                          "on line %d in '%s'", line, fname);
+                               goto failed;
+                       }
+                       user->password = os_malloc((pos2 - pos) / 2);
+                       if (user->password == NULL) {
+                               wpa_printf(MSG_ERROR, "Failed to allocate "
+                                          "memory for EAP password");
+                               goto failed;
+                       }
+                       if (hexstr2bin(pos, user->password,
+                                      (pos2 - pos) / 2) < 0) {
+                               wpa_printf(MSG_ERROR, "Invalid hex password "
+                                          "on line %d in '%s'", line, fname);
+                               goto failed;
+                       }
+                       user->password_len = (pos2 - pos) / 2;
+                       pos = pos2;
+               }
+
+               while (*pos == ' ' || *pos == '\t')
+                       pos++;
+               if (os_strncmp(pos, "[2]", 3) == 0) {
+                       user->phase2 = 1;
+               }
+
+       done:
+               if (tail == NULL) {
+                       tail = conf->eap_user = user;
+               } else {
+                       tail->next = user;
+                       tail = user;
+               }
+               continue;
+
+       failed:
+               if (user) {
+                       os_free(user->password);
+                       os_free(user->identity);
+                       os_free(user);
+               }
+               ret = -1;
+               break;
+       }
+
+       fclose(f);
+
+       return ret;
+}
+#endif /* EAP_SERVER */
+
+
+#ifndef CONFIG_NO_RADIUS
+static int
+hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
+                               int *num_server, const char *val, int def_port,
+                               struct hostapd_radius_server **curr_serv)
+{
+       struct hostapd_radius_server *nserv;
+       int ret;
+       static int server_index = 1;
+
+       nserv = os_realloc(*server, (*num_server + 1) * sizeof(*nserv));
+       if (nserv == NULL)
+               return -1;
+
+       *server = nserv;
+       nserv = &nserv[*num_server];
+       (*num_server)++;
+       (*curr_serv) = nserv;
+
+       os_memset(nserv, 0, sizeof(*nserv));
+       nserv->port = def_port;
+       ret = hostapd_parse_ip_addr(val, &nserv->addr);
+       nserv->index = server_index++;
+
+       return ret;
+}
+#endif /* CONFIG_NO_RADIUS */
+
+
+static int hostapd_config_parse_key_mgmt(int line, const char *value)
+{
+       int val = 0, last;
+       char *start, *end, *buf;
+
+       buf = os_strdup(value);
+       if (buf == NULL)
+               return -1;
+       start = buf;
+
+       while (*start != '\0') {
+               while (*start == ' ' || *start == '\t')
+                       start++;
+               if (*start == '\0')
+                       break;
+               end = start;
+               while (*end != ' ' && *end != '\t' && *end != '\0')
+                       end++;
+               last = *end == '\0';
+               *end = '\0';
+               if (os_strcmp(start, "WPA-PSK") == 0)
+                       val |= WPA_KEY_MGMT_PSK;
+               else if (os_strcmp(start, "WPA-EAP") == 0)
+                       val |= WPA_KEY_MGMT_IEEE8021X;
+#ifdef CONFIG_IEEE80211R
+               else if (os_strcmp(start, "FT-PSK") == 0)
+                       val |= WPA_KEY_MGMT_FT_PSK;
+               else if (os_strcmp(start, "FT-EAP") == 0)
+                       val |= WPA_KEY_MGMT_FT_IEEE8021X;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+               else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
+                       val |= WPA_KEY_MGMT_PSK_SHA256;
+               else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
+                       val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
+#endif /* CONFIG_IEEE80211W */
+               else {
+                       wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
+                                  line, start);
+                       os_free(buf);
+                       return -1;
+               }
+
+               if (last)
+                       break;
+               start = end + 1;
+       }
+
+       os_free(buf);
+       if (val == 0) {
+               wpa_printf(MSG_ERROR, "Line %d: no key_mgmt values "
+                          "configured.", line);
+               return -1;
+       }
+
+       return val;
+}
+
+
+static int hostapd_config_parse_cipher(int line, const char *value)
+{
+       int val = 0, last;
+       char *start, *end, *buf;
+
+       buf = os_strdup(value);
+       if (buf == NULL)
+               return -1;
+       start = buf;
+
+       while (*start != '\0') {
+               while (*start == ' ' || *start == '\t')
+                       start++;
+               if (*start == '\0')
+                       break;
+               end = start;
+               while (*end != ' ' && *end != '\t' && *end != '\0')
+                       end++;
+               last = *end == '\0';
+               *end = '\0';
+               if (os_strcmp(start, "CCMP") == 0)
+                       val |= WPA_CIPHER_CCMP;
+               else if (os_strcmp(start, "TKIP") == 0)
+                       val |= WPA_CIPHER_TKIP;
+               else if (os_strcmp(start, "WEP104") == 0)
+                       val |= WPA_CIPHER_WEP104;
+               else if (os_strcmp(start, "WEP40") == 0)
+                       val |= WPA_CIPHER_WEP40;
+               else if (os_strcmp(start, "NONE") == 0)
+                       val |= WPA_CIPHER_NONE;
+               else {
+                       wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
+                                  line, start);
+                       os_free(buf);
+                       return -1;
+               }
+
+               if (last)
+                       break;
+               start = end + 1;
+       }
+       os_free(buf);
+
+       if (val == 0) {
+               wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
+                          line);
+               return -1;
+       }
+       return val;
+}
+
+
+static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
+                                  char *val)
+{
+       size_t len = os_strlen(val);
+
+       if (keyidx < 0 || keyidx > 3 || wep->key[keyidx] != NULL)
+               return -1;
+
+       if (val[0] == '"') {
+               if (len < 2 || val[len - 1] != '"')
+                       return -1;
+               len -= 2;
+               wep->key[keyidx] = os_malloc(len);
+               if (wep->key[keyidx] == NULL)
+                       return -1;
+               os_memcpy(wep->key[keyidx], val + 1, len);
+               wep->len[keyidx] = len;
+       } else {
+               if (len & 1)
+                       return -1;
+               len /= 2;
+               wep->key[keyidx] = os_malloc(len);
+               if (wep->key[keyidx] == NULL)
+                       return -1;
+               wep->len[keyidx] = len;
+               if (hexstr2bin(val, wep->key[keyidx], len) < 0)
+                       return -1;
+       }
+
+       wep->keys_set++;
+
+       return 0;
+}
+
+
+static int hostapd_parse_rates(int **rate_list, char *val)
+{
+       int *list;
+       int count;
+       char *pos, *end;
+
+       os_free(*rate_list);
+       *rate_list = NULL;
+
+       pos = val;
+       count = 0;
+       while (*pos != '\0') {
+               if (*pos == ' ')
+                       count++;
+               pos++;
+       }
+
+       list = os_malloc(sizeof(int) * (count + 2));
+       if (list == NULL)
+               return -1;
+       pos = val;
+       count = 0;
+       while (*pos != '\0') {
+               end = os_strchr(pos, ' ');
+               if (end)
+                       *end = '\0';
+
+               list[count++] = atoi(pos);
+               if (!end)
+                       break;
+               pos = end + 1;
+       }
+       list[count] = -1;
+
+       *rate_list = list;
+       return 0;
+}
+
+
+static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
+{
+       struct hostapd_bss_config *bss;
+
+       if (*ifname == '\0')
+               return -1;
+
+       bss = os_realloc(conf->bss, (conf->num_bss + 1) *
+                        sizeof(struct hostapd_bss_config));
+       if (bss == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to allocate memory for "
+                          "multi-BSS entry");
+               return -1;
+       }
+       conf->bss = bss;
+
+       bss = &(conf->bss[conf->num_bss]);
+       os_memset(bss, 0, sizeof(*bss));
+       bss->radius = os_zalloc(sizeof(*bss->radius));
+       if (bss->radius == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to allocate memory for "
+                          "multi-BSS RADIUS data");
+               return -1;
+       }
+
+       conf->num_bss++;
+       conf->last_bss = bss;
+
+       hostapd_config_defaults_bss(bss);
+       os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
+       os_memcpy(bss->ssid.vlan, bss->iface, IFNAMSIZ + 1);
+
+       return 0;
+}
+
+
+/* convert floats with one decimal place to value*10 int, i.e.,
+ * "1.5" will return 15 */
+static int hostapd_config_read_int10(const char *value)
+{
+       int i, d;
+       char *pos;
+
+       i = atoi(value);
+       pos = os_strchr(value, '.');
+       d = 0;
+       if (pos) {
+               pos++;
+               if (*pos >= '0' && *pos <= '9')
+                       d = *pos - '0';
+       }
+
+       return i * 10 + d;
+}
+
+
+static int valid_cw(int cw)
+{
+       return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
+               cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023);
+}
+
+
+enum {
+       IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */
+       IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */
+       IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */
+       IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */
+};
+
+static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name,
+                                  char *val)
+{
+       int num;
+       char *pos;
+       struct hostapd_tx_queue_params *queue;
+
+       /* skip 'tx_queue_' prefix */
+       pos = name + 9;
+       if (os_strncmp(pos, "data", 4) == 0 &&
+           pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
+               num = pos[4] - '0';
+               pos += 6;
+       } else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
+                  os_strncmp(pos, "beacon_", 7) == 0) {
+               wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
+               return 0;
+       } else {
+               wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
+               return -1;
+       }
+
+       if (num >= NUM_TX_QUEUES) {
+               /* for backwards compatibility, do not trigger failure */
+               wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
+               return 0;
+       }
+
+       queue = &conf->tx_queue[num];
+
+       if (os_strcmp(pos, "aifs") == 0) {
+               queue->aifs = atoi(val);
+               if (queue->aifs < 0 || queue->aifs > 255) {
+                       wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
+                                  queue->aifs);
+                       return -1;
+               }
+       } else if (os_strcmp(pos, "cwmin") == 0) {
+               queue->cwmin = atoi(val);
+               if (!valid_cw(queue->cwmin)) {
+                       wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
+                                  queue->cwmin);
+                       return -1;
+               }
+       } else if (os_strcmp(pos, "cwmax") == 0) {
+               queue->cwmax = atoi(val);
+               if (!valid_cw(queue->cwmax)) {
+                       wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
+                                  queue->cwmax);
+                       return -1;
+               }
+       } else if (os_strcmp(pos, "burst") == 0) {
+               queue->burst = hostapd_config_read_int10(val);
+       } else {
+               wpa_printf(MSG_ERROR, "Unknown tx_queue field '%s'", pos);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+static int hostapd_config_wmm_ac(struct hostapd_config *conf, char *name,
+                                char *val)
+{
+       int num, v;
+       char *pos;
+       struct hostapd_wmm_ac_params *ac;
+
+       /* skip 'wme_ac_' or 'wmm_ac_' prefix */
+       pos = name + 7;
+       if (os_strncmp(pos, "be_", 3) == 0) {
+               num = 0;
+               pos += 3;
+       } else if (os_strncmp(pos, "bk_", 3) == 0) {
+               num = 1;
+               pos += 3;
+       } else if (os_strncmp(pos, "vi_", 3) == 0) {
+               num = 2;
+               pos += 3;
+       } else if (os_strncmp(pos, "vo_", 3) == 0) {
+               num = 3;
+               pos += 3;
+       } else {
+               wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
+               return -1;
+       }
+
+       ac = &conf->wmm_ac_params[num];
+
+       if (os_strcmp(pos, "aifs") == 0) {
+               v = atoi(val);
+               if (v < 1 || v > 255) {
+                       wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
+                       return -1;
+               }
+               ac->aifs = v;
+       } else if (os_strcmp(pos, "cwmin") == 0) {
+               v = atoi(val);
+               if (v < 0 || v > 12) {
+                       wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
+                       return -1;
+               }
+               ac->cwmin = v;
+       } else if (os_strcmp(pos, "cwmax") == 0) {
+               v = atoi(val);
+               if (v < 0 || v > 12) {
+                       wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
+                       return -1;
+               }
+               ac->cwmax = v;
+       } else if (os_strcmp(pos, "txop_limit") == 0) {
+               v = atoi(val);
+               if (v < 0 || v > 0xffff) {
+                       wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
+                       return -1;
+               }
+               ac->txop_limit = v;
+       } else if (os_strcmp(pos, "acm") == 0) {
+               v = atoi(val);
+               if (v < 0 || v > 1) {
+                       wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
+                       return -1;
+               }
+               ac->admission_control_mandatory = v;
+       } else {
+               wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+#ifdef CONFIG_IEEE80211R
+static int add_r0kh(struct hostapd_bss_config *bss, char *value)
+{
+       struct ft_remote_r0kh *r0kh;
+       char *pos, *next;
+
+       r0kh = os_zalloc(sizeof(*r0kh));
+       if (r0kh == NULL)
+               return -1;
+
+       /* 02:01:02:03:04:05 a.example.com 000102030405060708090a0b0c0d0e0f */
+       pos = value;
+       next = os_strchr(pos, ' ');
+       if (next)
+               *next++ = '\0';
+       if (next == NULL || hwaddr_aton(pos, r0kh->addr)) {
+               wpa_printf(MSG_ERROR, "Invalid R0KH MAC address: '%s'", pos);
+               os_free(r0kh);
+               return -1;
+       }
+
+       pos = next;
+       next = os_strchr(pos, ' ');
+       if (next)
+               *next++ = '\0';
+       if (next == NULL || next - pos > FT_R0KH_ID_MAX_LEN) {
+               wpa_printf(MSG_ERROR, "Invalid R0KH-ID: '%s'", pos);
+               os_free(r0kh);
+               return -1;
+       }
+       r0kh->id_len = next - pos - 1;
+       os_memcpy(r0kh->id, pos, r0kh->id_len);
+
+       pos = next;
+       if (hexstr2bin(pos, r0kh->key, sizeof(r0kh->key))) {
+               wpa_printf(MSG_ERROR, "Invalid R0KH key: '%s'", pos);
+               os_free(r0kh);
+               return -1;
+       }
+
+       r0kh->next = bss->r0kh_list;
+       bss->r0kh_list = r0kh;
+
+       return 0;
+}
+
+
+static int add_r1kh(struct hostapd_bss_config *bss, char *value)
+{
+       struct ft_remote_r1kh *r1kh;
+       char *pos, *next;
+
+       r1kh = os_zalloc(sizeof(*r1kh));
+       if (r1kh == NULL)
+               return -1;
+
+       /* 02:01:02:03:04:05 02:01:02:03:04:05
+        * 000102030405060708090a0b0c0d0e0f */
+       pos = value;
+       next = os_strchr(pos, ' ');
+       if (next)
+               *next++ = '\0';
+       if (next == NULL || hwaddr_aton(pos, r1kh->addr)) {
+               wpa_printf(MSG_ERROR, "Invalid R1KH MAC address: '%s'", pos);
+               os_free(r1kh);
+               return -1;
+       }
+
+       pos = next;
+       next = os_strchr(pos, ' ');
+       if (next)
+               *next++ = '\0';
+       if (next == NULL || hwaddr_aton(pos, r1kh->id)) {
+               wpa_printf(MSG_ERROR, "Invalid R1KH-ID: '%s'", pos);
+               os_free(r1kh);
+               return -1;
+       }
+
+       pos = next;
+       if (hexstr2bin(pos, r1kh->key, sizeof(r1kh->key))) {
+               wpa_printf(MSG_ERROR, "Invalid R1KH key: '%s'", pos);
+               os_free(r1kh);
+               return -1;
+       }
+
+       r1kh->next = bss->r1kh_list;
+       bss->r1kh_list = r1kh;
+
+       return 0;
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+#ifdef CONFIG_IEEE80211N
+static int hostapd_config_ht_capab(struct hostapd_config *conf,
+                                  const char *capab)
+{
+       if (os_strstr(capab, "[LDPC]"))
+               conf->ht_capab |= HT_CAP_INFO_LDPC_CODING_CAP;
+       if (os_strstr(capab, "[HT40-]")) {
+               conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+               conf->secondary_channel = -1;
+       }
+       if (os_strstr(capab, "[HT40+]")) {
+               conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+               conf->secondary_channel = 1;
+       }
+       if (os_strstr(capab, "[SMPS-STATIC]")) {
+               conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
+               conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC;
+       }
+       if (os_strstr(capab, "[SMPS-DYNAMIC]")) {
+               conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
+               conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC;
+       }
+       if (os_strstr(capab, "[GF]"))
+               conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD;
+       if (os_strstr(capab, "[SHORT-GI-20]"))
+               conf->ht_capab |= HT_CAP_INFO_SHORT_GI20MHZ;
+       if (os_strstr(capab, "[SHORT-GI-40]"))
+               conf->ht_capab |= HT_CAP_INFO_SHORT_GI40MHZ;
+       if (os_strstr(capab, "[TX-STBC]"))
+               conf->ht_capab |= HT_CAP_INFO_TX_STBC;
+       if (os_strstr(capab, "[RX-STBC1]")) {
+               conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
+               conf->ht_capab |= HT_CAP_INFO_RX_STBC_1;
+       }
+       if (os_strstr(capab, "[RX-STBC12]")) {
+               conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
+               conf->ht_capab |= HT_CAP_INFO_RX_STBC_12;
+       }
+       if (os_strstr(capab, "[RX-STBC123]")) {
+               conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
+               conf->ht_capab |= HT_CAP_INFO_RX_STBC_123;
+       }
+       if (os_strstr(capab, "[DELAYED-BA]"))
+               conf->ht_capab |= HT_CAP_INFO_DELAYED_BA;
+       if (os_strstr(capab, "[MAX-AMSDU-7935]"))
+               conf->ht_capab |= HT_CAP_INFO_MAX_AMSDU_SIZE;
+       if (os_strstr(capab, "[DSSS_CCK-40]"))
+               conf->ht_capab |= HT_CAP_INFO_DSSS_CCK40MHZ;
+       if (os_strstr(capab, "[PSMP]"))
+               conf->ht_capab |= HT_CAP_INFO_PSMP_SUPP;
+       if (os_strstr(capab, "[LSIG-TXOP-PROT]"))
+               conf->ht_capab |= HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT;
+
+       return 0;
+}
+#endif /* CONFIG_IEEE80211N */
+
+
+static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
+                                   struct hostapd_config *conf)
+{
+       if (bss->ieee802_1x && !bss->eap_server &&
+           !bss->radius->auth_servers) {
+               wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
+                          "EAP authenticator configured).");
+               return -1;
+       }
+
+       if (bss->wpa && bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
+           bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+               wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
+                          "RADIUS checking (macaddr_acl=2) enabled.");
+               return -1;
+       }
+
+       if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
+           bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
+           bss->ssid.wpa_psk_file == NULL &&
+           (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
+            bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
+               wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
+                          "is not configured.");
+               return -1;
+       }
+
+       if (hostapd_mac_comp_empty(bss->bssid) != 0) {
+               size_t i;
+
+               for (i = 0; i < conf->num_bss; i++) {
+                       if ((&conf->bss[i] != bss) &&
+                           (hostapd_mac_comp(conf->bss[i].bssid,
+                                             bss->bssid) == 0)) {
+                               wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR
+                                          " on interface '%s' and '%s'.",
+                                          MAC2STR(bss->bssid),
+                                          conf->bss[i].iface, bss->iface);
+                               return -1;
+                       }
+               }
+       }
+
+#ifdef CONFIG_IEEE80211R
+       if (wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
+           (bss->nas_identifier == NULL ||
+            os_strlen(bss->nas_identifier) < 1 ||
+            os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
+               wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires "
+                          "nas_identifier to be configured as a 1..48 octet "
+                          "string");
+               return -1;
+       }
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211N
+       if (conf->ieee80211n &&
+           bss->ssid.security_policy == SECURITY_STATIC_WEP) {
+               bss->disable_11n = 1;
+               wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
+                          "allowed, disabling HT capabilities");
+       }
+
+       if (conf->ieee80211n && bss->wpa &&
+           !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
+           !(bss->rsn_pairwise & WPA_CIPHER_CCMP)) {
+               bss->disable_11n = 1;
+               wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
+                          "requires CCMP to be enabled, disabling HT "
+                          "capabilities");
+       }
+#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_WPS2
+       if (bss->wps_state && bss->ignore_broadcast_ssid) {
+               wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
+                          "configuration forced WPS to be disabled");
+               bss->wps_state = 0;
+       }
+
+       if (bss->wps_state && bss->ssid.wep.keys_set && bss->wpa == 0) {
+               wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
+                          "disabled");
+               bss->wps_state = 0;
+       }
+#endif /* CONFIG_WPS2 */
+
+       return 0;
+}
+
+
+static int hostapd_config_check(struct hostapd_config *conf)
+{
+       size_t i;
+
+       if (conf->ieee80211d && (!conf->country[0] || !conf->country[1])) {
+               wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
+                          "setting the country_code");
+               return -1;
+       }
+
+       for (i = 0; i < conf->num_bss; i++) {
+               if (hostapd_config_check_bss(&conf->bss[i], conf))
+                       return -1;
+       }
+
+       return 0;
+}
+
+
+#ifdef CONFIG_INTERWORKING
+static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
+                                   int line)
+{
+       size_t len = os_strlen(pos);
+       u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
+
+       struct hostapd_roaming_consortium *rc;
+
+       if ((len & 1) || len < 2 * 3 || len / 2 > MAX_ROAMING_CONSORTIUM_LEN ||
+           hexstr2bin(pos, oi, len / 2)) {
+               wpa_printf(MSG_ERROR, "Line %d: invalid roaming_consortium "
+                          "'%s'", line, pos);
+               return -1;
+       }
+       len /= 2;
+
+       rc = os_realloc(bss->roaming_consortium,
+                       sizeof(struct hostapd_roaming_consortium) *
+                       (bss->roaming_consortium_count + 1));
+       if (rc == NULL)
+               return -1;
+
+       os_memcpy(rc[bss->roaming_consortium_count].oi, oi, len);
+       rc[bss->roaming_consortium_count].len = len;
+
+       bss->roaming_consortium = rc;
+       bss->roaming_consortium_count++;
+
+       return 0;
+}
+#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)
+{
+       struct hostapd_config *conf;
+       struct hostapd_bss_config *bss;
+       FILE *f;
+       char buf[256], *pos;
+       int line = 0;
+       int errors = 0;
+       int pairwise;
+       size_t i;
+
+       f = fopen(fname, "r");
+       if (f == NULL) {
+               wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
+                          "for reading.", fname);
+               return NULL;
+       }
+
+       conf = hostapd_config_defaults();
+       if (conf == NULL) {
+               fclose(f);
+               return NULL;
+       }
+
+       /* set default driver based on configuration */
+       conf->driver = wpa_drivers[0];
+       if (conf->driver == NULL) {
+               wpa_printf(MSG_ERROR, "No driver wrappers registered!");
+               hostapd_config_free(conf);
+               fclose(f);
+               return NULL;
+       }
+
+       bss = conf->last_bss = conf->bss;
+
+       while (fgets(buf, sizeof(buf), f)) {
+               bss = conf->last_bss;
+               line++;
+
+               if (buf[0] == '#')
+                       continue;
+               pos = buf;
+               while (*pos != '\0') {
+                       if (*pos == '\n') {
+                               *pos = '\0';
+                               break;
+                       }
+                       pos++;
+               }
+               if (buf[0] == '\0')
+                       continue;
+
+               pos = os_strchr(buf, '=');
+               if (pos == NULL) {
+                       wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'",
+                                  line, buf);
+                       errors++;
+                       continue;
+               }
+               *pos = '\0';
+               pos++;
+
+               if (os_strcmp(buf, "interface") == 0) {
+                       os_strlcpy(conf->bss[0].iface, pos,
+                                  sizeof(conf->bss[0].iface));
+               } else if (os_strcmp(buf, "bridge") == 0) {
+                       os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
+               } else if (os_strcmp(buf, "wds_bridge") == 0) {
+                       os_strlcpy(bss->wds_bridge, pos,
+                                  sizeof(bss->wds_bridge));
+               } else if (os_strcmp(buf, "driver") == 0) {
+                       int j;
+                       /* clear to get error below if setting is invalid */
+                       conf->driver = NULL;
+                       for (j = 0; wpa_drivers[j]; j++) {
+                               if (os_strcmp(pos, wpa_drivers[j]->name) == 0)
+                               {
+                                       conf->driver = wpa_drivers[j];
+                                       break;
+                               }
+                       }
+                       if (conf->driver == NULL) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid/"
+                                          "unknown driver '%s'", line, pos);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "debug") == 0) {
+                       wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' "
+                                  "configuration variable is not used "
+                                  "anymore", line);
+               } else if (os_strcmp(buf, "logger_syslog_level") == 0) {
+                       bss->logger_syslog_level = atoi(pos);
+               } else if (os_strcmp(buf, "logger_stdout_level") == 0) {
+                       bss->logger_stdout_level = atoi(pos);
+               } else if (os_strcmp(buf, "logger_syslog") == 0) {
+                       bss->logger_syslog = atoi(pos);
+               } else if (os_strcmp(buf, "logger_stdout") == 0) {
+                       bss->logger_stdout = atoi(pos);
+               } else if (os_strcmp(buf, "dump_file") == 0) {
+                       bss->dump_log_name = os_strdup(pos);
+               } else if (os_strcmp(buf, "ssid") == 0) {
+                       bss->ssid.ssid_len = os_strlen(pos);
+                       if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
+                           bss->ssid.ssid_len < 1) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid SSID "
+                                          "'%s'", line, pos);
+                               errors++;
+                       } else {
+                               os_memcpy(bss->ssid.ssid, pos,
+                                         bss->ssid.ssid_len);
+                               bss->ssid.ssid[bss->ssid.ssid_len] = '\0';
+                               bss->ssid.ssid_set = 1;
+                       }
+               } else if (os_strcmp(buf, "macaddr_acl") == 0) {
+                       bss->macaddr_acl = atoi(pos);
+                       if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
+                           bss->macaddr_acl != DENY_UNLESS_ACCEPTED &&
+                           bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+                               wpa_printf(MSG_ERROR, "Line %d: unknown "
+                                          "macaddr_acl %d",
+                                          line, bss->macaddr_acl);
+                       }
+               } else if (os_strcmp(buf, "accept_mac_file") == 0) {
+                       if (hostapd_config_read_maclist(pos, &bss->accept_mac,
+                                                       &bss->num_accept_mac))
+                       {
+                               wpa_printf(MSG_ERROR, "Line %d: Failed to "
+                                          "read accept_mac_file '%s'",
+                                          line, pos);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "deny_mac_file") == 0) {
+                       if (hostapd_config_read_maclist(pos, &bss->deny_mac,
+                                                       &bss->num_deny_mac)) {
+                               wpa_printf(MSG_ERROR, "Line %d: Failed to "
+                                          "read deny_mac_file '%s'",
+                                          line, pos);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "wds_sta") == 0) {
+                       bss->wds_sta = atoi(pos);
+               } else if (os_strcmp(buf, "ap_isolate") == 0) {
+                       bss->isolate = atoi(pos);
+               } else if (os_strcmp(buf, "ap_max_inactivity") == 0) {
+                       bss->ap_max_inactivity = atoi(pos);
+               } else if (os_strcmp(buf, "country_code") == 0) {
+                       os_memcpy(conf->country, pos, 2);
+                       /* FIX: make this configurable */
+                       conf->country[2] = ' ';
+               } else if (os_strcmp(buf, "ieee80211d") == 0) {
+                       conf->ieee80211d = atoi(pos);
+               } else if (os_strcmp(buf, "ieee8021x") == 0) {
+                       bss->ieee802_1x = atoi(pos);
+               } else if (os_strcmp(buf, "eapol_version") == 0) {
+                       bss->eapol_version = atoi(pos);
+                       if (bss->eapol_version < 1 ||
+                           bss->eapol_version > 2) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid EAPOL "
+                                          "version (%d): '%s'.",
+                                          line, bss->eapol_version, pos);
+                               errors++;
+                       } else
+                               wpa_printf(MSG_DEBUG, "eapol_version=%d",
+                                          bss->eapol_version);
+#ifdef EAP_SERVER
+               } else if (os_strcmp(buf, "eap_authenticator") == 0) {
+                       bss->eap_server = atoi(pos);
+                       wpa_printf(MSG_ERROR, "Line %d: obsolete "
+                                  "eap_authenticator used; this has been "
+                                  "renamed to eap_server", line);
+               } else if (os_strcmp(buf, "eap_server") == 0) {
+                       bss->eap_server = atoi(pos);
+               } else if (os_strcmp(buf, "eap_user_file") == 0) {
+                       if (hostapd_config_read_eap_user(pos, bss))
+                               errors++;
+               } else if (os_strcmp(buf, "ca_cert") == 0) {
+                       os_free(bss->ca_cert);
+                       bss->ca_cert = os_strdup(pos);
+               } else if (os_strcmp(buf, "server_cert") == 0) {
+                       os_free(bss->server_cert);
+                       bss->server_cert = os_strdup(pos);
+               } else if (os_strcmp(buf, "private_key") == 0) {
+                       os_free(bss->private_key);
+                       bss->private_key = os_strdup(pos);
+               } else if (os_strcmp(buf, "private_key_passwd") == 0) {
+                       os_free(bss->private_key_passwd);
+                       bss->private_key_passwd = os_strdup(pos);
+               } else if (os_strcmp(buf, "check_crl") == 0) {
+                       bss->check_crl = atoi(pos);
+               } else if (os_strcmp(buf, "dh_file") == 0) {
+                       os_free(bss->dh_file);
+                       bss->dh_file = os_strdup(pos);
+               } else if (os_strcmp(buf, "fragment_size") == 0) {
+                       bss->fragment_size = atoi(pos);
+#ifdef EAP_SERVER_FAST
+               } else if (os_strcmp(buf, "pac_opaque_encr_key") == 0) {
+                       os_free(bss->pac_opaque_encr_key);
+                       bss->pac_opaque_encr_key = os_malloc(16);
+                       if (bss->pac_opaque_encr_key == NULL) {
+                               wpa_printf(MSG_ERROR, "Line %d: No memory for "
+                                          "pac_opaque_encr_key", line);
+                               errors++;
+                       } else if (hexstr2bin(pos, bss->pac_opaque_encr_key,
+                                             16)) {
+                               wpa_printf(MSG_ERROR, "Line %d: Invalid "
+                                          "pac_opaque_encr_key", line);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "eap_fast_a_id") == 0) {
+                       size_t idlen = os_strlen(pos);
+                       if (idlen & 1) {
+                               wpa_printf(MSG_ERROR, "Line %d: Invalid "
+                                          "eap_fast_a_id", line);
+                               errors++;
+                       } else {
+                               os_free(bss->eap_fast_a_id);
+                               bss->eap_fast_a_id = os_malloc(idlen / 2);
+                               if (bss->eap_fast_a_id == NULL ||
+                                   hexstr2bin(pos, bss->eap_fast_a_id,
+                                              idlen / 2)) {
+                                       wpa_printf(MSG_ERROR, "Line %d: "
+                                                  "Failed to parse "
+                                                  "eap_fast_a_id", line);
+                                       errors++;
+                               } else
+                                       bss->eap_fast_a_id_len = idlen / 2;
+                       }
+               } else if (os_strcmp(buf, "eap_fast_a_id_info") == 0) {
+                       os_free(bss->eap_fast_a_id_info);
+                       bss->eap_fast_a_id_info = os_strdup(pos);
+               } else if (os_strcmp(buf, "eap_fast_prov") == 0) {
+                       bss->eap_fast_prov = atoi(pos);
+               } else if (os_strcmp(buf, "pac_key_lifetime") == 0) {
+                       bss->pac_key_lifetime = atoi(pos);
+               } else if (os_strcmp(buf, "pac_key_refresh_time") == 0) {
+                       bss->pac_key_refresh_time = atoi(pos);
+#endif /* EAP_SERVER_FAST */
+#ifdef EAP_SERVER_SIM
+               } else if (os_strcmp(buf, "eap_sim_db") == 0) {
+                       os_free(bss->eap_sim_db);
+                       bss->eap_sim_db = os_strdup(pos);
+               } else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
+                       bss->eap_sim_aka_result_ind = atoi(pos);
+#endif /* EAP_SERVER_SIM */
+#ifdef EAP_SERVER_TNC
+               } else if (os_strcmp(buf, "tnc") == 0) {
+                       bss->tnc = atoi(pos);
+#endif /* EAP_SERVER_TNC */
+#ifdef EAP_SERVER_PWD
+               } else if (os_strcmp(buf, "pwd_group") == 0) {
+                       bss->pwd_group = atoi(pos);
+#endif /* EAP_SERVER_PWD */
+#endif /* EAP_SERVER */
+               } else if (os_strcmp(buf, "eap_message") == 0) {
+                       char *term;
+                       bss->eap_req_id_text = os_strdup(pos);
+                       if (bss->eap_req_id_text == NULL) {
+                               wpa_printf(MSG_ERROR, "Line %d: Failed to "
+                                          "allocate memory for "
+                                          "eap_req_id_text", line);
+                               errors++;
+                               continue;
+                       }
+                       bss->eap_req_id_text_len =
+                               os_strlen(bss->eap_req_id_text);
+                       term = os_strstr(bss->eap_req_id_text, "\\0");
+                       if (term) {
+                               *term++ = '\0';
+                               os_memmove(term, term + 1,
+                                          bss->eap_req_id_text_len -
+                                          (term - bss->eap_req_id_text) - 1);
+                               bss->eap_req_id_text_len--;
+                       }
+               } else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
+                       bss->default_wep_key_len = atoi(pos);
+                       if (bss->default_wep_key_len > 13) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
+                                          "key len %lu (= %lu bits)", line,
+                                          (unsigned long)
+                                          bss->default_wep_key_len,
+                                          (unsigned long)
+                                          bss->default_wep_key_len * 8);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "wep_key_len_unicast") == 0) {
+                       bss->individual_wep_key_len = atoi(pos);
+                       if (bss->individual_wep_key_len < 0 ||
+                           bss->individual_wep_key_len > 13) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
+                                          "key len %d (= %d bits)", line,
+                                          bss->individual_wep_key_len,
+                                          bss->individual_wep_key_len * 8);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "wep_rekey_period") == 0) {
+                       bss->wep_rekeying_period = atoi(pos);
+                       if (bss->wep_rekeying_period < 0) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "period %d",
+                                          line, bss->wep_rekeying_period);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "eap_reauth_period") == 0) {
+                       bss->eap_reauth_period = atoi(pos);
+                       if (bss->eap_reauth_period < 0) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "period %d",
+                                          line, bss->eap_reauth_period);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "eapol_key_index_workaround") == 0) {
+                       bss->eapol_key_index_workaround = atoi(pos);
+#ifdef CONFIG_IAPP
+               } else if (os_strcmp(buf, "iapp_interface") == 0) {
+                       bss->ieee802_11f = 1;
+                       os_strlcpy(bss->iapp_iface, pos,
+                                  sizeof(bss->iapp_iface));
+#endif /* CONFIG_IAPP */
+               } else if (os_strcmp(buf, "own_ip_addr") == 0) {
+                       if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid IP "
+                                          "address '%s'", line, pos);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "nas_identifier") == 0) {
+                       bss->nas_identifier = os_strdup(pos);
+#ifndef CONFIG_NO_RADIUS
+               } else if (os_strcmp(buf, "auth_server_addr") == 0) {
+                       if (hostapd_config_read_radius_addr(
+                                   &bss->radius->auth_servers,
+                                   &bss->radius->num_auth_servers, pos, 1812,
+                                   &bss->radius->auth_server)) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid IP "
+                                          "address '%s'", line, pos);
+                               errors++;
+                       }
+               } else if (bss->radius->auth_server &&
+                          os_strcmp(buf, "auth_server_port") == 0) {
+                       bss->radius->auth_server->port = atoi(pos);
+               } else if (bss->radius->auth_server &&
+                          os_strcmp(buf, "auth_server_shared_secret") == 0) {
+                       int len = os_strlen(pos);
+                       if (len == 0) {
+                               /* RFC 2865, Ch. 3 */
+                               wpa_printf(MSG_ERROR, "Line %d: empty shared "
+                                          "secret is not allowed.", line);
+                               errors++;
+                       }
+                       bss->radius->auth_server->shared_secret =
+                               (u8 *) os_strdup(pos);
+                       bss->radius->auth_server->shared_secret_len = len;
+               } else if (os_strcmp(buf, "acct_server_addr") == 0) {
+                       if (hostapd_config_read_radius_addr(
+                                   &bss->radius->acct_servers,
+                                   &bss->radius->num_acct_servers, pos, 1813,
+                                   &bss->radius->acct_server)) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid IP "
+                                          "address '%s'", line, pos);
+                               errors++;
+                       }
+               } else if (bss->radius->acct_server &&
+                          os_strcmp(buf, "acct_server_port") == 0) {
+                       bss->radius->acct_server->port = atoi(pos);
+               } else if (bss->radius->acct_server &&
+                          os_strcmp(buf, "acct_server_shared_secret") == 0) {
+                       int len = os_strlen(pos);
+                       if (len == 0) {
+                               /* RFC 2865, Ch. 3 */
+                               wpa_printf(MSG_ERROR, "Line %d: empty shared "
+                                          "secret is not allowed.", line);
+                               errors++;
+                       }
+                       bss->radius->acct_server->shared_secret =
+                               (u8 *) os_strdup(pos);
+                       bss->radius->acct_server->shared_secret_len = len;
+               } else if (os_strcmp(buf, "radius_retry_primary_interval") ==
+                          0) {
+                       bss->radius->retry_primary_interval = atoi(pos);
+               } else if (os_strcmp(buf, "radius_acct_interim_interval") == 0)
+               {
+                       bss->acct_interim_interval = atoi(pos);
+#endif /* CONFIG_NO_RADIUS */
+               } else if (os_strcmp(buf, "auth_algs") == 0) {
+                       bss->auth_algs = atoi(pos);
+                       if (bss->auth_algs == 0) {
+                               wpa_printf(MSG_ERROR, "Line %d: no "
+                                          "authentication algorithms allowed",
+                                          line);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "max_num_sta") == 0) {
+                       bss->max_num_sta = atoi(pos);
+                       if (bss->max_num_sta < 0 ||
+                           bss->max_num_sta > MAX_STA_COUNT) {
+                               wpa_printf(MSG_ERROR, "Line %d: Invalid "
+                                          "max_num_sta=%d; allowed range "
+                                          "0..%d", line, bss->max_num_sta,
+                                          MAX_STA_COUNT);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "wpa") == 0) {
+                       bss->wpa = atoi(pos);
+               } else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
+                       bss->wpa_group_rekey = atoi(pos);
+               } else if (os_strcmp(buf, "wpa_strict_rekey") == 0) {
+                       bss->wpa_strict_rekey = atoi(pos);
+               } else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) {
+                       bss->wpa_gmk_rekey = atoi(pos);
+               } else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
+                       bss->wpa_ptk_rekey = atoi(pos);
+               } else if (os_strcmp(buf, "wpa_passphrase") == 0) {
+                       int len = os_strlen(pos);
+                       if (len < 8 || len > 63) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid WPA "
+                                          "passphrase length %d (expected "
+                                          "8..63)", line, len);
+                               errors++;
+                       } else {
+                               os_free(bss->ssid.wpa_passphrase);
+                               bss->ssid.wpa_passphrase = os_strdup(pos);
+                       }
+               } else if (os_strcmp(buf, "wpa_psk") == 0) {
+                       os_free(bss->ssid.wpa_psk);
+                       bss->ssid.wpa_psk =
+                               os_zalloc(sizeof(struct hostapd_wpa_psk));
+                       if (bss->ssid.wpa_psk == NULL)
+                               errors++;
+                       else if (hexstr2bin(pos, bss->ssid.wpa_psk->psk,
+                                           PMK_LEN) ||
+                                pos[PMK_LEN * 2] != '\0') {
+                               wpa_printf(MSG_ERROR, "Line %d: Invalid PSK "
+                                          "'%s'.", line, pos);
+                               errors++;
+                       } else {
+                               bss->ssid.wpa_psk->group = 1;
+                       }
+               } else if (os_strcmp(buf, "wpa_psk_file") == 0) {
+                       os_free(bss->ssid.wpa_psk_file);
+                       bss->ssid.wpa_psk_file = os_strdup(pos);
+                       if (!bss->ssid.wpa_psk_file) {
+                               wpa_printf(MSG_ERROR, "Line %d: allocation "
+                                          "failed", line);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "wpa_key_mgmt") == 0) {
+                       bss->wpa_key_mgmt =
+                               hostapd_config_parse_key_mgmt(line, pos);
+                       if (bss->wpa_key_mgmt == -1)
+                               errors++;
+               } else if (os_strcmp(buf, "wpa_psk_radius") == 0) {
+                       bss->wpa_psk_radius = atoi(pos);
+                       if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
+                           bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED &&
+                           bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) {
+                               wpa_printf(MSG_ERROR, "Line %d: unknown "
+                                          "wpa_psk_radius %d",
+                                          line, bss->wpa_psk_radius);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "wpa_pairwise") == 0) {
+                       bss->wpa_pairwise =
+                               hostapd_config_parse_cipher(line, pos);
+                       if (bss->wpa_pairwise == -1 ||
+                           bss->wpa_pairwise == 0)
+                               errors++;
+                       else if (bss->wpa_pairwise &
+                                (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
+                                 WPA_CIPHER_WEP104)) {
+                               wpa_printf(MSG_ERROR, "Line %d: unsupported "
+                                          "pairwise cipher suite '%s'",
+                                          bss->wpa_pairwise, pos);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "rsn_pairwise") == 0) {
+                       bss->rsn_pairwise =
+                               hostapd_config_parse_cipher(line, pos);
+                       if (bss->rsn_pairwise == -1 ||
+                           bss->rsn_pairwise == 0)
+                               errors++;
+                       else if (bss->rsn_pairwise &
+                                (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
+                                 WPA_CIPHER_WEP104)) {
+                               wpa_printf(MSG_ERROR, "Line %d: unsupported "
+                                          "pairwise cipher suite '%s'",
+                                          bss->rsn_pairwise, pos);
+                               errors++;
+                       }
+#ifdef CONFIG_RSN_PREAUTH
+               } else if (os_strcmp(buf, "rsn_preauth") == 0) {
+                       bss->rsn_preauth = atoi(pos);
+               } else if (os_strcmp(buf, "rsn_preauth_interfaces") == 0) {
+                       bss->rsn_preauth_interfaces = os_strdup(pos);
+#endif /* CONFIG_RSN_PREAUTH */
+#ifdef CONFIG_PEERKEY
+               } else if (os_strcmp(buf, "peerkey") == 0) {
+                       bss->peerkey = atoi(pos);
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_IEEE80211R
+               } else if (os_strcmp(buf, "mobility_domain") == 0) {
+                       if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN ||
+                           hexstr2bin(pos, bss->mobility_domain,
+                                      MOBILITY_DOMAIN_ID_LEN) != 0) {
+                               wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+                                          "mobility_domain '%s'", line, pos);
+                               errors++;
+                               continue;
+                       }
+               } else if (os_strcmp(buf, "r1_key_holder") == 0) {
+                       if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN ||
+                           hexstr2bin(pos, bss->r1_key_holder,
+                                      FT_R1KH_ID_LEN) != 0) {
+                               wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+                                          "r1_key_holder '%s'", line, pos);
+                               errors++;
+                               continue;
+                       }
+               } else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
+                       bss->r0_key_lifetime = atoi(pos);
+               } else if (os_strcmp(buf, "reassociation_deadline") == 0) {
+                       bss->reassociation_deadline = atoi(pos);
+               } else if (os_strcmp(buf, "r0kh") == 0) {
+                       if (add_r0kh(bss, pos) < 0) {
+                               wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+                                          "r0kh '%s'", line, pos);
+                               errors++;
+                               continue;
+                       }
+               } else if (os_strcmp(buf, "r1kh") == 0) {
+                       if (add_r1kh(bss, pos) < 0) {
+                               wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+                                          "r1kh '%s'", line, pos);
+                               errors++;
+                               continue;
+                       }
+               } else if (os_strcmp(buf, "pmk_r1_push") == 0) {
+                       bss->pmk_r1_push = atoi(pos);
+               } else if (os_strcmp(buf, "ft_over_ds") == 0) {
+                       bss->ft_over_ds = atoi(pos);
+#endif /* CONFIG_IEEE80211R */
+#ifndef CONFIG_NO_CTRL_IFACE
+               } else if (os_strcmp(buf, "ctrl_interface") == 0) {
+                       os_free(bss->ctrl_interface);
+                       bss->ctrl_interface = os_strdup(pos);
+               } else if (os_strcmp(buf, "ctrl_interface_group") == 0) {
+#ifndef CONFIG_NATIVE_WINDOWS
+                       struct group *grp;
+                       char *endp;
+                       const char *group = pos;
+
+                       grp = getgrnam(group);
+                       if (grp) {
+                               bss->ctrl_interface_gid = grp->gr_gid;
+                               bss->ctrl_interface_gid_set = 1;
+                               wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
+                                          " (from group name '%s')",
+                                          bss->ctrl_interface_gid, group);
+                               continue;
+                       }
+
+                       /* Group name not found - try to parse this as gid */
+                       bss->ctrl_interface_gid = strtol(group, &endp, 10);
+                       if (*group == '\0' || *endp != '\0') {
+                               wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
+                                          "'%s'", line, group);
+                               errors++;
+                               continue;
+                       }
+                       bss->ctrl_interface_gid_set = 1;
+                       wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
+                                  bss->ctrl_interface_gid);
+#endif /* CONFIG_NATIVE_WINDOWS */
+#endif /* CONFIG_NO_CTRL_IFACE */
+#ifdef RADIUS_SERVER
+               } else if (os_strcmp(buf, "radius_server_clients") == 0) {
+                       os_free(bss->radius_server_clients);
+                       bss->radius_server_clients = os_strdup(pos);
+               } else if (os_strcmp(buf, "radius_server_auth_port") == 0) {
+                       bss->radius_server_auth_port = atoi(pos);
+               } else if (os_strcmp(buf, "radius_server_ipv6") == 0) {
+                       bss->radius_server_ipv6 = atoi(pos);
+#endif /* RADIUS_SERVER */
+               } else if (os_strcmp(buf, "test_socket") == 0) {
+                       os_free(bss->test_socket);
+                       bss->test_socket = os_strdup(pos);
+               } else if (os_strcmp(buf, "use_pae_group_addr") == 0) {
+                       bss->use_pae_group_addr = atoi(pos);
+               } else if (os_strcmp(buf, "hw_mode") == 0) {
+                       if (os_strcmp(pos, "a") == 0)
+                               conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
+                       else if (os_strcmp(pos, "b") == 0)
+                               conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
+                       else if (os_strcmp(pos, "g") == 0)
+                               conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
+                       else {
+                               wpa_printf(MSG_ERROR, "Line %d: unknown "
+                                          "hw_mode '%s'", line, pos);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "wps_rf_bands") == 0) {
+                       if (os_strcmp(pos, "a") == 0)
+                               bss->wps_rf_bands = WPS_RF_50GHZ;
+                       else if (os_strcmp(pos, "g") == 0 ||
+                                os_strcmp(pos, "b") == 0)
+                               bss->wps_rf_bands = WPS_RF_24GHZ;
+                       else if (os_strcmp(pos, "ag") == 0 ||
+                                os_strcmp(pos, "ga") == 0)
+                               bss->wps_rf_bands =
+                                       WPS_RF_24GHZ | WPS_RF_50GHZ;
+                       else {
+                               wpa_printf(MSG_ERROR, "Line %d: unknown "
+                                          "wps_rf_band '%s'", line, pos);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "channel") == 0) {
+                       conf->channel = atoi(pos);
+               } else if (os_strcmp(buf, "beacon_int") == 0) {
+                       int val = atoi(pos);
+                       /* MIB defines range as 1..65535, but very small values
+                        * cause problems with the current implementation.
+                        * Since it is unlikely that this small numbers are
+                        * useful in real life scenarios, do not allow beacon
+                        * period to be set below 15 TU. */
+                       if (val < 15 || val > 65535) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "beacon_int %d (expected "
+                                          "15..65535)", line, val);
+                               errors++;
+                       } else
+                               conf->beacon_int = val;
+               } else if (os_strcmp(buf, "dtim_period") == 0) {
+                       bss->dtim_period = atoi(pos);
+                       if (bss->dtim_period < 1 || bss->dtim_period > 255) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "dtim_period %d",
+                                          line, bss->dtim_period);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "rts_threshold") == 0) {
+                       conf->rts_threshold = atoi(pos);
+                       if (conf->rts_threshold < 0 ||
+                           conf->rts_threshold > 2347) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "rts_threshold %d",
+                                          line, conf->rts_threshold);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "fragm_threshold") == 0) {
+                       conf->fragm_threshold = atoi(pos);
+                       if (conf->fragm_threshold < 256 ||
+                           conf->fragm_threshold > 2346) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "fragm_threshold %d",
+                                          line, conf->fragm_threshold);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "send_probe_response") == 0) {
+                       int val = atoi(pos);
+                       if (val != 0 && val != 1) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "send_probe_response %d (expected "
+                                          "0 or 1)", line, val);
+                       } else
+                               conf->send_probe_response = val;
+               } else if (os_strcmp(buf, "supported_rates") == 0) {
+                       if (hostapd_parse_rates(&conf->supported_rates, pos)) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid rate "
+                                          "list", line);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "basic_rates") == 0) {
+                       if (hostapd_parse_rates(&conf->basic_rates, pos)) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid rate "
+                                          "list", line);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "preamble") == 0) {
+                       if (atoi(pos))
+                               conf->preamble = SHORT_PREAMBLE;
+                       else
+                               conf->preamble = LONG_PREAMBLE;
+               } else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
+                       bss->ignore_broadcast_ssid = atoi(pos);
+               } else if (os_strcmp(buf, "wep_default_key") == 0) {
+                       bss->ssid.wep.idx = atoi(pos);
+                       if (bss->ssid.wep.idx > 3) {
+                               wpa_printf(MSG_ERROR, "Invalid "
+                                          "wep_default_key index %d",
+                                          bss->ssid.wep.idx);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "wep_key0") == 0 ||
+                          os_strcmp(buf, "wep_key1") == 0 ||
+                          os_strcmp(buf, "wep_key2") == 0 ||
+                          os_strcmp(buf, "wep_key3") == 0) {
+                       if (hostapd_config_read_wep(&bss->ssid.wep,
+                                                   buf[7] - '0', pos)) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
+                                          "key '%s'", line, buf);
+                               errors++;
+                       }
+#ifndef CONFIG_NO_VLAN
+               } else if (os_strcmp(buf, "dynamic_vlan") == 0) {
+                       bss->ssid.dynamic_vlan = atoi(pos);
+               } else if (os_strcmp(buf, "vlan_file") == 0) {
+                       if (hostapd_config_read_vlan_file(bss, pos)) {
+                               wpa_printf(MSG_ERROR, "Line %d: failed to "
+                                          "read VLAN file '%s'", line, pos);
+                               errors++;
+                       }
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+               } else if (os_strcmp(buf, "vlan_tagged_interface") == 0) {
+                       bss->ssid.vlan_tagged_interface = os_strdup(pos);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+#endif /* CONFIG_NO_VLAN */
+               } else if (os_strcmp(buf, "ap_table_max_size") == 0) {
+                       conf->ap_table_max_size = atoi(pos);
+               } else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
+                       conf->ap_table_expiration_time = atoi(pos);
+               } else if (os_strncmp(buf, "tx_queue_", 9) == 0) {
+                       if (hostapd_config_tx_queue(conf, buf, pos)) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid TX "
+                                          "queue item", line);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "wme_enabled") == 0 ||
+                          os_strcmp(buf, "wmm_enabled") == 0) {
+                       bss->wmm_enabled = atoi(pos);
+               } else if (os_strcmp(buf, "uapsd_advertisement_enabled") == 0) {
+                       bss->wmm_uapsd = atoi(pos);
+               } else if (os_strncmp(buf, "wme_ac_", 7) == 0 ||
+                          os_strncmp(buf, "wmm_ac_", 7) == 0) {
+                       if (hostapd_config_wmm_ac(conf, buf, pos)) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
+                                          "ac item", line);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "bss") == 0) {
+                       if (hostapd_config_bss(conf, pos)) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid bss "
+                                          "item", line);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "bssid") == 0) {
+                       if (hwaddr_aton(pos, bss->bssid)) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid bssid "
+                                          "item", line);
+                               errors++;
+                       }
+#ifdef CONFIG_IEEE80211W
+               } else if (os_strcmp(buf, "ieee80211w") == 0) {
+                       bss->ieee80211w = atoi(pos);
+               } else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
+                       bss->assoc_sa_query_max_timeout = atoi(pos);
+                       if (bss->assoc_sa_query_max_timeout == 0) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "assoc_sa_query_max_timeout", line);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "assoc_sa_query_retry_timeout") == 0)
+               {
+                       bss->assoc_sa_query_retry_timeout = atoi(pos);
+                       if (bss->assoc_sa_query_retry_timeout == 0) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "assoc_sa_query_retry_timeout",
+                                          line);
+                               errors++;
+                       }
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211N
+               } else if (os_strcmp(buf, "ieee80211n") == 0) {
+                       conf->ieee80211n = atoi(pos);
+               } else if (os_strcmp(buf, "ht_capab") == 0) {
+                       if (hostapd_config_ht_capab(conf, pos) < 0) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "ht_capab", line);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "require_ht") == 0) {
+                       conf->require_ht = atoi(pos);
+#endif /* CONFIG_IEEE80211N */
+               } else if (os_strcmp(buf, "max_listen_interval") == 0) {
+                       bss->max_listen_interval = atoi(pos);
+               } else if (os_strcmp(buf, "disable_pmksa_caching") == 0) {
+                       bss->disable_pmksa_caching = atoi(pos);
+               } else if (os_strcmp(buf, "okc") == 0) {
+                       bss->okc = atoi(pos);
+#ifdef CONFIG_WPS
+               } else if (os_strcmp(buf, "wps_state") == 0) {
+                       bss->wps_state = atoi(pos);
+                       if (bss->wps_state < 0 || bss->wps_state > 2) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "wps_state", line);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "ap_setup_locked") == 0) {
+                       bss->ap_setup_locked = atoi(pos);
+               } else if (os_strcmp(buf, "uuid") == 0) {
+                       if (uuid_str2bin(pos, bss->uuid)) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid UUID",
+                                          line);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "wps_pin_requests") == 0) {
+                       os_free(bss->wps_pin_requests);
+                       bss->wps_pin_requests = os_strdup(pos);
+               } else if (os_strcmp(buf, "device_name") == 0) {
+                       if (os_strlen(pos) > 32) {
+                               wpa_printf(MSG_ERROR, "Line %d: Too long "
+                                          "device_name", line);
+                               errors++;
+                       }
+                       os_free(bss->device_name);
+                       bss->device_name = os_strdup(pos);
+               } else if (os_strcmp(buf, "manufacturer") == 0) {
+                       if (os_strlen(pos) > 64) {
+                               wpa_printf(MSG_ERROR, "Line %d: Too long "
+                                          "manufacturer", line);
+                               errors++;
+                       }
+                       os_free(bss->manufacturer);
+                       bss->manufacturer = os_strdup(pos);
+               } else if (os_strcmp(buf, "model_name") == 0) {
+                       if (os_strlen(pos) > 32) {
+                               wpa_printf(MSG_ERROR, "Line %d: Too long "
+                                          "model_name", line);
+                               errors++;
+                       }
+                       os_free(bss->model_name);
+                       bss->model_name = os_strdup(pos);
+               } else if (os_strcmp(buf, "model_number") == 0) {
+                       if (os_strlen(pos) > 32) {
+                               wpa_printf(MSG_ERROR, "Line %d: Too long "
+                                          "model_number", line);
+                               errors++;
+                       }
+                       os_free(bss->model_number);
+                       bss->model_number = os_strdup(pos);
+               } else if (os_strcmp(buf, "serial_number") == 0) {
+                       if (os_strlen(pos) > 32) {
+                               wpa_printf(MSG_ERROR, "Line %d: Too long "
+                                          "serial_number", line);
+                               errors++;
+                       }
+                       os_free(bss->serial_number);
+                       bss->serial_number = os_strdup(pos);
+               } else if (os_strcmp(buf, "device_type") == 0) {
+                       if (wps_dev_type_str2bin(pos, bss->device_type))
+                               errors++;
+               } else if (os_strcmp(buf, "config_methods") == 0) {
+                       os_free(bss->config_methods);
+                       bss->config_methods = os_strdup(pos);
+               } else if (os_strcmp(buf, "os_version") == 0) {
+                       if (hexstr2bin(pos, bss->os_version, 4)) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "os_version", line);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "ap_pin") == 0) {
+                       os_free(bss->ap_pin);
+                       bss->ap_pin = os_strdup(pos);
+               } else if (os_strcmp(buf, "skip_cred_build") == 0) {
+                       bss->skip_cred_build = atoi(pos);
+               } else if (os_strcmp(buf, "extra_cred") == 0) {
+                       os_free(bss->extra_cred);
+                       bss->extra_cred =
+                               (u8 *) os_readfile(pos, &bss->extra_cred_len);
+                       if (bss->extra_cred == NULL) {
+                               wpa_printf(MSG_ERROR, "Line %d: could not "
+                                          "read Credentials from '%s'",
+                                          line, pos);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "wps_cred_processing") == 0) {
+                       bss->wps_cred_processing = atoi(pos);
+               } else if (os_strcmp(buf, "ap_settings") == 0) {
+                       os_free(bss->ap_settings);
+                       bss->ap_settings =
+                               (u8 *) os_readfile(pos, &bss->ap_settings_len);
+                       if (bss->ap_settings == NULL) {
+                               wpa_printf(MSG_ERROR, "Line %d: could not "
+                                          "read AP Settings from '%s'",
+                                          line, pos);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "upnp_iface") == 0) {
+                       bss->upnp_iface = os_strdup(pos);
+               } else if (os_strcmp(buf, "friendly_name") == 0) {
+                       os_free(bss->friendly_name);
+                       bss->friendly_name = os_strdup(pos);
+               } else if (os_strcmp(buf, "manufacturer_url") == 0) {
+                       os_free(bss->manufacturer_url);
+                       bss->manufacturer_url = os_strdup(pos);
+               } else if (os_strcmp(buf, "model_description") == 0) {
+                       os_free(bss->model_description);
+                       bss->model_description = os_strdup(pos);
+               } else if (os_strcmp(buf, "model_url") == 0) {
+                       os_free(bss->model_url);
+                       bss->model_url = os_strdup(pos);
+               } else if (os_strcmp(buf, "upc") == 0) {
+                       os_free(bss->upc);
+                       bss->upc = os_strdup(pos);
+               } else if (os_strcmp(buf, "pbc_in_m1") == 0) {
+                       bss->pbc_in_m1 = atoi(pos);
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P_MANAGER
+               } else if (os_strcmp(buf, "manage_p2p") == 0) {
+                       int manage = atoi(pos);
+                       if (manage)
+                               bss->p2p |= P2P_MANAGE;
+                       else
+                               bss->p2p &= ~P2P_MANAGE;
+               } else if (os_strcmp(buf, "allow_cross_connection") == 0) {
+                       if (atoi(pos))
+                               bss->p2p |= P2P_ALLOW_CROSS_CONNECTION;
+                       else
+                               bss->p2p &= ~P2P_ALLOW_CROSS_CONNECTION;
+#endif /* CONFIG_P2P_MANAGER */
+               } else if (os_strcmp(buf, "disassoc_low_ack") == 0) {
+                       bss->disassoc_low_ack = atoi(pos);
+               } else if (os_strcmp(buf, "tdls_prohibit") == 0) {
+                       int val = atoi(pos);
+                       if (val)
+                               bss->tdls |= TDLS_PROHIBIT;
+                       else
+                               bss->tdls &= ~TDLS_PROHIBIT;
+               } else if (os_strcmp(buf, "tdls_prohibit_chan_switch") == 0) {
+                       int val = atoi(pos);
+                       if (val)
+                               bss->tdls |= TDLS_PROHIBIT_CHAN_SWITCH;
+                       else
+                               bss->tdls &= ~TDLS_PROHIBIT_CHAN_SWITCH;
+#ifdef CONFIG_RSN_TESTING
+               } else if (os_strcmp(buf, "rsn_testing") == 0) {
+                       extern int rsn_testing;
+                       rsn_testing = atoi(pos);
+#endif /* CONFIG_RSN_TESTING */
+               } else if (os_strcmp(buf, "time_advertisement") == 0) {
+                       bss->time_advertisement = atoi(pos);
+               } else if (os_strcmp(buf, "time_zone") == 0) {
+                       size_t tz_len = os_strlen(pos);
+                       if (tz_len < 4 || tz_len > 255) {
+                               wpa_printf(MSG_DEBUG, "Line %d: invalid "
+                                          "time_zone", line);
+                               errors++;
+                               continue;
+                       }
+                       os_free(bss->time_zone);
+                       bss->time_zone = os_strdup(pos);
+                       if (bss->time_zone == NULL)
+                               errors++;
+#ifdef CONFIG_INTERWORKING
+               } else if (os_strcmp(buf, "interworking") == 0) {
+                       bss->interworking = atoi(pos);
+               } else if (os_strcmp(buf, "access_network_type") == 0) {
+                       bss->access_network_type = atoi(pos);
+                       if (bss->access_network_type < 0 ||
+                           bss->access_network_type > 15) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "access_network_type", line);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "internet") == 0) {
+                       bss->internet = atoi(pos);
+               } else if (os_strcmp(buf, "asra") == 0) {
+                       bss->asra = atoi(pos);
+               } else if (os_strcmp(buf, "esr") == 0) {
+                       bss->esr = atoi(pos);
+               } else if (os_strcmp(buf, "uesa") == 0) {
+                       bss->uesa = atoi(pos);
+               } else if (os_strcmp(buf, "venue_group") == 0) {
+                       bss->venue_group = atoi(pos);
+                       bss->venue_info_set = 1;
+               } else if (os_strcmp(buf, "venue_type") == 0) {
+                       bss->venue_type = atoi(pos);
+                       bss->venue_info_set = 1;
+               } else if (os_strcmp(buf, "hessid") == 0) {
+                       if (hwaddr_aton(pos, bss->hessid)) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "hessid", line);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "roaming_consortium") == 0) {
+                       if (parse_roaming_consortium(bss, pos, line) < 0)
+                               errors++;
+#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 */
+               } else {
+                       wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
+                                  "item '%s'", line, buf);
+                       errors++;
+               }
+       }
+
+       fclose(f);
+
+       for (i = 0; i < conf->num_bss; i++) {
+               bss = &conf->bss[i];
+
+               if (bss->individual_wep_key_len == 0) {
+                       /* individual keys are not use; can use key idx0 for
+                        * broadcast keys */
+                       bss->broadcast_key_idx_min = 0;
+               }
+
+               /* Select group cipher based on the enabled pairwise cipher
+                * suites */
+               pairwise = 0;
+               if (bss->wpa & 1)
+                       pairwise |= bss->wpa_pairwise;
+               if (bss->wpa & 2) {
+                       if (bss->rsn_pairwise == 0)
+                               bss->rsn_pairwise = bss->wpa_pairwise;
+                       pairwise |= bss->rsn_pairwise;
+               }
+               if (pairwise & WPA_CIPHER_TKIP)
+                       bss->wpa_group = WPA_CIPHER_TKIP;
+               else
+                       bss->wpa_group = WPA_CIPHER_CCMP;
+
+               bss->radius->auth_server = bss->radius->auth_servers;
+               bss->radius->acct_server = bss->radius->acct_servers;
+
+               if (bss->wpa && bss->ieee802_1x) {
+                       bss->ssid.security_policy = SECURITY_WPA;
+               } else if (bss->wpa) {
+                       bss->ssid.security_policy = SECURITY_WPA_PSK;
+               } else if (bss->ieee802_1x) {
+                       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 (hostapd_config_check(conf))
+               errors++;
+
+#ifndef WPA_IGNORE_CONFIG_ERRORS
+       if (errors) {
+               wpa_printf(MSG_ERROR, "%d errors found in configuration file "
+                          "'%s'", errors, fname);
+               hostapd_config_free(conf);
+               conf = NULL;
+       }
+#endif /* WPA_IGNORE_CONFIG_ERRORS */
+
+       return conf;
+}
diff --git a/hostapd/config_file.h b/hostapd/config_file.h
new file mode 100644 (file)
index 0000000..7111a9a
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+#ifndef CONFIG_FILE_H
+#define CONFIG_FILE_H
+
+struct hostapd_config * hostapd_config_read(const char *fname);
+
+#endif /* CONFIG_FILE_H */
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
new file mode 100644 (file)
index 0000000..a38d77c
--- /dev/null
@@ -0,0 +1,1186 @@
+/*
+ * hostapd / UNIX domain socket -based control interface
+ * 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.
+ */
+
+#include "utils/includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
+
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/version.h"
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+#include "radius/radius_client.h"
+#include "ap/hostapd.h"
+#include "ap/ap_config.h"
+#include "ap/ieee802_1x.h"
+#include "ap/wpa_auth.h"
+#include "ap/ieee802_11.h"
+#include "ap/sta_info.h"
+#include "ap/wps_hostapd.h"
+#include "ap/ctrl_iface_ap.h"
+#include "ap/ap_drv_ops.h"
+#include "wps/wps_defs.h"
+#include "wps/wps.h"
+#include "ctrl_iface.h"
+
+
+struct wpa_ctrl_dst {
+       struct wpa_ctrl_dst *next;
+       struct sockaddr_un addr;
+       socklen_t addrlen;
+       int debug_level;
+       int errors;
+};
+
+
+static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+                                   const char *buf, size_t len);
+
+
+static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
+                                    struct sockaddr_un *from,
+                                    socklen_t fromlen)
+{
+       struct wpa_ctrl_dst *dst;
+
+       dst = os_zalloc(sizeof(*dst));
+       if (dst == NULL)
+               return -1;
+       os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
+       dst->addrlen = fromlen;
+       dst->debug_level = MSG_INFO;
+       dst->next = hapd->ctrl_dst;
+       hapd->ctrl_dst = dst;
+       wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
+                   (u8 *) from->sun_path,
+                   fromlen - offsetof(struct sockaddr_un, sun_path));
+       return 0;
+}
+
+
+static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
+                                    struct sockaddr_un *from,
+                                    socklen_t fromlen)
+{
+       struct wpa_ctrl_dst *dst, *prev = NULL;
+
+       dst = hapd->ctrl_dst;
+       while (dst) {
+               if (fromlen == dst->addrlen &&
+                   os_memcmp(from->sun_path, dst->addr.sun_path,
+                             fromlen - offsetof(struct sockaddr_un, sun_path))
+                   == 0) {
+                       if (prev == NULL)
+                               hapd->ctrl_dst = dst->next;
+                       else
+                               prev->next = dst->next;
+                       os_free(dst);
+                       wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
+                                   (u8 *) from->sun_path,
+                                   fromlen -
+                                   offsetof(struct sockaddr_un, sun_path));
+                       return 0;
+               }
+               prev = dst;
+               dst = dst->next;
+       }
+       return -1;
+}
+
+
+static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
+                                   struct sockaddr_un *from,
+                                   socklen_t fromlen,
+                                   char *level)
+{
+       struct wpa_ctrl_dst *dst;
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
+
+       dst = hapd->ctrl_dst;
+       while (dst) {
+               if (fromlen == dst->addrlen &&
+                   os_memcmp(from->sun_path, dst->addr.sun_path,
+                             fromlen - offsetof(struct sockaddr_un, sun_path))
+                   == 0) {
+                       wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
+                                   "level", (u8 *) from->sun_path, fromlen -
+                                   offsetof(struct sockaddr_un, sun_path));
+                       dst->debug_level = atoi(level);
+                       return 0;
+               }
+               dst = dst->next;
+       }
+
+       return -1;
+}
+
+
+static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
+                                     const char *txtaddr)
+{
+       u8 addr[ETH_ALEN];
+       struct sta_info *sta;
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
+
+       if (hwaddr_aton(txtaddr, addr))
+               return -1;
+
+       sta = ap_get_sta(hapd, addr);
+       if (sta)
+               return 0;
+
+       wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
+                  "notification", MAC2STR(addr));
+       sta = ap_sta_add(hapd, addr);
+       if (sta == NULL)
+               return -1;
+
+       hostapd_new_assoc_sta(hapd, sta, 0);
+       return 0;
+}
+
+
+#ifdef CONFIG_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,
+                                      const char *txtaddr)
+{
+       u8 addr[ETH_ALEN];
+       u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
+
+       if (hwaddr_aton(txtaddr, addr) ||
+           os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
+               return -1;
+
+       ieee802_11_send_sa_query_req(hapd, addr, trans_id);
+
+       return 0;
+}
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_IEEE80211W */
+
+
+#ifdef CONFIG_WPS
+static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
+{
+       char *pin = os_strchr(txt, ' ');
+       char *timeout_txt;
+       int timeout;
+       u8 addr_buf[ETH_ALEN], *addr = NULL;
+       char *pos;
+
+       if (pin == NULL)
+               return -1;
+       *pin++ = '\0';
+
+       timeout_txt = os_strchr(pin, ' ');
+       if (timeout_txt) {
+               *timeout_txt++ = '\0';
+               timeout = atoi(timeout_txt);
+               pos = os_strchr(timeout_txt, ' ');
+               if (pos) {
+                       *pos++ = '\0';
+                       if (hwaddr_aton(pos, addr_buf) == 0)
+                               addr = addr_buf;
+               }
+       } else
+               timeout = 0;
+
+       return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
+}
+
+
+static int hostapd_ctrl_iface_wps_check_pin(
+       struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen)
+{
+       char pin[9];
+       size_t len;
+       char *pos;
+       int ret;
+
+       wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
+                             (u8 *) cmd, os_strlen(cmd));
+       for (pos = cmd, len = 0; *pos != '\0'; pos++) {
+               if (*pos < '0' || *pos > '9')
+                       continue;
+               pin[len++] = *pos;
+               if (len == 9) {
+                       wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
+                       return -1;
+               }
+       }
+       if (len != 4 && len != 8) {
+               wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
+               return -1;
+       }
+       pin[len] = '\0';
+
+       if (len == 8) {
+               unsigned int pin_val;
+               pin_val = atoi(pin);
+               if (!wps_pin_valid(pin_val)) {
+                       wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
+                       ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
+                       if (ret < 0 || (size_t) ret >= buflen)
+                               return -1;
+                       return ret;
+               }
+       }
+
+       ret = os_snprintf(buf, buflen, "%s", pin);
+       if (ret < 0 || (size_t) ret >= buflen)
+               return -1;
+
+       return ret;
+}
+
+
+#ifdef CONFIG_WPS_OOB
+static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
+{
+       char *path, *method, *name;
+
+       path = os_strchr(txt, ' ');
+       if (path == NULL)
+               return -1;
+       *path++ = '\0';
+
+       method = os_strchr(path, ' ');
+       if (method == NULL)
+               return -1;
+       *method++ = '\0';
+
+       name = os_strchr(method, ' ');
+       if (name != NULL)
+               *name++ = '\0';
+
+       return hostapd_wps_start_oob(hapd, txt, path, method, name);
+}
+#endif /* CONFIG_WPS_OOB */
+
+
+static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
+                                        char *buf, size_t buflen)
+{
+       int timeout = 300;
+       char *pos;
+       const char *pin_txt;
+
+       pos = os_strchr(txt, ' ');
+       if (pos)
+               *pos++ = '\0';
+
+       if (os_strcmp(txt, "disable") == 0) {
+               hostapd_wps_ap_pin_disable(hapd);
+               return os_snprintf(buf, buflen, "OK\n");
+       }
+
+       if (os_strcmp(txt, "random") == 0) {
+               if (pos)
+                       timeout = atoi(pos);
+               pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
+               if (pin_txt == NULL)
+                       return -1;
+               return os_snprintf(buf, buflen, "%s", pin_txt);
+       }
+
+       if (os_strcmp(txt, "get") == 0) {
+               pin_txt = hostapd_wps_ap_pin_get(hapd);
+               if (pin_txt == NULL)
+                       return -1;
+               return os_snprintf(buf, buflen, "%s", pin_txt);
+       }
+
+       if (os_strcmp(txt, "set") == 0) {
+               char *pin;
+               if (pos == NULL)
+                       return -1;
+               pin = pos;
+               pos = os_strchr(pos, ' ');
+               if (pos) {
+                       *pos++ = '\0';
+                       timeout = atoi(pos);
+               }
+               if (os_strlen(pin) > buflen)
+                       return -1;
+               if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
+                       return -1;
+               return os_snprintf(buf, buflen, "%s", pin);
+       }
+
+       return -1;
+}
+
+
+static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
+{
+       char *pos;
+       char *ssid, *auth, *encr = NULL, *key = NULL;
+
+       ssid = txt;
+       pos = os_strchr(txt, ' ');
+       if (!pos)
+               return -1;
+       *pos++ = '\0';
+
+       auth = pos;
+       pos = os_strchr(pos, ' ');
+       if (pos) {
+               *pos++ = '\0';
+               encr = pos;
+               pos = os_strchr(pos, ' ');
+               if (pos) {
+                       *pos++ = '\0';
+                       key = pos;
+               }
+       }
+
+       return hostapd_wps_config_ap(hapd, ssid, auth, encr, key);
+}
+#endif /* CONFIG_WPS */
+
+
+static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
+                                          const char *cmd)
+{
+       u8 addr[ETH_ALEN];
+       const char *url;
+       u8 buf[1000], *pos;
+       struct ieee80211_mgmt *mgmt;
+       size_t url_len;
+
+       if (hwaddr_aton(cmd, addr))
+               return -1;
+       url = cmd + 17;
+       if (*url != ' ')
+               return -1;
+       url++;
+       url_len = os_strlen(url);
+       if (url_len > 255)
+               return -1;
+
+       os_memset(buf, 0, sizeof(buf));
+       mgmt = (struct ieee80211_mgmt *) buf;
+       mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+                                          WLAN_FC_STYPE_ACTION);
+       os_memcpy(mgmt->da, addr, ETH_ALEN);
+       os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+       os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+       mgmt->u.action.category = WLAN_ACTION_WNM;
+       mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
+       mgmt->u.action.u.bss_tm_req.dialog_token = 1;
+       mgmt->u.action.u.bss_tm_req.req_mode =
+               WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
+       mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
+       mgmt->u.action.u.bss_tm_req.validity_interval = 0;
+
+       pos = mgmt->u.action.u.bss_tm_req.variable;
+
+       /* Session Information URL */
+       *pos++ = url_len;
+       os_memcpy(pos, url, url_len);
+       pos += url_len;
+
+       if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+               wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
+                          "Management Request frame");
+               return -1;
+       }
+
+       return 0;
+}
+
+
+static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
+                                        char *buf, size_t buflen)
+{
+       int ret;
+       char *pos, *end;
+
+       pos = buf;
+       end = buf + buflen;
+
+       ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
+                         "ssid=%s\n",
+                         MAC2STR(hapd->own_addr),
+                         hapd->conf->ssid.ssid);
+       if (ret < 0 || ret >= end - pos)
+               return pos - buf;
+       pos += ret;
+
+#ifdef CONFIG_WPS
+       ret = os_snprintf(pos, end - pos, "wps_state=%s\n",
+                         hapd->conf->wps_state == 0 ? "disabled" :
+                         (hapd->conf->wps_state == 1 ? "not configured" :
+                          "configured"));
+       if (ret < 0 || ret >= end - pos)
+               return pos - buf;
+       pos += ret;
+
+       if (hapd->conf->wps_state && hapd->conf->wpa &&
+           hapd->conf->ssid.wpa_passphrase) {
+               ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
+                                 hapd->conf->ssid.wpa_passphrase);
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       }
+
+       if (hapd->conf->wps_state && hapd->conf->wpa &&
+           hapd->conf->ssid.wpa_psk &&
+           hapd->conf->ssid.wpa_psk->group) {
+               char hex[PMK_LEN * 2 + 1];
+               wpa_snprintf_hex(hex, sizeof(hex),
+                                hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
+               ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       }
+#endif /* CONFIG_WPS */
+
+       if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
+               ret = os_snprintf(pos, end - pos, "key_mgmt=");
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+
+               if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
+                       ret = os_snprintf(pos, end - pos, "WPA-PSK ");
+                       if (ret < 0 || ret >= end - pos)
+                               return pos - buf;
+                       pos += ret;
+               }
+               if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+                       ret = os_snprintf(pos, end - pos, "WPA-EAP ");
+                       if (ret < 0 || ret >= end - pos)
+                               return pos - buf;
+                       pos += ret;
+               }
+#ifdef CONFIG_IEEE80211R
+               if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
+                       ret = os_snprintf(pos, end - pos, "FT-PSK ");
+                       if (ret < 0 || ret >= end - pos)
+                               return pos - buf;
+                       pos += ret;
+               }
+               if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
+                       ret = os_snprintf(pos, end - pos, "FT-EAP ");
+                       if (ret < 0 || ret >= end - pos)
+                               return pos - buf;
+                       pos += ret;
+               }
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+               if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
+                       ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
+                       if (ret < 0 || ret >= end - pos)
+                               return pos - buf;
+                       pos += ret;
+               }
+               if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+                       ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
+                       if (ret < 0 || ret >= end - pos)
+                               return pos - buf;
+                       pos += ret;
+               }
+#endif /* CONFIG_IEEE80211W */
+
+               ret = os_snprintf(pos, end - pos, "\n");
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       }
+
+       if (hapd->conf->wpa && hapd->conf->wpa_group == WPA_CIPHER_CCMP) {
+               ret = os_snprintf(pos, end - pos, "group_cipher=CCMP\n");
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       } else if (hapd->conf->wpa &&
+                  hapd->conf->wpa_group == WPA_CIPHER_TKIP) {
+               ret = os_snprintf(pos, end - pos, "group_cipher=TKIP\n");
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       }
+
+       if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
+               ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+
+               if (hapd->conf->rsn_pairwise & WPA_CIPHER_CCMP) {
+                       ret = os_snprintf(pos, end - pos, "CCMP ");
+                       if (ret < 0 || ret >= end - pos)
+                               return pos - buf;
+                       pos += ret;
+               }
+               if (hapd->conf->rsn_pairwise & WPA_CIPHER_TKIP) {
+                       ret = os_snprintf(pos, end - pos, "TKIP ");
+                       if (ret < 0 || ret >= end - pos)
+                               return pos - buf;
+                       pos += ret;
+               }
+
+               ret = os_snprintf(pos, end - pos, "\n");
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       }
+
+       if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
+               ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+
+               if (hapd->conf->wpa_pairwise & WPA_CIPHER_CCMP) {
+                       ret = os_snprintf(pos, end - pos, "CCMP ");
+                       if (ret < 0 || ret >= end - pos)
+                               return pos - buf;
+                       pos += ret;
+               }
+               if (hapd->conf->wpa_pairwise & WPA_CIPHER_TKIP) {
+                       ret = os_snprintf(pos, end - pos, "TKIP ");
+                       if (ret < 0 || ret >= end - pos)
+                               return pos - buf;
+                       pos += ret;
+               }
+
+               ret = os_snprintf(pos, end - pos, "\n");
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       }
+
+       return pos - buf;
+}
+
+
+static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
+{
+       char *value;
+       int ret = 0;
+
+       value = os_strchr(cmd, ' ');
+       if (value == NULL)
+               return -1;
+       *value++ = '\0';
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
+       if (0) {
+#ifdef CONFIG_WPS_TESTING
+       } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
+               long int val;
+               val = strtol(value, NULL, 0);
+               if (val < 0 || val > 0xff) {
+                       ret = -1;
+                       wpa_printf(MSG_DEBUG, "WPS: Invalid "
+                                  "wps_version_number %ld", val);
+               } else {
+                       wps_version_number = val;
+                       wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
+                                  "version %u.%u",
+                                  (wps_version_number & 0xf0) >> 4,
+                                  wps_version_number & 0x0f);
+                       hostapd_wps_update_ie(hapd);
+               }
+       } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
+               wps_testing_dummy_cred = atoi(value);
+               wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
+                          wps_testing_dummy_cred);
+#endif /* CONFIG_WPS_TESTING */
+       } else {
+               ret = -1;
+       }
+
+       return ret;
+}
+
+
+static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
+                                 char *buf, size_t buflen)
+{
+       int res;
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
+
+       if (os_strcmp(cmd, "version") == 0) {
+               res = os_snprintf(buf, buflen, "%s", VERSION_STR);
+               if (res < 0 || (unsigned int) res >= buflen)
+                       return -1;
+               return res;
+       }
+
+       return -1;
+}
+
+
+static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
+                                      void *sock_ctx)
+{
+       struct hostapd_data *hapd = eloop_ctx;
+       char buf[256];
+       int res;
+       struct sockaddr_un from;
+       socklen_t fromlen = sizeof(from);
+       char *reply;
+       const int reply_size = 4096;
+       int reply_len;
+       int level = MSG_DEBUG;
+
+       res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+                      (struct sockaddr *) &from, &fromlen);
+       if (res < 0) {
+               perror("recvfrom(ctrl_iface)");
+               return;
+       }
+       buf[res] = '\0';
+       if (os_strcmp(buf, "PING") == 0)
+               level = MSG_EXCESSIVE;
+       wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res);
+
+       reply = os_malloc(reply_size);
+       if (reply == NULL) {
+               sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+                      fromlen);
+               return;
+       }
+
+       os_memcpy(reply, "OK\n", 3);
+       reply_len = 3;
+
+       if (os_strcmp(buf, "PING") == 0) {
+               os_memcpy(reply, "PONG\n", 5);
+               reply_len = 5;
+       } else if (os_strncmp(buf, "RELOG", 5) == 0) {
+               if (wpa_debug_reopen_file() < 0)
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "MIB") == 0) {
+               reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
+               if (reply_len >= 0) {
+                       res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
+                                         reply_size - reply_len);
+                       if (res < 0)
+                               reply_len = -1;
+                       else
+                               reply_len += res;
+               }
+               if (reply_len >= 0) {
+                       res = ieee802_1x_get_mib(hapd, reply + reply_len,
+                                                reply_size - reply_len);
+                       if (res < 0)
+                               reply_len = -1;
+                       else
+                               reply_len += res;
+               }
+#ifndef CONFIG_NO_RADIUS
+               if (reply_len >= 0) {
+                       res = radius_client_get_mib(hapd->radius,
+                                                   reply + reply_len,
+                                                   reply_size - reply_len);
+                       if (res < 0)
+                               reply_len = -1;
+                       else
+                               reply_len += res;
+               }
+#endif /* CONFIG_NO_RADIUS */
+       } else if (os_strcmp(buf, "STA-FIRST") == 0) {
+               reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
+                                                        reply_size);
+       } else if (os_strncmp(buf, "STA ", 4) == 0) {
+               reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
+                                                  reply_size);
+       } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
+               reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
+                                                       reply_size);
+       } else if (os_strcmp(buf, "ATTACH") == 0) {
+               if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "DETACH") == 0) {
+               if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
+               if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
+                                                   buf + 6))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
+               if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
+               if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
+               if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
+                       reply_len = -1;
+#ifdef CONFIG_IEEE80211W
+#ifdef NEED_AP_MLME
+       } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
+               if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
+                       reply_len = -1;
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WPS
+       } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
+               if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
+               reply_len = hostapd_ctrl_iface_wps_check_pin(
+                       hapd, buf + 14, reply, reply_size);
+       } else if (os_strcmp(buf, "WPS_PBC") == 0) {
+               if (hostapd_wps_button_pushed(hapd, NULL))
+                       reply_len = -1;
+#ifdef CONFIG_WPS_OOB
+       } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
+               if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
+                       reply_len = -1;
+#endif /* CONFIG_WPS_OOB */
+       } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
+               reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
+                                                         reply, reply_size);
+       } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
+               if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
+                       reply_len = -1;
+#endif /* CONFIG_WPS */
+       } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
+               if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "GET_CONFIG") == 0) {
+               reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
+                                                         reply_size);
+       } else if (os_strncmp(buf, "SET ", 4) == 0) {
+               if (hostapd_ctrl_iface_set(hapd, buf + 4))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "GET ", 4) == 0) {
+               reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
+                                                  reply_size);
+       } else {
+               os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
+               reply_len = 16;
+       }
+
+       if (reply_len < 0) {
+               os_memcpy(reply, "FAIL\n", 5);
+               reply_len = 5;
+       }
+       sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
+       os_free(reply);
+}
+
+
+static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
+{
+       char *buf;
+       size_t len;
+
+       if (hapd->conf->ctrl_interface == NULL)
+               return NULL;
+
+       len = os_strlen(hapd->conf->ctrl_interface) +
+               os_strlen(hapd->conf->iface) + 2;
+       buf = os_malloc(len);
+       if (buf == NULL)
+               return NULL;
+
+       os_snprintf(buf, len, "%s/%s",
+                   hapd->conf->ctrl_interface, hapd->conf->iface);
+       buf[len - 1] = '\0';
+       return buf;
+}
+
+
+static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
+                                     const char *txt, size_t len)
+{
+       struct hostapd_data *hapd = ctx;
+       if (hapd == NULL)
+               return;
+       hostapd_ctrl_iface_send(hapd, level, txt, len);
+}
+
+
+int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
+{
+       struct sockaddr_un addr;
+       int s = -1;
+       char *fname = NULL;
+
+       hapd->ctrl_sock = -1;
+
+       if (hapd->conf->ctrl_interface == NULL)
+               return 0;
+
+       if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
+               if (errno == EEXIST) {
+                       wpa_printf(MSG_DEBUG, "Using existing control "
+                                  "interface directory.");
+               } else {
+                       perror("mkdir[ctrl_interface]");
+                       goto fail;
+               }
+       }
+
+       if (hapd->conf->ctrl_interface_gid_set &&
+           chown(hapd->conf->ctrl_interface, 0,
+                 hapd->conf->ctrl_interface_gid) < 0) {
+               perror("chown[ctrl_interface]");
+               return -1;
+       }
+
+       if (os_strlen(hapd->conf->ctrl_interface) + 1 +
+           os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
+               goto fail;
+
+       s = socket(PF_UNIX, SOCK_DGRAM, 0);
+       if (s < 0) {
+               perror("socket(PF_UNIX)");
+               goto fail;
+       }
+
+       os_memset(&addr, 0, sizeof(addr));
+#ifdef __FreeBSD__
+       addr.sun_len = sizeof(addr);
+#endif /* __FreeBSD__ */
+       addr.sun_family = AF_UNIX;
+       fname = hostapd_ctrl_iface_path(hapd);
+       if (fname == NULL)
+               goto fail;
+       os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
+       if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
+                          strerror(errno));
+               if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+                       wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
+                                  " allow connections - assuming it was left"
+                                  "over from forced program termination");
+                       if (unlink(fname) < 0) {
+                               perror("unlink[ctrl_iface]");
+                               wpa_printf(MSG_ERROR, "Could not unlink "
+                                          "existing ctrl_iface socket '%s'",
+                                          fname);
+                               goto fail;
+                       }
+                       if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
+                           0) {
+                               perror("bind(PF_UNIX)");
+                               goto fail;
+                       }
+                       wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
+                                  "ctrl_iface socket '%s'", fname);
+               } else {
+                       wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
+                                  "be in use - cannot override it");
+                       wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
+                                  "not used anymore", fname);
+                       os_free(fname);
+                       fname = NULL;
+                       goto fail;
+               }
+       }
+
+       if (hapd->conf->ctrl_interface_gid_set &&
+           chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
+               perror("chown[ctrl_interface/ifname]");
+               goto fail;
+       }
+
+       if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
+               perror("chmod[ctrl_interface/ifname]");
+               goto fail;
+       }
+       os_free(fname);
+
+       hapd->ctrl_sock = s;
+       eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
+                                NULL);
+       hapd->msg_ctx = hapd;
+       wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
+
+       return 0;
+
+fail:
+       if (s >= 0)
+               close(s);
+       if (fname) {
+               unlink(fname);
+               os_free(fname);
+       }
+       return -1;
+}
+
+
+void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
+{
+       struct wpa_ctrl_dst *dst, *prev;
+
+       if (hapd->ctrl_sock > -1) {
+               char *fname;
+               eloop_unregister_read_sock(hapd->ctrl_sock);
+               close(hapd->ctrl_sock);
+               hapd->ctrl_sock = -1;
+               fname = hostapd_ctrl_iface_path(hapd);
+               if (fname)
+                       unlink(fname);
+               os_free(fname);
+
+               if (hapd->conf->ctrl_interface &&
+                   rmdir(hapd->conf->ctrl_interface) < 0) {
+                       if (errno == ENOTEMPTY) {
+                               wpa_printf(MSG_DEBUG, "Control interface "
+                                          "directory not empty - leaving it "
+                                          "behind");
+                       } else {
+                               perror("rmdir[ctrl_interface]");
+                       }
+               }
+       }
+
+       dst = hapd->ctrl_dst;
+       while (dst) {
+               prev = dst;
+               dst = dst->next;
+               os_free(prev);
+       }
+}
+
+
+static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+                                   const char *buf, size_t len)
+{
+       struct wpa_ctrl_dst *dst, *next;
+       struct msghdr msg;
+       int idx;
+       struct iovec io[2];
+       char levelstr[10];
+
+       dst = hapd->ctrl_dst;
+       if (hapd->ctrl_sock < 0 || dst == NULL)
+               return;
+
+       os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+       io[0].iov_base = levelstr;
+       io[0].iov_len = os_strlen(levelstr);
+       io[1].iov_base = (char *) buf;
+       io[1].iov_len = len;
+       os_memset(&msg, 0, sizeof(msg));
+       msg.msg_iov = io;
+       msg.msg_iovlen = 2;
+
+       idx = 0;
+       while (dst) {
+               next = dst->next;
+               if (level >= dst->debug_level) {
+                       wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
+                                   (u8 *) dst->addr.sun_path, dst->addrlen -
+                                   offsetof(struct sockaddr_un, sun_path));
+                       msg.msg_name = &dst->addr;
+                       msg.msg_namelen = dst->addrlen;
+                       if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
+                               int _errno = errno;
+                               wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
+                                          "%d - %s",
+                                          idx, errno, strerror(errno));
+                               dst->errors++;
+                               if (dst->errors > 10 || _errno == ENOENT) {
+                                       hostapd_ctrl_iface_detach(
+                                               hapd, &dst->addr,
+                                               dst->addrlen);
+                               }
+                       } else
+                               dst->errors = 0;
+               }
+               idx++;
+               dst = next;
+       }
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/hostapd/ctrl_iface.h b/hostapd/ctrl_iface.h
new file mode 100644 (file)
index 0000000..c997141
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef CTRL_IFACE_H
+#define CTRL_IFACE_H
+
+#ifndef CONFIG_NO_CTRL_IFACE
+int hostapd_ctrl_iface_init(struct hostapd_data *hapd);
+void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd);
+#else /* CONFIG_NO_CTRL_IFACE */
+static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
+{
+       return 0;
+}
+
+static inline void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
+{
+}
+#endif /* CONFIG_NO_CTRL_IFACE */
+
+#endif /* CTRL_IFACE_H */
diff --git a/hostapd/defconfig b/hostapd/defconfig
new file mode 100644 (file)
index 0000000..bae5ba2
--- /dev/null
@@ -0,0 +1,247 @@
+# Example hostapd build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cass, these lines should use += in order not
+# to override previous values of the variables.
+
+# Driver interface for Host AP driver
+CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for wired authenticator
+#CONFIG_DRIVER_WIRED=y
+
+# Driver interface for madwifi driver
+#CONFIG_DRIVER_MADWIFI=y
+#CFLAGS += -I../../madwifi # change to the madwifi source directory
+
+# Driver interface for drivers using the nl80211 kernel interface
+CONFIG_DRIVER_NL80211=y
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
+
+# Driver interface for no driver (e.g., RADIUS server only)
+#CONFIG_DRIVER_NONE=y
+
+# IEEE 802.11F/IAPP
+CONFIG_IAPP=y
+
+# WPA2/IEEE 802.11i RSN pre-authentication
+CONFIG_RSN_PREAUTH=y
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection)
+# This version is an experimental implementation based on IEEE 802.11w/D1.0
+# draft and is subject to change since the standard has not yet been finalized.
+# Driver support is also needed for IEEE 802.11w.
+#CONFIG_IEEE80211W=y
+
+# Integrated EAP server
+CONFIG_EAP=y
+
+# EAP-MD5 for the integrated EAP server
+CONFIG_EAP_MD5=y
+
+# EAP-TLS for the integrated EAP server
+CONFIG_EAP_TLS=y
+
+# EAP-MSCHAPv2 for the integrated EAP server
+CONFIG_EAP_MSCHAPV2=y
+
+# EAP-PEAP for the integrated EAP server
+CONFIG_EAP_PEAP=y
+
+# EAP-GTC for the integrated EAP server
+CONFIG_EAP_GTC=y
+
+# EAP-TTLS for the integrated EAP server
+CONFIG_EAP_TTLS=y
+
+# EAP-SIM for the integrated EAP server
+#CONFIG_EAP_SIM=y
+
+# EAP-AKA for the integrated EAP server
+#CONFIG_EAP_AKA=y
+
+# EAP-AKA' for the integrated EAP server
+# This requires CONFIG_EAP_AKA to be enabled, too.
+#CONFIG_EAP_AKA_PRIME=y
+
+# EAP-PAX for the integrated EAP server
+#CONFIG_EAP_PAX=y
+
+# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-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 a file: -f /tmp/hostapd.log
+# Disabled by default.
+#CONFIG_DEBUG_FILE=y
+
+# Remove support for RADIUS accounting
+#CONFIG_NO_ACCOUNTING=y
+
+# Remove support for RADIUS
+#CONFIG_NO_RADIUS=y
+
+# Remove support for VLANs
+#CONFIG_NO_VLAN=y
+
+# Enable support for fully dynamic VLANs. This enables hostapd to
+# automatically create bridge and VLAN interfaces if necessary.
+#CONFIG_FULL_DYNAMIC_VLAN=y
+
+# Remove support for dumping state into a file on SIGUSR1 signal
+# This can be used to reduce binary size at the cost of disabling a debugging
+# option.
+#CONFIG_NO_DUMP_STATE=y
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, comment out these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, comment out these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+# hostapd depends on strong random number generation being available from the
+# operating system. os_get_random() function is used to fetch random data when
+# needed, e.g., for key generation. On Linux and BSD systems, this works by
+# reading /dev/urandom. It should be noted that the OS entropy pool needs to be
+# properly initialized before hostapd is started. This is important especially
+# on embedded devices that do not have a hardware random number generator and
+# may by default start up with minimal entropy available for random number
+# generation.
+#
+# As a safety net, hostapd is by default trying to internally collect
+# additional entropy for generating random data to mix in with the data
+# fetched from the OS. This by itself is not considered to be very strong, but
+# it may help in cases where the system pool is not initialized properly.
+# However, it is very strongly recommended that the system pool is initialized
+# with enough entropy either by using hardware assisted random number
+# generator or by storing state over device reboots.
+#
+# hostapd can be configured to maintain its own entropy store over restarts to
+# enhance random number generation. This is not perfect, but it is much more
+# secure than using the same sequence of random numbers after every reboot.
+# This can be enabled with -e<entropy file> command line option. The specified
+# file needs to be readable and writable by hostapd.
+#
+# If the os_get_random() is known to provide strong random data (e.g., on
+# Linux/BSD, the board in question is known to have reliable source of random
+# data from /dev/urandom), the internal hostapd random pool can be disabled.
+# This will save some in binary size and CPU use. However, this should only be
+# considered for builds that are known to be used on devices that meet the
+# requirements described above.
+#CONFIG_NO_RANDOM_POOL=y
+
+# Select TLS implementation
+# openssl = OpenSSL (default)
+# gnutls = GnuTLS
+# internal = Internal TLSv1 implementation (experimental)
+# none = Empty template
+#CONFIG_TLS=openssl
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1)
+# can be enabled to get a stronger construction of messages when block ciphers
+# are used.
+#CONFIG_TLSV11=y
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2)
+# can be enabled to enable use of stronger crypto algorithms.
+#CONFIG_TLSV12=y
+
+# If CONFIG_TLS=internal is used, additional library and include paths are
+# needed for LibTomMath. Alternatively, an integrated, minimal version of
+# LibTomMath can be used. See beginning of libtommath.c for details on benefits
+# and drawbacks of this option.
+#CONFIG_INTERNAL_LIBTOMMATH=y
+#ifndef CONFIG_INTERNAL_LIBTOMMATH
+#LTM_PATH=/usr/src/libtommath-0.39
+#CFLAGS += -I$(LTM_PATH)
+#LIBS += -L$(LTM_PATH)
+#LIBS_p += -L$(LTM_PATH)
+#endif
+# At the cost of about 4 kB of additional binary size, the internal LibTomMath
+# can be configured to include faster routines for exptmod, sqr, and div to
+# speed up DH and RSA calculation considerably
+#CONFIG_INTERNAL_LIBTOMMATH_FAST=y
+
+# Interworking (IEEE 802.11u)
+# This can be used to enable functionality to improve interworking with
+# external networks.
+#CONFIG_INTERWORKING=y
diff --git a/hostapd/dump_state.c b/hostapd/dump_state.c
new file mode 100644 (file)
index 0000000..110cedc
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+#include <time.h>
+
+#include "utils/common.h"
+#include "radius/radius_client.h"
+#include "radius/radius_server.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
+#include "eap_server/eap.h"
+#include "ap/hostapd.h"
+#include "ap/ap_config.h"
+#include "ap/sta_info.h"
+#include "dump_state.h"
+
+
+static void fprint_char(FILE *f, char c)
+{
+       if (c >= 32 && c < 127)
+               fprintf(f, "%c", c);
+       else
+               fprintf(f, "<%02x>", c);
+}
+
+
+static void ieee802_1x_dump_state(FILE *f, const char *prefix,
+                                 struct sta_info *sta)
+{
+       struct eapol_state_machine *sm = sta->eapol_sm;
+       if (sm == NULL)
+               return;
+
+       fprintf(f, "%sIEEE 802.1X:\n", prefix);
+
+       if (sm->identity) {
+               size_t i;
+               fprintf(f, "%sidentity=", prefix);
+               for (i = 0; i < sm->identity_len; i++)
+                       fprint_char(f, sm->identity[i]);
+               fprintf(f, "\n");
+       }
+
+       fprintf(f, "%slast EAP type: Authentication Server: %d (%s) "
+               "Supplicant: %d (%s)\n", prefix,
+               sm->eap_type_authsrv,
+               eap_server_get_name(0, sm->eap_type_authsrv),
+               sm->eap_type_supp, eap_server_get_name(0, sm->eap_type_supp));
+
+       fprintf(f, "%scached_packets=%s\n", prefix,
+               sm->last_recv_radius ? "[RX RADIUS]" : "");
+
+       eapol_auth_dump_state(f, prefix, sm);
+}
+
+
+/**
+ * hostapd_dump_state - SIGUSR1 handler to dump hostapd state to a text file
+ */
+static void hostapd_dump_state(struct hostapd_data *hapd)
+{
+       FILE *f;
+       time_t now;
+       struct sta_info *sta;
+       int i;
+#ifndef CONFIG_NO_RADIUS
+       char *buf;
+#endif /* CONFIG_NO_RADIUS */
+
+       if (!hapd->conf->dump_log_name) {
+               wpa_printf(MSG_DEBUG, "Dump file not defined - ignoring dump "
+                          "request");
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "Dumping hostapd state to '%s'",
+                  hapd->conf->dump_log_name);
+       f = fopen(hapd->conf->dump_log_name, "w");
+       if (f == NULL) {
+               wpa_printf(MSG_WARNING, "Could not open dump file '%s' for "
+                          "writing.", hapd->conf->dump_log_name);
+               return;
+       }
+
+       time(&now);
+       fprintf(f, "hostapd state dump - %s", ctime(&now));
+       fprintf(f, "num_sta=%d num_sta_non_erp=%d "
+               "num_sta_no_short_slot_time=%d\n"
+               "num_sta_no_short_preamble=%d\n",
+               hapd->num_sta, hapd->iface->num_sta_non_erp,
+               hapd->iface->num_sta_no_short_slot_time,
+               hapd->iface->num_sta_no_short_preamble);
+
+       for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
+               fprintf(f, "\nSTA=" MACSTR "\n", MAC2STR(sta->addr));
+
+               fprintf(f,
+                       "  AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
+                       "\n"
+                       "  capability=0x%x listen_interval=%d\n",
+                       sta->aid,
+                       sta->flags,
+                       (sta->flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
+                       (sta->flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
+                       (sta->flags & WLAN_STA_PS ? "[PS]" : ""),
+                       (sta->flags & WLAN_STA_TIM ? "[TIM]" : ""),
+                       (sta->flags & WLAN_STA_PERM ? "[PERM]" : ""),
+                       (ap_sta_is_authorized(sta) ? "[AUTHORIZED]" : ""),
+                       (sta->flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" :
+                        ""),
+                       (sta->flags & WLAN_STA_SHORT_PREAMBLE ?
+                        "[SHORT_PREAMBLE]" : ""),
+                       (sta->flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""),
+                       (sta->flags & WLAN_STA_WMM ? "[WMM]" : ""),
+                       (sta->flags & WLAN_STA_MFP ? "[MFP]" : ""),
+                       (sta->flags & WLAN_STA_WPS ? "[WPS]" : ""),
+                       (sta->flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
+                       (sta->flags & WLAN_STA_WDS ? "[WDS]" : ""),
+                       (sta->flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
+                       (sta->flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
+                       sta->capability,
+                       sta->listen_interval);
+
+               fprintf(f, "  supported_rates=");
+               for (i = 0; i < sta->supported_rates_len; i++)
+                       fprintf(f, "%02x ", sta->supported_rates[i]);
+               fprintf(f, "\n");
+
+               fprintf(f,
+                       "  timeout_next=%s\n",
+                       (sta->timeout_next == STA_NULLFUNC ? "NULLFUNC POLL" :
+                        (sta->timeout_next == STA_DISASSOC ? "DISASSOC" :
+                         "DEAUTH")));
+
+               ieee802_1x_dump_state(f, "  ", sta);
+       }
+
+#ifndef CONFIG_NO_RADIUS
+       buf = os_malloc(4096);
+       if (buf) {
+               int count = radius_client_get_mib(hapd->radius, buf, 4096);
+               if (count < 0)
+                       count = 0;
+               else if (count > 4095)
+                       count = 4095;
+               buf[count] = '\0';
+               fprintf(f, "%s", buf);
+
+#ifdef RADIUS_SERVER
+               count = radius_server_get_mib(hapd->radius_srv, buf, 4096);
+               if (count < 0)
+                       count = 0;
+               else if (count > 4095)
+                       count = 4095;
+               buf[count] = '\0';
+               fprintf(f, "%s", buf);
+#endif /* RADIUS_SERVER */
+
+               os_free(buf);
+       }
+#endif /* CONFIG_NO_RADIUS */
+       fclose(f);
+}
+
+
+int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx)
+{
+       size_t i;
+
+       for (i = 0; i < iface->num_bss; i++)
+               hostapd_dump_state(iface->bss[i]);
+
+       return 0;
+}
diff --git a/hostapd/dump_state.h b/hostapd/dump_state.h
new file mode 100644 (file)
index 0000000..e14f08a
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+#ifndef DUMP_STATE_H
+#define DUMP_STATE_H
+
+int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx);
+
+#endif /* DUMP_STATE_H */
diff --git a/hostapd/eap_register.c b/hostapd/eap_register.c
new file mode 100644 (file)
index 0000000..bab2871
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_server/eap_methods.h"
+#include "eap_register.h"
+
+
+/**
+ * eap_server_register_methods - Register statically linked EAP server methods
+ * Returns: 0 on success, -1 or -2 on failure
+ *
+ * This function is called at program initialization to register all EAP
+ * methods that were linked in statically.
+ */
+int eap_server_register_methods(void)
+{
+       int ret = 0;
+
+#ifdef EAP_SERVER_IDENTITY
+       if (ret == 0)
+               ret = eap_server_identity_register();
+#endif /* EAP_SERVER_IDENTITY */
+
+#ifdef EAP_SERVER_MD5
+       if (ret == 0)
+               ret = eap_server_md5_register();
+#endif /* EAP_SERVER_MD5 */
+
+#ifdef EAP_SERVER_TLS
+       if (ret == 0)
+               ret = eap_server_tls_register();
+#endif /* EAP_SERVER_TLS */
+
+#ifdef EAP_SERVER_MSCHAPV2
+       if (ret == 0)
+               ret = eap_server_mschapv2_register();
+#endif /* EAP_SERVER_MSCHAPV2 */
+
+#ifdef EAP_SERVER_PEAP
+       if (ret == 0)
+               ret = eap_server_peap_register();
+#endif /* EAP_SERVER_PEAP */
+
+#ifdef EAP_SERVER_TLV
+       if (ret == 0)
+               ret = eap_server_tlv_register();
+#endif /* EAP_SERVER_TLV */
+
+#ifdef EAP_SERVER_GTC
+       if (ret == 0)
+               ret = eap_server_gtc_register();
+#endif /* EAP_SERVER_GTC */
+
+#ifdef EAP_SERVER_TTLS
+       if (ret == 0)
+               ret = eap_server_ttls_register();
+#endif /* EAP_SERVER_TTLS */
+
+#ifdef EAP_SERVER_SIM
+       if (ret == 0)
+               ret = eap_server_sim_register();
+#endif /* EAP_SERVER_SIM */
+
+#ifdef EAP_SERVER_AKA
+       if (ret == 0)
+               ret = eap_server_aka_register();
+#endif /* EAP_SERVER_AKA */
+
+#ifdef EAP_SERVER_AKA_PRIME
+       if (ret == 0)
+               ret = eap_server_aka_prime_register();
+#endif /* EAP_SERVER_AKA_PRIME */
+
+#ifdef EAP_SERVER_PAX
+       if (ret == 0)
+               ret = eap_server_pax_register();
+#endif /* EAP_SERVER_PAX */
+
+#ifdef EAP_SERVER_PSK
+       if (ret == 0)
+               ret = eap_server_psk_register();
+#endif /* EAP_SERVER_PSK */
+
+#ifdef EAP_SERVER_SAKE
+       if (ret == 0)
+               ret = eap_server_sake_register();
+#endif /* EAP_SERVER_SAKE */
+
+#ifdef EAP_SERVER_GPSK
+       if (ret == 0)
+               ret = eap_server_gpsk_register();
+#endif /* EAP_SERVER_GPSK */
+
+#ifdef EAP_SERVER_VENDOR_TEST
+       if (ret == 0)
+               ret = eap_server_vendor_test_register();
+#endif /* EAP_SERVER_VENDOR_TEST */
+
+#ifdef EAP_SERVER_FAST
+       if (ret == 0)
+               ret = eap_server_fast_register();
+#endif /* EAP_SERVER_FAST */
+
+#ifdef EAP_SERVER_WSC
+       if (ret == 0)
+               ret = eap_server_wsc_register();
+#endif /* EAP_SERVER_WSC */
+
+#ifdef EAP_SERVER_IKEV2
+       if (ret == 0)
+               ret = eap_server_ikev2_register();
+#endif /* EAP_SERVER_IKEV2 */
+
+#ifdef EAP_SERVER_TNC
+       if (ret == 0)
+               ret = eap_server_tnc_register();
+#endif /* EAP_SERVER_TNC */
+
+#ifdef EAP_SERVER_PWD
+       if (ret == 0)
+               ret = eap_server_pwd_register();
+#endif /* EAP_SERVER_PWD */
+
+       return ret;
+}
diff --git a/hostapd/eap_register.h b/hostapd/eap_register.h
new file mode 100644 (file)
index 0000000..82e7171
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+#ifndef EAP_REGISTER_H
+#define EAP_REGISTER_H
+
+int eap_server_register_methods(void);
+
+#endif /* EAP_REGISTER_H */
diff --git a/hostapd/eap_testing.txt b/hostapd/eap_testing.txt
new file mode 100644 (file)
index 0000000..04468c3
--- /dev/null
@@ -0,0 +1,77 @@
+Interoperability testing of hostapd's IEEE 802.1X/EAPOL authentication
+
+Test matrix
+
++) tested successfully
+F) failed
+-) peer did not support
+?) not tested
+
+XSupplicant --------------------------------.
+Intel PROSet ---------------------------.   |
+Windows XP -------------------------.   |   |
+Mac OS X 10.4 ------------------.   |   |   |
+Nokia S60 ------------------.   |   |   |   |
+wpa_supplicant ---------.   |   |   |   |   |
+                       |   |   |   |   |   |
+
+EAP-MD5                        +   -   ?   ?   -
+EAP-GTC                        +   -   ?   -   -
+EAP-MSCHAPv2           +   -   ?   -   -
+EAP-TLS                        +   +   +1  +   +
+EAP-PEAPv0/MSCHAPv2    +   +   +   +   +   +
+EAP-PEAPv0/GTC         +   +   +   -   +
+EAP-PEAPv0/MD5         +   -   +   -   -
+EAP-PEAPv0/TLS         +   F   -   +   +
+EAP-PEAPv0/SIM         +   +   -   -   -
+EAP-PEAPv0/AKA         +   +   -   -   -
+EAP-PEAPv0/PSK         +   -   -   -   -
+EAP-PEAPv0/PAX         +   -   -   -   -
+EAP-PEAPv0/SAKE                +   -   -   -   -
+EAP-PEAPv0/GPSK                +   -   -   -   -
+EAP-PEAPv1/MSCHAPv2    +   +   +   -   +   +
+EAP-PEAPv1/GTC         +   +   +   -   +
+EAP-PEAPv1/MD5         +   -   +   -   -
+EAP-PEAPv1/TLS         +   F   -   -   +
+EAP-PEAPv1/SIM         +   +   -   -   -
+EAP-PEAPv1/AKA         +   +   -   -   -
+EAP-PEAPv1/PSK         +   -   -   -   -
+EAP-PEAPv1/PAX         +   -   -   -   -
+EAP-PEAPv1/SAKE                +   -   -   -   -
+EAP-PEAPv1/GPSK                +   -   -   -   -
+EAP-TTLS/CHAP          +   -   +   -   +   +
+EAP-TTLS/MSCHAP                +   -   +   -   +   +
+EAP-TTLS/MSCHAPv2      +   +   +   -   +   +
+EAP-TTLS/PAP           +   -   +   -   +   +
+EAP-TTLS/EAP-MD5       +   -   -   -   -   +
+EAP-TTLS/EAP-GTC       +   +   -   -   -
+EAP-TTLS/EAP-MSCHAPv2  +   +   -   -   -
+EAP-TTLS/EAP-TLS       +   F   -   -   -
+EAP-TTLS/EAP-SIM       +   +   -   -   -
+EAP-TTLS/EAP-AKA       +   +   -   -   -
+EAP-TTLS + TNC         +   -   -   -   -
+EAP-SIM                        +   +   -   -   +
+EAP-AKA                        +   +   -   -   -
+EAP-PAX                        +   -   -   -   -
+EAP-SAKE               +   -   -   -   -
+EAP-GPSK               +   -   -   -   -
+EAP-FAST/MSCHAPv2(prov)        +   -   F   -   F
+EAP-FAST/GTC(auth)     +   -   +   -   +
+EAP-FAST/MSCHAPv2(aprov)+   -   F   -   F
+EAP-FAST/GTC(aprov)    +   -   F   -   F
+EAP-FAST/MD5(aprov)    +   -   -   -   -
+EAP-FAST/TLS(aprov)    +   -   -   -   -
+EAP-FAST/SIM(aprov)    +   -   -   -   -
+EAP-FAST/AKA(aprov)    +   -   -   -   -
+EAP-FAST/MSCHAPv2(auth)        +   -   +   -   +
+EAP-FAST/MD5(auth)     +   -   +   -   -
+EAP-FAST/TLS(auth)     +   -   -   -   -
+EAP-FAST/SIM(auth)     +   -   -   -   -
+EAP-FAST/AKA(auth)     +   -   -   -   -
+EAP-FAST + TNC         +   -   -   -   -
+EAP-IKEv2              +   -   -   -   -
+EAP-TNC                        +   -   -   -   -
+
+1) EAP-TLS itself worked, but peer certificate validation failed at
+   least when using the internal TLS server (peer included incorrect
+   certificates in the chain?)
diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c
new file mode 100644 (file)
index 0000000..2919122
--- /dev/null
@@ -0,0 +1,715 @@
+/*
+ * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
+ * 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 is an example implementation of the EAP-SIM/AKA database/authentication
+ * gateway interface to HLR/AuC. It is expected to be replaced with an
+ * implementation of SS7 gateway to GSM/UMTS authentication center (HLR/AuC) or
+ * a local implementation of SIM triplet and AKA authentication data generator.
+ *
+ * hostapd will send SIM/AKA authentication queries over a UNIX domain socket
+ * to and external program, e.g., this hlr_auc_gw. This interface uses simple
+ * text-based format:
+ *
+ * EAP-SIM / GSM triplet query/response:
+ * SIM-REQ-AUTH <IMSI> <max_chal>
+ * SIM-RESP-AUTH <IMSI> Kc1:SRES1:RAND1 Kc2:SRES2:RAND2 [Kc3:SRES3:RAND3]
+ * SIM-RESP-AUTH <IMSI> FAILURE
+ *
+ * EAP-AKA / UMTS query/response:
+ * AKA-REQ-AUTH <IMSI>
+ * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
+ * AKA-RESP-AUTH <IMSI> FAILURE
+ *
+ * EAP-AKA / UMTS AUTS (re-synchronization):
+ * AKA-AUTS <IMSI> <AUTS> <RAND>
+ *
+ * IMSI and max_chal are sent as an ASCII string,
+ * Kc/SRES/RAND/AUTN/IK/CK/RES/AUTS as hex strings.
+ *
+ * The example implementation here reads GSM authentication triplets from a
+ * text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex
+ * strings. This is used to simulate an HLR/AuC. As such, it is not very useful
+ * for real life authentication, but it is useful both as an example
+ * implementation and for EAP-SIM testing.
+ */
+
+#include "includes.h"
+#include <sys/un.h>
+
+#include "common.h"
+#include "crypto/milenage.h"
+#include "crypto/random.h"
+
+static const char *default_socket_path = "/tmp/hlr_auc_gw.sock";
+static const char *socket_path;
+static int serv_sock = -1;
+
+/* GSM triplets */
+struct gsm_triplet {
+       struct gsm_triplet *next;
+       char imsi[20];
+       u8 kc[8];
+       u8 sres[4];
+       u8 _rand[16];
+};
+
+static struct gsm_triplet *gsm_db = NULL, *gsm_db_pos = NULL;
+
+/* OPc and AMF parameters for Milenage (Example algorithms for AKA). */
+struct milenage_parameters {
+       struct milenage_parameters *next;
+       char imsi[20];
+       u8 ki[16];
+       u8 opc[16];
+       u8 amf[2];
+       u8 sqn[6];
+};
+
+static struct milenage_parameters *milenage_db = NULL;
+
+#define EAP_SIM_MAX_CHAL 3
+
+#define EAP_AKA_RAND_LEN 16
+#define EAP_AKA_AUTN_LEN 16
+#define EAP_AKA_AUTS_LEN 14
+#define EAP_AKA_RES_MAX_LEN 16
+#define EAP_AKA_IK_LEN 16
+#define EAP_AKA_CK_LEN 16
+
+
+static int open_socket(const char *path)
+{
+       struct sockaddr_un addr;
+       int s;
+
+       s = socket(PF_UNIX, SOCK_DGRAM, 0);
+       if (s < 0) {
+               perror("socket(PF_UNIX)");
+               return -1;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       os_strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
+       if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               perror("bind(PF_UNIX)");
+               close(s);
+               return -1;
+       }
+
+       return s;
+}
+
+
+static int read_gsm_triplets(const char *fname)
+{
+       FILE *f;
+       char buf[200], *pos, *pos2;
+       struct gsm_triplet *g = NULL;
+       int line, ret = 0;
+
+       if (fname == NULL)
+               return -1;
+
+       f = fopen(fname, "r");
+       if (f == NULL) {
+               printf("Could not open GSM tripler data file '%s'\n", fname);
+               return -1;
+       }
+
+       line = 0;
+       while (fgets(buf, sizeof(buf), f)) {
+               line++;
+
+               /* Parse IMSI:Kc:SRES:RAND */
+               buf[sizeof(buf) - 1] = '\0';
+               if (buf[0] == '#')
+                       continue;
+               pos = buf;
+               while (*pos != '\0' && *pos != '\n')
+                       pos++;
+               if (*pos == '\n')
+                       *pos = '\0';
+               pos = buf;
+               if (*pos == '\0')
+                       continue;
+
+               g = os_zalloc(sizeof(*g));
+               if (g == NULL) {
+                       ret = -1;
+                       break;
+               }
+
+               /* IMSI */
+               pos2 = strchr(pos, ':');
+               if (pos2 == NULL) {
+                       printf("%s:%d - Invalid IMSI (%s)\n",
+                              fname, line, pos);
+                       ret = -1;
+                       break;
+               }
+               *pos2 = '\0';
+               if (strlen(pos) >= sizeof(g->imsi)) {
+                       printf("%s:%d - Too long IMSI (%s)\n",
+                              fname, line, pos);
+                       ret = -1;
+                       break;
+               }
+               os_strlcpy(g->imsi, pos, sizeof(g->imsi));
+               pos = pos2 + 1;
+
+               /* Kc */
+               pos2 = strchr(pos, ':');
+               if (pos2 == NULL) {
+                       printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos);
+                       ret = -1;
+                       break;
+               }
+               *pos2 = '\0';
+               if (strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) {
+                       printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos);
+                       ret = -1;
+                       break;
+               }
+               pos = pos2 + 1;
+
+               /* SRES */
+               pos2 = strchr(pos, ':');
+               if (pos2 == NULL) {
+                       printf("%s:%d - Invalid SRES (%s)\n", fname, line,
+                              pos);
+                       ret = -1;
+                       break;
+               }
+               *pos2 = '\0';
+               if (strlen(pos) != 8 || hexstr2bin(pos, g->sres, 4)) {
+                       printf("%s:%d - Invalid SRES (%s)\n", fname, line,
+                              pos);
+                       ret = -1;
+                       break;
+               }
+               pos = pos2 + 1;
+
+               /* RAND */
+               pos2 = strchr(pos, ':');
+               if (pos2)
+                       *pos2 = '\0';
+               if (strlen(pos) != 32 || hexstr2bin(pos, g->_rand, 16)) {
+                       printf("%s:%d - Invalid RAND (%s)\n", fname, line,
+                              pos);
+                       ret = -1;
+                       break;
+               }
+               pos = pos2 + 1;
+
+               g->next = gsm_db;
+               gsm_db = g;
+               g = NULL;
+       }
+       free(g);
+
+       fclose(f);
+
+       return ret;
+}
+
+
+static struct gsm_triplet * get_gsm_triplet(const char *imsi)
+{
+       struct gsm_triplet *g = gsm_db_pos;
+
+       while (g) {
+               if (strcmp(g->imsi, imsi) == 0) {
+                       gsm_db_pos = g->next;
+                       return g;
+               }
+               g = g->next;
+       }
+
+       g = gsm_db;
+       while (g && g != gsm_db_pos) {
+               if (strcmp(g->imsi, imsi) == 0) {
+                       gsm_db_pos = g->next;
+                       return g;
+               }
+               g = g->next;
+       }
+
+       return NULL;
+}
+
+
+static int read_milenage(const char *fname)
+{
+       FILE *f;
+       char buf[200], *pos, *pos2;
+       struct milenage_parameters *m = NULL;
+       int line, ret = 0;
+
+       if (fname == NULL)
+               return -1;
+
+       f = fopen(fname, "r");
+       if (f == NULL) {
+               printf("Could not open Milenage data file '%s'\n", fname);
+               return -1;
+       }
+
+       line = 0;
+       while (fgets(buf, sizeof(buf), f)) {
+               line++;
+
+               /* Parse IMSI Ki OPc AMF SQN */
+               buf[sizeof(buf) - 1] = '\0';
+               if (buf[0] == '#')
+                       continue;
+               pos = buf;
+               while (*pos != '\0' && *pos != '\n')
+                       pos++;
+               if (*pos == '\n')
+                       *pos = '\0';
+               pos = buf;
+               if (*pos == '\0')
+                       continue;
+
+               m = os_zalloc(sizeof(*m));
+               if (m == NULL) {
+                       ret = -1;
+                       break;
+               }
+
+               /* IMSI */
+               pos2 = strchr(pos, ' ');
+               if (pos2 == NULL) {
+                       printf("%s:%d - Invalid IMSI (%s)\n",
+                              fname, line, pos);
+                       ret = -1;
+                       break;
+               }
+               *pos2 = '\0';
+               if (strlen(pos) >= sizeof(m->imsi)) {
+                       printf("%s:%d - Too long IMSI (%s)\n",
+                              fname, line, pos);
+                       ret = -1;
+                       break;
+               }
+               os_strlcpy(m->imsi, pos, sizeof(m->imsi));
+               pos = pos2 + 1;
+
+               /* Ki */
+               pos2 = strchr(pos, ' ');
+               if (pos2 == NULL) {
+                       printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
+                       ret = -1;
+                       break;
+               }
+               *pos2 = '\0';
+               if (strlen(pos) != 32 || hexstr2bin(pos, m->ki, 16)) {
+                       printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
+                       ret = -1;
+                       break;
+               }
+               pos = pos2 + 1;
+
+               /* OPc */
+               pos2 = strchr(pos, ' ');
+               if (pos2 == NULL) {
+                       printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
+                       ret = -1;
+                       break;
+               }
+               *pos2 = '\0';
+               if (strlen(pos) != 32 || hexstr2bin(pos, m->opc, 16)) {
+                       printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
+                       ret = -1;
+                       break;
+               }
+               pos = pos2 + 1;
+
+               /* AMF */
+               pos2 = strchr(pos, ' ');
+               if (pos2 == NULL) {
+                       printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
+                       ret = -1;
+                       break;
+               }
+               *pos2 = '\0';
+               if (strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) {
+                       printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
+                       ret = -1;
+                       break;
+               }
+               pos = pos2 + 1;
+
+               /* SQN */
+               pos2 = strchr(pos, ' ');
+               if (pos2)
+                       *pos2 = '\0';
+               if (strlen(pos) != 12 || hexstr2bin(pos, m->sqn, 6)) {
+                       printf("%s:%d - Invalid SEQ (%s)\n", fname, line, pos);
+                       ret = -1;
+                       break;
+               }
+               pos = pos2 + 1;
+
+               m->next = milenage_db;
+               milenage_db = m;
+               m = NULL;
+       }
+       free(m);
+
+       fclose(f);
+
+       return ret;
+}
+
+
+static struct milenage_parameters * get_milenage(const char *imsi)
+{
+       struct milenage_parameters *m = milenage_db;
+
+       while (m) {
+               if (strcmp(m->imsi, imsi) == 0)
+                       break;
+               m = m->next;
+       }
+
+       return m;
+}
+
+
+static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
+                        char *imsi)
+{
+       int count, max_chal, ret;
+       char *pos;
+       char reply[1000], *rpos, *rend;
+       struct milenage_parameters *m;
+       struct gsm_triplet *g;
+
+       reply[0] = '\0';
+
+       pos = strchr(imsi, ' ');
+       if (pos) {
+               *pos++ = '\0';
+               max_chal = atoi(pos);
+               if (max_chal < 1 || max_chal < EAP_SIM_MAX_CHAL)
+                       max_chal = EAP_SIM_MAX_CHAL;
+       } else
+               max_chal = EAP_SIM_MAX_CHAL;
+
+       rend = &reply[sizeof(reply)];
+       rpos = reply;
+       ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi);
+       if (ret < 0 || ret >= rend - rpos)
+               return;
+       rpos += ret;
+
+       m = get_milenage(imsi);
+       if (m) {
+               u8 _rand[16], sres[4], kc[8];
+               for (count = 0; count < max_chal; count++) {
+                       if (random_get_bytes(_rand, 16) < 0)
+                               return;
+                       gsm_milenage(m->opc, m->ki, _rand, sres, kc);
+                       *rpos++ = ' ';
+                       rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
+                       *rpos++ = ':';
+                       rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4);
+                       *rpos++ = ':';
+                       rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16);
+               }
+               *rpos = '\0';
+               goto send;
+       }
+
+       count = 0;
+       while (count < max_chal && (g = get_gsm_triplet(imsi))) {
+               if (strcmp(g->imsi, imsi) != 0)
+                       continue;
+
+               if (rpos < rend)
+                       *rpos++ = ' ';
+               rpos += wpa_snprintf_hex(rpos, rend - rpos, g->kc, 8);
+               if (rpos < rend)
+                       *rpos++ = ':';
+               rpos += wpa_snprintf_hex(rpos, rend - rpos, g->sres, 4);
+               if (rpos < rend)
+                       *rpos++ = ':';
+               rpos += wpa_snprintf_hex(rpos, rend - rpos, g->_rand, 16);
+               count++;
+       }
+
+       if (count == 0) {
+               printf("No GSM triplets found for %s\n", imsi);
+               ret = snprintf(rpos, rend - rpos, " FAILURE");
+               if (ret < 0 || ret >= rend - rpos)
+                       return;
+               rpos += ret;
+       }
+
+send:
+       printf("Send: %s\n", reply);
+       if (sendto(s, reply, rpos - reply, 0,
+                  (struct sockaddr *) from, fromlen) < 0)
+               perror("send");
+}
+
+
+static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
+                        char *imsi)
+{
+       /* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> */
+       char reply[1000], *pos, *end;
+       u8 _rand[EAP_AKA_RAND_LEN];
+       u8 autn[EAP_AKA_AUTN_LEN];
+       u8 ik[EAP_AKA_IK_LEN];
+       u8 ck[EAP_AKA_CK_LEN];
+       u8 res[EAP_AKA_RES_MAX_LEN];
+       size_t res_len;
+       int ret;
+       struct milenage_parameters *m;
+
+       m = get_milenage(imsi);
+       if (m) {
+               if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0)
+                       return;
+               res_len = EAP_AKA_RES_MAX_LEN;
+               inc_byte_array(m->sqn, 6);
+               printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
+                      m->sqn[0], m->sqn[1], m->sqn[2],
+                      m->sqn[3], m->sqn[4], m->sqn[5]);
+               milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
+                                 autn, ik, ck, res, &res_len);
+       } else {
+               printf("Unknown IMSI: %s\n", imsi);
+#ifdef AKA_USE_FIXED_TEST_VALUES
+               printf("Using fixed test values for AKA\n");
+               memset(_rand, '0', EAP_AKA_RAND_LEN);
+               memset(autn, '1', EAP_AKA_AUTN_LEN);
+               memset(ik, '3', EAP_AKA_IK_LEN);
+               memset(ck, '4', EAP_AKA_CK_LEN);
+               memset(res, '2', EAP_AKA_RES_MAX_LEN);
+               res_len = EAP_AKA_RES_MAX_LEN;
+#else /* AKA_USE_FIXED_TEST_VALUES */
+               return;
+#endif /* AKA_USE_FIXED_TEST_VALUES */
+       }
+
+       pos = reply;
+       end = &reply[sizeof(reply)];
+       ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi);
+       if (ret < 0 || ret >= end - pos)
+               return;
+       pos += ret;
+       pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN);
+       *pos++ = ' ';
+       pos += wpa_snprintf_hex(pos, end - pos, autn, EAP_AKA_AUTN_LEN);
+       *pos++ = ' ';
+       pos += wpa_snprintf_hex(pos, end - pos, ik, EAP_AKA_IK_LEN);
+       *pos++ = ' ';
+       pos += wpa_snprintf_hex(pos, end - pos, ck, EAP_AKA_CK_LEN);
+       *pos++ = ' ';
+       pos += wpa_snprintf_hex(pos, end - pos, res, res_len);
+
+       printf("Send: %s\n", reply);
+
+       if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from,
+                  fromlen) < 0)
+               perror("send");
+}
+
+
+static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
+                    char *imsi)
+{
+       char *auts, *__rand;
+       u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6];
+       struct milenage_parameters *m;
+
+       /* AKA-AUTS <IMSI> <AUTS> <RAND> */
+
+       auts = strchr(imsi, ' ');
+       if (auts == NULL)
+               return;
+       *auts++ = '\0';
+
+       __rand = strchr(auts, ' ');
+       if (__rand == NULL)
+               return;
+       *__rand++ = '\0';
+
+       printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", imsi, auts, __rand);
+       if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) ||
+           hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) {
+               printf("Could not parse AUTS/RAND\n");
+               return;
+       }
+
+       m = get_milenage(imsi);
+       if (m == NULL) {
+               printf("Unknown IMSI: %s\n", imsi);
+               return;
+       }
+
+       if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) {
+               printf("AKA-AUTS: Incorrect MAC-S\n");
+       } else {
+               memcpy(m->sqn, sqn, 6);
+               printf("AKA-AUTS: Re-synchronized: "
+                      "SQN=%02x%02x%02x%02x%02x%02x\n",
+                      sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
+       }
+}
+
+
+static int process(int s)
+{
+       char buf[1000];
+       struct sockaddr_un from;
+       socklen_t fromlen;
+       ssize_t res;
+
+       fromlen = sizeof(from);
+       res = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *) &from,
+                      &fromlen);
+       if (res < 0) {
+               perror("recvfrom");
+               return -1;
+       }
+
+       if (res == 0)
+               return 0;
+
+       if ((size_t) res >= sizeof(buf))
+               res = sizeof(buf) - 1;
+       buf[res] = '\0';
+
+       printf("Received: %s\n", buf);
+
+       if (strncmp(buf, "SIM-REQ-AUTH ", 13) == 0)
+               sim_req_auth(s, &from, fromlen, buf + 13);
+       else if (strncmp(buf, "AKA-REQ-AUTH ", 13) == 0)
+               aka_req_auth(s, &from, fromlen, buf + 13);
+       else if (strncmp(buf, "AKA-AUTS ", 9) == 0)
+               aka_auts(s, &from, fromlen, buf + 9);
+       else
+               printf("Unknown request: %s\n", buf);
+
+       return 0;
+}
+
+
+static void cleanup(void)
+{
+       struct gsm_triplet *g, *gprev;
+       struct milenage_parameters *m, *prev;
+
+       g = gsm_db;
+       while (g) {
+               gprev = g;
+               g = g->next;
+               free(gprev);
+       }
+
+       m = milenage_db;
+       while (m) {
+               prev = m;
+               m = m->next;
+               free(prev);
+       }
+
+       close(serv_sock);
+       unlink(socket_path);
+}
+
+
+static void handle_term(int sig)
+{
+       printf("Signal %d - terminate\n", sig);
+       exit(0);
+}
+
+
+static void usage(void)
+{
+       printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
+              "database/authenticator\n"
+              "Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>\n"
+              "\n"
+              "usage:\n"
+              "hlr_auc_gw [-h] [-s<socket path>] [-g<triplet file>] "
+              "[-m<milenage file>]\n"
+              "\n"
+              "options:\n"
+              "  -h = show this usage help\n"
+              "  -s<socket path> = path for UNIX domain socket\n"
+              "                    (default: %s)\n"
+              "  -g<triplet file> = path for GSM authentication triplets\n"
+              "  -m<milenage file> = path for Milenage keys\n",
+              default_socket_path);
+}
+
+
+int main(int argc, char *argv[])
+{
+       int c;
+       char *milenage_file = NULL;
+       char *gsm_triplet_file = NULL;
+
+       socket_path = default_socket_path;
+
+       for (;;) {
+               c = getopt(argc, argv, "g:hm:s:");
+               if (c < 0)
+                       break;
+               switch (c) {
+               case 'g':
+                       gsm_triplet_file = optarg;
+                       break;
+               case 'h':
+                       usage();
+                       return 0;
+               case 'm':
+                       milenage_file = optarg;
+                       break;
+               case 's':
+                       socket_path = optarg;
+                       break;
+               default:
+                       usage();
+                       return -1;
+               }
+       }
+
+       if (gsm_triplet_file && read_gsm_triplets(gsm_triplet_file) < 0)
+               return -1;
+
+       if (milenage_file && read_milenage(milenage_file) < 0)
+               return -1;
+
+       serv_sock = open_socket(socket_path);
+       if (serv_sock < 0)
+               return -1;
+
+       printf("Listening for requests on %s\n", socket_path);
+
+       atexit(cleanup);
+       signal(SIGTERM, handle_term);
+       signal(SIGINT, handle_term);
+
+       for (;;)
+               process(serv_sock);
+
+       return 0;
+}
diff --git a/hostapd/hlr_auc_gw.milenage_db b/hostapd/hlr_auc_gw.milenage_db
new file mode 100644 (file)
index 0000000..ecd06d7
--- /dev/null
@@ -0,0 +1,13 @@
+# Parameters for Milenage (Example algorithms for AKA).
+# The example Ki, OPc, and AMF values here are from 3GPP TS 35.208 v6.0.0
+# 4.3.20 Test Set 20. SQN is the last used SQN value.
+# These values can be used for both UMTS (EAP-AKA) and GSM (EAP-SIM)
+# authentication. In case of GSM/EAP-SIM, AMF and SQN values are not used, but
+# dummy values will need to be included in this file.
+
+# IMSI Ki OPc AMF SQN
+232010000000000 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000
+
+# These values are from Test Set 19 which has the AMF separation bit set to 1
+# and as such, is suitable for EAP-AKA' test.
+555444333222111 5122250214c33e723a5dd523fc145fc0 981d464c7c52eb6e5036234984ad0bcf c3ab 16f3b3f70fc1
diff --git a/hostapd/hostapd.8 b/hostapd/hostapd.8
new file mode 100644 (file)
index 0000000..b4456bb
--- /dev/null
@@ -0,0 +1,59 @@
+.TH HOSTAPD 8 "April  7, 2005" hostapd hostapd
+.SH NAME
+hostapd \- IEEE 802.11 AP, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator
+.SH SYNOPSIS
+.B hostapd
+[\-hdBKtv] [\-P <PID file>] <configuration file(s)>
+.SH DESCRIPTION
+This manual page documents briefly the
+.B hostapd
+daemon.
+.PP
+.B hostapd
+is a user space daemon for access point and authentication servers.
+It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server.
+The current version supports Linux (Host AP, madwifi, mac80211-based drivers) and FreeBSD (net80211).
+
+.B hostapd
+is designed to be a "daemon" program that runs in the background and acts as the backend component controlling authentication.
+.B hostapd
+supports separate frontend programs and an example text-based frontend,
+.BR hostapd_cli ,
+is included with
+.BR hostapd .
+.SH OPTIONS
+A summary of options is included below.
+For a complete description, run
+.BR hostapd
+from the command line.
+.TP
+.B \-h
+Show usage.
+.TP
+.B \-d
+Show more debug messages.
+.TP
+.B \-dd
+Show even more debug messages.
+.TP
+.B \-B
+Run daemon in the background.
+.TP
+.B \-P <PID file>
+Path to PID file.
+.TP
+.B \-K
+Include key data in debug messages.
+.TP
+.B \-t
+Include timestamps in some debug messages.
+.TP
+.B \-v
+Show hostapd version.
+.SH SEE ALSO
+.BR hostapd_cli (1).
+.SH AUTHOR
+hostapd was written by Jouni Malinen <j@w1.fi>. 
+.PP
+This manual page was written by Faidon Liambotis <faidon@cube.gr>,
+for the Debian project (but may be used by others).
diff --git a/hostapd/hostapd.accept b/hostapd/hostapd.accept
new file mode 100644 (file)
index 0000000..2d2a0a2
--- /dev/null
@@ -0,0 +1,6 @@
+# List of MAC addresses that are allowed to authenticate (IEEE 802.11)
+# with the AP. Optional VLAN ID can be assigned for clients based on the
+# MAC address if dynamic VLANs (hostapd.conf dynamic_vlan option) are used.
+00:11:22:33:44:55
+00:66:77:88:99:aa
+00:00:22:33:44:55      1
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
new file mode 100644 (file)
index 0000000..5272d58
--- /dev/null
@@ -0,0 +1,1147 @@
+##### hostapd configuration file ##############################################
+# Empty lines and lines starting with # are ignored
+
+# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
+# management frames); ath0 for madwifi
+interface=wlan0
+
+# In case of madwifi, atheros, and nl80211 driver interfaces, an additional
+# configuration parameter, bridge, may be used to notify hostapd if the
+# interface is included in a bridge. This parameter is not used with Host AP
+# driver. If the bridge parameter is not set, the drivers will automatically
+# figure out the bridge interface (assuming sysfs is enabled and mounted to
+# /sys) and this parameter may not be needed.
+#
+# For nl80211, this parameter can be used to request the AP interface to be
+# added to the bridge automatically (brctl may refuse to do this before hostapd
+# has been started to change the interface mode). If needed, the bridge
+# interface is also created.
+#bridge=br0
+
+# Driver interface type (hostap/wired/madwifi/test/none/nl80211/bsd);
+# default: hostap). nl80211 is used with all Linux mac80211 drivers.
+# Use driver=none if building hostapd as a standalone RADIUS server that does
+# not control any wireless/wired driver.
+# driver=hostap
+
+# hostapd event logger configuration
+#
+# Two output method: syslog and stdout (only usable if not forking to
+# background).
+#
+# Module bitfield (ORed bitfield of modules that will be logged; -1 = all
+# modules):
+# bit 0 (1) = IEEE 802.11
+# bit 1 (2) = IEEE 802.1X
+# bit 2 (4) = RADIUS
+# bit 3 (8) = WPA
+# bit 4 (16) = driver interface
+# bit 5 (32) = IAPP
+# bit 6 (64) = MLME
+#
+# Levels (minimum value for logged events):
+#  0 = verbose debugging
+#  1 = debugging
+#  2 = informational messages
+#  3 = notification
+#  4 = warning
+#
+logger_syslog=-1
+logger_syslog_level=2
+logger_stdout=-1
+logger_stdout_level=2
+
+# Dump file for state information (on SIGUSR1)
+dump_file=/tmp/hostapd.dump
+
+# Interface for separate control program. If this is specified, hostapd
+# will create this directory and a UNIX domain socket for listening to requests
+# from external programs (CLI/GUI, etc.) for status information and
+# configuration. The socket file will be named based on the interface name, so
+# multiple hostapd processes/interfaces can be run at the same time if more
+# than one interface is used.
+# /var/run/hostapd is the recommended directory for sockets and by default,
+# hostapd_cli will use it when trying to connect with hostapd.
+ctrl_interface=/var/run/hostapd
+
+# Access control for the control interface can be configured by setting the
+# directory to allow only members of a group to use sockets. This way, it is
+# possible to run hostapd as root (since it needs to change network
+# configuration and open raw sockets) and still allow GUI/CLI components to be
+# run as non-root users. However, since the control interface can be used to
+# change the network configuration, this access needs to be protected in many
+# cases. By default, hostapd is configured to use gid 0 (root). If you
+# want to allow non-root users to use the contron interface, add a new group
+# and change this value to match with that group. Add users that should have
+# control interface access to this group.
+#
+# This variable can be a group name or gid.
+#ctrl_interface_group=wheel
+ctrl_interface_group=0
+
+
+##### IEEE 802.11 related configuration #######################################
+
+# SSID to be used in IEEE 802.11 management frames
+ssid=test
+
+# Country code (ISO/IEC 3166-1). Used to set regulatory domain.
+# Set as needed to indicate country in which device is operating.
+# This can limit available channels and transmit power.
+#country_code=US
+
+# Enable IEEE 802.11d. This advertises the country_code and the set of allowed
+# channels and transmit power levels based on the regulatory limits. The
+# country_code setting must be configured with the correct country for
+# IEEE 802.11d functions.
+# (default: 0 = disabled)
+#ieee80211d=1
+
+# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
+# Default: IEEE 802.11b
+hw_mode=g
+
+# Channel number (IEEE 802.11)
+# (default: 0, i.e., not set)
+# Please note that some drivers do not use this value from hostapd and the
+# channel will need to be configured separately with iwconfig.
+channel=1
+
+# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
+beacon_int=100
+
+# DTIM (delivery traffic information message) period (range 1..255):
+# number of beacons between DTIMs (1 = every beacon includes DTIM element)
+# (default: 2)
+dtim_period=2
+
+# Maximum number of stations allowed in station table. New stations will be
+# rejected after the station table is full. IEEE 802.11 has a limit of 2007
+# different association IDs, so this number should not be larger than that.
+# (default: 2007)
+max_num_sta=255
+
+# RTS/CTS threshold; 2347 = disabled (default); range 0..2347
+# If this field is not included in hostapd.conf, hostapd will not control
+# RTS threshold and 'iwconfig wlan# rts <val>' can be used to set it.
+rts_threshold=2347
+
+# Fragmentation threshold; 2346 = disabled (default); range 256..2346
+# If this field is not included in hostapd.conf, hostapd will not control
+# fragmentation threshold and 'iwconfig wlan# frag <val>' can be used to set
+# it.
+fragm_threshold=2346
+
+# Rate configuration
+# Default is to enable all rates supported by the hardware. This configuration
+# item allows this list be filtered so that only the listed rates will be left
+# in the list. If the list is empty, all rates are used. This list can have
+# entries that are not in the list of rates the hardware supports (such entries
+# are ignored). The entries in this list are in 100 kbps, i.e., 11 Mbps = 110.
+# If this item is present, at least one rate have to be matching with the rates
+# hardware supports.
+# default: use the most common supported rate setting for the selected
+# hw_mode (i.e., this line can be removed from configuration file in most
+# cases)
+#supported_rates=10 20 55 110 60 90 120 180 240 360 480 540
+
+# Basic rate set configuration
+# List of rates (in 100 kbps) that are included in the basic rate set.
+# If this item is not included, usually reasonable default set is used.
+#basic_rates=10 20
+#basic_rates=10 20 55 110
+#basic_rates=60 120 240
+
+# Short Preamble
+# This parameter can be used to enable optional use of short preamble for
+# frames sent at 2 Mbps, 5.5 Mbps, and 11 Mbps to improve network performance.
+# This applies only to IEEE 802.11b-compatible networks and this should only be
+# enabled if the local hardware supports use of short preamble. If any of the
+# associated STAs do not support short preamble, use of short preamble will be
+# disabled (and enabled when such STAs disassociate) dynamically.
+# 0 = do not allow use of short preamble (default)
+# 1 = allow use of short preamble
+#preamble=1
+
+# Station MAC address -based authentication
+# Please note that this kind of access control requires a driver that uses
+# hostapd to take care of management frame processing and as such, this can be
+# used with driver=hostap or driver=nl80211, but not with driver=madwifi.
+# 0 = accept unless in deny list
+# 1 = deny unless in accept list
+# 2 = use external RADIUS server (accept/deny lists are searched first)
+macaddr_acl=0
+
+# Accept/deny lists are read from separate files (containing list of
+# MAC addresses, one per line). Use absolute path name to make sure that the
+# files can be read on SIGHUP configuration reloads.
+#accept_mac_file=/etc/hostapd.accept
+#deny_mac_file=/etc/hostapd.deny
+
+# IEEE 802.11 specifies two authentication algorithms. hostapd can be
+# configured to allow both of these or only one. Open system authentication
+# should be used with IEEE 802.1X.
+# Bit fields of allowed authentication algorithms:
+# bit 0 = Open System Authentication
+# bit 1 = Shared Key Authentication (requires WEP)
+auth_algs=3
+
+# Send empty SSID in beacons and ignore probe request frames that do not
+# specify full SSID, i.e., require stations to know SSID.
+# default: disabled (0)
+# 1 = send empty (length=0) SSID in beacon and ignore probe request for
+#     broadcast SSID
+# 2 = clear SSID (ASCII 0), but keep the original length (this may be required
+#     with some clients that do not support empty SSID) and ignore probe
+#     requests for broadcast SSID
+ignore_broadcast_ssid=0
+
+# TX queue parameters (EDCF / bursting)
+# tx_queue_<queue name>_<param>
+# queues: data0, data1, data2, data3, after_beacon, beacon
+#              (data0 is the highest priority queue)
+# parameters:
+#   aifs: AIFS (default 2)
+#   cwmin: cwMin (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023)
+#   cwmax: cwMax (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023); cwMax >= cwMin
+#   burst: maximum length (in milliseconds with precision of up to 0.1 ms) for
+#          bursting
+#
+# Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e):
+# These parameters are used by the access point when transmitting frames
+# to the clients.
+#
+# Low priority / AC_BK = background
+#tx_queue_data3_aifs=7
+#tx_queue_data3_cwmin=15
+#tx_queue_data3_cwmax=1023
+#tx_queue_data3_burst=0
+# Note: for IEEE 802.11b mode: cWmin=31 cWmax=1023 burst=0
+#
+# Normal priority / AC_BE = best effort
+#tx_queue_data2_aifs=3
+#tx_queue_data2_cwmin=15
+#tx_queue_data2_cwmax=63
+#tx_queue_data2_burst=0
+# Note: for IEEE 802.11b mode: cWmin=31 cWmax=127 burst=0
+#
+# High priority / AC_VI = video
+#tx_queue_data1_aifs=1
+#tx_queue_data1_cwmin=7
+#tx_queue_data1_cwmax=15
+#tx_queue_data1_burst=3.0
+# Note: for IEEE 802.11b mode: cWmin=15 cWmax=31 burst=6.0
+#
+# Highest priority / AC_VO = voice
+#tx_queue_data0_aifs=1
+#tx_queue_data0_cwmin=3
+#tx_queue_data0_cwmax=7
+#tx_queue_data0_burst=1.5
+# Note: for IEEE 802.11b mode: cWmin=7 cWmax=15 burst=3.3
+
+# 802.1D Tag (= UP) to AC mappings
+# WMM specifies following mapping of data frames to different ACs. This mapping
+# can be configured using Linux QoS/tc and sch_pktpri.o module.
+# 802.1D Tag   802.1D Designation      Access Category WMM Designation
+# 1            BK                      AC_BK           Background
+# 2            -                       AC_BK           Background
+# 0            BE                      AC_BE           Best Effort
+# 3            EE                      AC_BE           Best Effort
+# 4            CL                      AC_VI           Video
+# 5            VI                      AC_VI           Video
+# 6            VO                      AC_VO           Voice
+# 7            NC                      AC_VO           Voice
+# Data frames with no priority information: AC_BE
+# Management frames: AC_VO
+# PS-Poll frames: AC_BE
+
+# Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e):
+# for 802.11a or 802.11g networks
+# These parameters are sent to WMM clients when they associate.
+# The parameters will be used by WMM clients for frames transmitted to the
+# access point.
+#
+# note - txop_limit is in units of 32microseconds
+# note - acm is admission control mandatory flag. 0 = admission control not
+# required, 1 = mandatory
+# note - here cwMin and cmMax are in exponent form. the actual cw value used
+# will be (2^n)-1 where n is the value given here
+#
+wmm_enabled=1
+#
+# WMM-PS Unscheduled Automatic Power Save Delivery [U-APSD]
+# Enable this flag if U-APSD supported outside hostapd (eg., Firmware/driver)
+#uapsd_advertisement_enabled=1
+#
+# Low priority / AC_BK = background
+wmm_ac_bk_cwmin=4
+wmm_ac_bk_cwmax=10
+wmm_ac_bk_aifs=7
+wmm_ac_bk_txop_limit=0
+wmm_ac_bk_acm=0
+# Note: for IEEE 802.11b mode: cWmin=5 cWmax=10
+#
+# Normal priority / AC_BE = best effort
+wmm_ac_be_aifs=3
+wmm_ac_be_cwmin=4
+wmm_ac_be_cwmax=10
+wmm_ac_be_txop_limit=0
+wmm_ac_be_acm=0
+# Note: for IEEE 802.11b mode: cWmin=5 cWmax=7
+#
+# High priority / AC_VI = video
+wmm_ac_vi_aifs=2
+wmm_ac_vi_cwmin=3
+wmm_ac_vi_cwmax=4
+wmm_ac_vi_txop_limit=94
+wmm_ac_vi_acm=0
+# Note: for IEEE 802.11b mode: cWmin=4 cWmax=5 txop_limit=188
+#
+# Highest priority / AC_VO = voice
+wmm_ac_vo_aifs=2
+wmm_ac_vo_cwmin=2
+wmm_ac_vo_cwmax=3
+wmm_ac_vo_txop_limit=47
+wmm_ac_vo_acm=0
+# Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102
+
+# Static WEP key configuration
+#
+# The key number to use when transmitting.
+# It must be between 0 and 3, and the corresponding key must be set.
+# default: not set
+#wep_default_key=0
+# The WEP keys to use.
+# A key may be a quoted string or unquoted hexadecimal digits.
+# The key length should be 5, 13, or 16 characters, or 10, 26, or 32
+# digits, depending on whether 40-bit (64-bit), 104-bit (128-bit), or
+# 128-bit (152-bit) WEP is used.
+# Only the default key must be supplied; the others are optional.
+# default: not set
+#wep_key0=123456789a
+#wep_key1="vwxyz"
+#wep_key2=0102030405060708090a0b0c0d
+#wep_key3=".2.4.6.8.0.23"
+
+# Station inactivity limit
+#
+# If a station does not send anything in ap_max_inactivity seconds, an
+# empty data frame is sent to it in order to verify whether it is
+# still in range. If this frame is not ACKed, the station will be
+# disassociated and then deauthenticated. This feature is used to
+# clear station table of old entries when the STAs move out of the
+# range.
+#
+# The station can associate again with the AP if it is still in range;
+# this inactivity poll is just used as a nicer way of verifying
+# inactivity; i.e., client will not report broken connection because
+# disassociation frame is not sent immediately without first polling
+# the STA with a data frame.
+# default: 300 (i.e., 5 minutes)
+#ap_max_inactivity=300
+
+# Disassociate stations based on excessive transmission failures or other
+# indications of connection loss. This depends on the driver capabilities and
+# may not be available with all drivers.
+#disassoc_low_ack=1
+
+# Maximum allowed Listen Interval (how many Beacon periods STAs are allowed to
+# remain asleep). Default: 65535 (no limit apart from field size)
+#max_listen_interval=100
+
+# WDS (4-address frame) mode with per-station virtual interfaces
+# (only supported with driver=nl80211)
+# This mode allows associated stations to use 4-address frames to allow layer 2
+# bridging to be used.
+#wds_sta=1
+
+# If bridge parameter is set, the WDS STA interface will be added to the same
+# bridge by default. This can be overridden with the wds_bridge parameter to
+# use a separate bridge.
+#wds_bridge=wds-br0
+
+# Client isolation can be used to prevent low-level bridging of frames between
+# associated stations in the BSS. By default, this bridging is allowed.
+#ap_isolate=1
+
+##### IEEE 802.11n related configuration ######################################
+
+# ieee80211n: Whether IEEE 802.11n (HT) is enabled
+# 0 = disabled (default)
+# 1 = enabled
+# Note: You will also need to enable WMM for full HT functionality.
+#ieee80211n=1
+
+# ht_capab: HT capabilities (list of flags)
+# LDPC coding capability: [LDPC] = supported
+# Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary
+#      channel below the primary channel; [HT40+] = both 20 MHz and 40 MHz
+#      with secondary channel below the primary channel
+#      (20 MHz only if neither is set)
+#      Note: There are limits on which channels can be used with HT40- and
+#      HT40+. Following table shows the channels that may be available for
+#      HT40- and HT40+ use per IEEE 802.11n Annex J:
+#      freq            HT40-           HT40+
+#      2.4 GHz         5-13            1-7 (1-9 in Europe/Japan)
+#      5 GHz           40,48,56,64     36,44,52,60
+#      (depending on the location, not all of these channels may be available
+#      for use)
+#      Please note that 40 MHz channels may switch their primary and secondary
+#      channels if needed or creation of 40 MHz channel maybe rejected based
+#      on overlapping BSSes. These changes are done automatically when hostapd
+#      is setting up the 40 MHz channel.
+# Spatial Multiplexing (SM) Power Save: [SMPS-STATIC] or [SMPS-DYNAMIC]
+#      (SMPS disabled if neither is set)
+# HT-greenfield: [GF] (disabled if not set)
+# Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set)
+# Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set)
+# Tx STBC: [TX-STBC] (disabled if not set)
+# Rx STBC: [RX-STBC1] (one spatial stream), [RX-STBC12] (one or two spatial
+#      streams), or [RX-STBC123] (one, two, or three spatial streams); Rx STBC
+#      disabled if none of these set
+# HT-delayed Block Ack: [DELAYED-BA] (disabled if not set)
+# Maximum A-MSDU length: [MAX-AMSDU-7935] for 7935 octets (3839 octets if not
+#      set)
+# DSSS/CCK Mode in 40 MHz: [DSSS_CCK-40] = allowed (not allowed if not set)
+# PSMP support: [PSMP] (disabled if not set)
+# L-SIG TXOP protection support: [LSIG-TXOP-PROT] (disabled if not set)
+#ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40]
+
+# Require stations to support HT PHY (reject association if they do not)
+#require_ht=1
+
+##### IEEE 802.1X-2004 related configuration ##################################
+
+# Require IEEE 802.1X authorization
+#ieee8021x=1
+
+# IEEE 802.1X/EAPOL version
+# hostapd is implemented based on IEEE Std 802.1X-2004 which defines EAPOL
+# version 2. However, there are many client implementations that do not handle
+# the new version number correctly (they seem to drop the frames completely).
+# In order to make hostapd interoperate with these clients, the version number
+# can be set to the older version (1) with this configuration value.
+#eapol_version=2
+
+# Optional displayable message sent with EAP Request-Identity. The first \0
+# in this string will be converted to ASCII-0 (nul). This can be used to
+# separate network info (comma separated list of attribute=value pairs); see,
+# e.g., RFC 4284.
+#eap_message=hello
+#eap_message=hello\0networkid=netw,nasid=foo,portid=0,NAIRealms=example.com
+
+# WEP rekeying (disabled if key lengths are not set or are set to 0)
+# Key lengths for default/broadcast and individual/unicast keys:
+# 5 = 40-bit WEP (also known as 64-bit WEP with 40 secret bits)
+# 13 = 104-bit WEP (also known as 128-bit WEP with 104 secret bits)
+#wep_key_len_broadcast=5
+#wep_key_len_unicast=5
+# Rekeying period in seconds. 0 = do not rekey (i.e., set keys only once)
+#wep_rekey_period=300
+
+# EAPOL-Key index workaround (set bit7) for WinXP Supplicant (needed only if
+# only broadcast keys are used)
+eapol_key_index_workaround=0
+
+# EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable
+# reauthentication).
+#eap_reauth_period=3600
+
+# Use PAE group address (01:80:c2:00:00:03) instead of individual target
+# address when sending EAPOL frames with driver=wired. This is the most common
+# mechanism used in wired authentication, but it also requires that the port
+# is only used by one station.
+#use_pae_group_addr=1
+
+##### Integrated EAP server ###################################################
+
+# Optionally, hostapd can be configured to use an integrated EAP server
+# to process EAP authentication locally without need for an external RADIUS
+# server. This functionality can be used both as a local authentication server
+# for IEEE 802.1X/EAPOL and as a RADIUS server for other devices.
+
+# Use integrated EAP server instead of external RADIUS authentication
+# server. This is also needed if hostapd is configured to act as a RADIUS
+# authentication server.
+eap_server=0
+
+# Path for EAP server user database
+#eap_user_file=/etc/hostapd.eap_user
+
+# CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
+#ca_cert=/etc/hostapd.ca.pem
+
+# Server certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
+#server_cert=/etc/hostapd.server.pem
+
+# Private key matching with the server certificate for EAP-TLS/PEAP/TTLS
+# This may point to the same file as server_cert if both certificate and key
+# are included in a single file. PKCS#12 (PFX) file (.p12/.pfx) can also be
+# used by commenting out server_cert and specifying the PFX file as the
+# private_key.
+#private_key=/etc/hostapd.server.prv
+
+# Passphrase for private key
+#private_key_passwd=secret passphrase
+
+# Enable CRL verification.
+# Note: hostapd does not yet support CRL downloading based on CDP. Thus, a
+# valid CRL signed by the CA is required to be included in the ca_cert file.
+# This can be done by using PEM format for CA certificate and CRL and
+# concatenating these into one file. Whenever CRL changes, hostapd needs to be
+# restarted to take the new CRL into use.
+# 0 = do not verify CRLs (default)
+# 1 = check the CRL of the user certificate
+# 2 = check all CRLs in the certificate path
+#check_crl=1
+
+# dh_file: File path to DH/DSA parameters file (in PEM format)
+# This is an optional configuration file for setting parameters for an
+# ephemeral DH key exchange. In most cases, the default RSA authentication does
+# not use this configuration. However, it is possible setup RSA to use
+# ephemeral DH key exchange. In addition, ciphers with DSA keys always use
+# ephemeral DH keys. This can be used to achieve forward secrecy. If the file
+# is in DSA parameters format, it will be automatically converted into DH
+# params. This parameter is required if anonymous EAP-FAST is used.
+# You can generate DH parameters file with OpenSSL, e.g.,
+# "openssl dhparam -out /etc/hostapd.dh.pem 1024"
+#dh_file=/etc/hostapd.dh.pem
+
+# Fragment size for EAP methods
+#fragment_size=1400
+
+# Finite cyclic group for EAP-pwd. Number maps to group of domain parameters
+# using the IANA repository for IKE (RFC 2409).
+#pwd_group=19
+
+# Configuration data for EAP-SIM database/authentication gateway interface.
+# This is a text string in implementation specific format. The example
+# implementation in eap_sim_db.c uses this as the UNIX domain socket name for
+# the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:"
+# prefix.
+#eap_sim_db=unix:/tmp/hlr_auc_gw.sock
+
+# Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret,
+# random value. It is configured as a 16-octet value in hex format. It can be
+# generated, e.g., with the following command:
+# od -tx1 -v -N16 /dev/random | colrm 1 8 | tr -d ' '
+#pac_opaque_encr_key=000102030405060708090a0b0c0d0e0f
+
+# EAP-FAST authority identity (A-ID)
+# A-ID indicates the identity of the authority that issues PACs. The A-ID
+# should be unique across all issuing servers. In theory, this is a variable
+# length field, but due to some existing implementations requiring A-ID to be
+# 16 octets in length, it is strongly recommended to use that length for the
+# field to provid interoperability with deployed peer implementations. This
+# field is configured in hex format.
+#eap_fast_a_id=101112131415161718191a1b1c1d1e1f
+
+# EAP-FAST authority identifier information (A-ID-Info)
+# This is a user-friendly name for the A-ID. For example, the enterprise name
+# and server name in a human-readable format. This field is encoded as UTF-8.
+#eap_fast_a_id_info=test server
+
+# Enable/disable different EAP-FAST provisioning modes:
+#0 = provisioning disabled
+#1 = only anonymous provisioning allowed
+#2 = only authenticated provisioning allowed
+#3 = both provisioning modes allowed (default)
+#eap_fast_prov=3
+
+# EAP-FAST PAC-Key lifetime in seconds (hard limit)
+#pac_key_lifetime=604800
+
+# EAP-FAST PAC-Key refresh time in seconds (soft limit on remaining hard
+# limit). The server will generate a new PAC-Key when this number of seconds
+# (or fewer) of the lifetime remains.
+#pac_key_refresh_time=86400
+
+# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND
+# (default: 0 = disabled).
+#eap_sim_aka_result_ind=1
+
+# Trusted Network Connect (TNC)
+# If enabled, TNC validation will be required before the peer is allowed to
+# connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other
+# EAP method is enabled, the peer will be allowed to connect without TNC.
+#tnc=1
+
+
+##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
+
+# Interface to be used for IAPP broadcast packets
+#iapp_interface=eth0
+
+
+##### RADIUS client configuration #############################################
+# for IEEE 802.1X with external Authentication Server, IEEE 802.11
+# authentication with external ACL for MAC addresses, and accounting
+
+# The own IP address of the access point (used as NAS-IP-Address)
+own_ip_addr=127.0.0.1
+
+# Optional NAS-Identifier string for RADIUS messages. When used, this should be
+# a unique to the NAS within the scope of the RADIUS server. For example, a
+# fully qualified domain name can be used here.
+# When using IEEE 802.11r, nas_identifier must be set and must be between 1 and
+# 48 octets long.
+#nas_identifier=ap.example.com
+
+# RADIUS authentication server
+#auth_server_addr=127.0.0.1
+#auth_server_port=1812
+#auth_server_shared_secret=secret
+
+# RADIUS accounting server
+#acct_server_addr=127.0.0.1
+#acct_server_port=1813
+#acct_server_shared_secret=secret
+
+# Secondary RADIUS servers; to be used if primary one does not reply to
+# RADIUS packets. These are optional and there can be more than one secondary
+# server listed.
+#auth_server_addr=127.0.0.2
+#auth_server_port=1812
+#auth_server_shared_secret=secret2
+#
+#acct_server_addr=127.0.0.2
+#acct_server_port=1813
+#acct_server_shared_secret=secret2
+
+# Retry interval for trying to return to the primary RADIUS server (in
+# seconds). RADIUS client code will automatically try to use the next server
+# when the current server is not replying to requests. If this interval is set,
+# primary server will be retried after configured amount of time even if the
+# currently used secondary server is still working.
+#radius_retry_primary_interval=600
+
+
+# Interim accounting update interval
+# If this is set (larger than 0) and acct_server is configured, hostapd will
+# send interim accounting updates every N seconds. Note: if set, this overrides
+# possible Acct-Interim-Interval attribute in Access-Accept message. Thus, this
+# value should not be configured in hostapd.conf, if RADIUS server is used to
+# control the interim interval.
+# This value should not be less 600 (10 minutes) and must not be less than
+# 60 (1 minute).
+#radius_acct_interim_interval=600
+
+# Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN
+# is used for the stations. This information is parsed from following RADIUS
+# attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN),
+# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
+# VLANID as a string). vlan_file option below must be configured if dynamic
+# VLANs are used. Optionally, the local MAC ACL list (accept_mac_file) can be
+# used to set static client MAC address to VLAN ID mapping.
+# 0 = disabled (default)
+# 1 = option; use default interface if RADIUS server does not include VLAN ID
+# 2 = required; reject authentication if RADIUS server does not include VLAN ID
+#dynamic_vlan=0
+
+# VLAN interface list for dynamic VLAN mode is read from a separate text file.
+# This list is used to map VLAN ID from the RADIUS server to a network
+# interface. Each station is bound to one interface in the same way as with
+# multiple BSSIDs or SSIDs. Each line in this text file is defining a new
+# interface and the line must include VLAN ID and interface name separated by
+# white space (space or tab).
+#vlan_file=/etc/hostapd.vlan
+
+# Interface where 802.1q tagged packets should appear when a RADIUS server is
+# used to determine which VLAN a station is on.  hostapd creates a bridge for
+# each VLAN.  Then hostapd adds a VLAN interface (associated with the interface
+# indicated by 'vlan_tagged_interface') and the appropriate wireless interface
+# to the bridge.
+#vlan_tagged_interface=eth0
+
+
+##### RADIUS authentication server configuration ##############################
+
+# hostapd can be used as a RADIUS authentication server for other hosts. This
+# requires that the integrated EAP server is also enabled and both
+# authentication services are sharing the same configuration.
+
+# File name of the RADIUS clients configuration for the RADIUS server. If this
+# commented out, RADIUS server is disabled.
+#radius_server_clients=/etc/hostapd.radius_clients
+
+# The UDP port number for the RADIUS authentication server
+#radius_server_auth_port=1812
+
+# Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API)
+#radius_server_ipv6=1
+
+
+##### WPA/IEEE 802.11i configuration ##########################################
+
+# Enable WPA. Setting this variable configures the AP to require WPA (either
+# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
+# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
+# Instead of wpa_psk / wpa_passphrase, wpa_psk_radius might suffice.
+# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
+# RADIUS authentication server must be configured, and WPA-EAP must be included
+# in wpa_key_mgmt.
+# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
+# and/or WPA2 (full IEEE 802.11i/RSN):
+# bit0 = WPA
+# bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled)
+#wpa=1
+
+# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
+# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
+# (8..63 characters) that will be converted to PSK. This conversion uses SSID
+# so the PSK changes when ASCII passphrase is used and the SSID is changed.
+# wpa_psk (dot11RSNAConfigPSKValue)
+# wpa_passphrase (dot11RSNAConfigPSKPassPhrase)
+#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+#wpa_passphrase=secret passphrase
+
+# Optionally, WPA PSKs can be read from a separate text file (containing list
+# of (PSK,MAC address) pairs. This allows more than one PSK to be configured.
+# Use absolute path name to make sure that the files can be read on SIGHUP
+# configuration reloads.
+#wpa_psk_file=/etc/hostapd.wpa_psk
+
+# Optionally, WPA passphrase can be received from RADIUS authentication server
+# This requires macaddr_acl to be set to 2 (RADIUS)
+# 0 = disabled (default)
+# 1 = optional; use default passphrase/psk if RADIUS server does not include
+#      Tunnel-Password
+# 2 = required; reject authentication if RADIUS server does not include
+#      Tunnel-Password
+#wpa_psk_radius=0
+
+# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
+# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
+# added to enable SHA256-based stronger algorithms.
+# (dot11RSNAConfigAuthenticationSuitesTable)
+#wpa_key_mgmt=WPA-PSK WPA-EAP
+
+# Set of accepted cipher suites (encryption algorithms) for pairwise keys
+# (unicast packets). This is a space separated list of algorithms:
+# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
+# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
+# Group cipher suite (encryption algorithm for broadcast and multicast frames)
+# is automatically selected based on this configuration. If only CCMP is
+# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
+# TKIP will be used as the group cipher.
+# (dot11RSNAConfigPairwiseCiphersTable)
+# Pairwise cipher for WPA (v1) (default: TKIP)
+#wpa_pairwise=TKIP CCMP
+# Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value)
+#rsn_pairwise=CCMP
+
+# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
+# seconds. (dot11RSNAConfigGroupRekeyTime)
+#wpa_group_rekey=600
+
+# Rekey GTK when any STA that possesses the current GTK is leaving the BSS.
+# (dot11RSNAConfigGroupRekeyStrict)
+#wpa_strict_rekey=1
+
+# Time interval for rekeying GMK (master key used internally to generate GTKs
+# (in seconds).
+#wpa_gmk_rekey=86400
+
+# Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of
+# PTK to mitigate some attacks against TKIP deficiencies.
+#wpa_ptk_rekey=600
+
+# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
+# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
+# authentication and key handshake before actually associating with a new AP.
+# (dot11RSNAPreauthenticationEnabled)
+#rsn_preauth=1
+#
+# Space separated list of interfaces from which pre-authentication frames are
+# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all
+# interface that are used for connections to other APs. This could include
+# wired interfaces and WDS links. The normal wireless data interface towards
+# associated stations (e.g., wlan0) should not be added, since
+# pre-authentication is only used with APs other than the currently associated
+# one.
+#rsn_preauth_interfaces=eth0
+
+# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e) is
+# allowed. This is only used with RSN/WPA2.
+# 0 = disabled (default)
+# 1 = enabled
+#peerkey=1
+
+# ieee80211w: Whether management frame protection (MFP) is enabled
+# 0 = disabled (default)
+# 1 = optional
+# 2 = required
+#ieee80211w=0
+
+# Association SA Query maximum timeout (in TU = 1.024 ms; for MFP)
+# (maximum time to wait for a SA Query response)
+# dot11AssociationSAQueryMaximumTimeout, 1...4294967295
+#assoc_sa_query_max_timeout=1000
+
+# Association SA Query retry timeout (in TU = 1.024 ms; for MFP)
+# (time between two subsequent SA Query requests)
+# dot11AssociationSAQueryRetryTimeout, 1...4294967295
+#assoc_sa_query_retry_timeout=201
+
+# disable_pmksa_caching: Disable PMKSA caching
+# This parameter can be used to disable caching of PMKSA created through EAP
+# authentication. RSN preauthentication may still end up using PMKSA caching if
+# it is enabled (rsn_preauth=1).
+# 0 = PMKSA caching enabled (default)
+# 1 = PMKSA caching disabled
+#disable_pmksa_caching=0
+
+# okc: Opportunistic Key Caching (aka Proactive Key Caching)
+# Allow PMK cache to be shared opportunistically among configured interfaces
+# and BSSes (i.e., all configurations within a single hostapd process).
+# 0 = disabled (default)
+# 1 = enabled
+#okc=1
+
+
+##### IEEE 802.11r configuration ##############################################
+
+# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
+# MDID is used to indicate a group of APs (within an ESS, i.e., sharing the
+# same SSID) between which a STA can use Fast BSS Transition.
+# 2-octet identifier as a hex string.
+#mobility_domain=a1b2
+
+# PMK-R0 Key Holder identifier (dot11FTR0KeyHolderID)
+# 1 to 48 octet identifier.
+# This is configured with nas_identifier (see RADIUS client section above).
+
+# Default lifetime of the PMK-RO in minutes; range 1..65535
+# (dot11FTR0KeyLifetime)
+#r0_key_lifetime=10000
+
+# PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID)
+# 6-octet identifier as a hex string.
+#r1_key_holder=000102030405
+
+# Reassociation deadline in time units (TUs / 1.024 ms; range 1000..65535)
+# (dot11FTReassociationDeadline)
+#reassociation_deadline=1000
+
+# List of R0KHs in the same Mobility Domain
+# format: <MAC address> <NAS Identifier> <128-bit key as hex string>
+# This list is used to map R0KH-ID (NAS Identifier) to a destination MAC
+# address when requesting PMK-R1 key from the R0KH that the STA used during the
+# Initial Mobility Domain Association.
+#r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f
+#r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff
+# And so on.. One line per R0KH.
+
+# List of R1KHs in the same Mobility Domain
+# format: <MAC address> <R1KH-ID> <128-bit key as hex string>
+# This list is used to map R1KH-ID to a destination MAC address when sending
+# PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD
+# that can request PMK-R1 keys.
+#r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f
+#r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff
+# And so on.. One line per R1KH.
+
+# Whether PMK-R1 push is enabled at R0KH
+# 0 = do not push PMK-R1 to all configured R1KHs (default)
+# 1 = push PMK-R1 to all configured R1KHs whenever a new PMK-R0 is derived
+#pmk_r1_push=1
+
+##### Neighbor table ##########################################################
+# Maximum number of entries kept in AP table (either for neigbor table or for
+# detecting Overlapping Legacy BSS Condition). The oldest entry will be
+# removed when adding a new entry that would make the list grow over this
+# limit. Note! WFA certification for IEEE 802.11g requires that OLBC is
+# enabled, so this field should not be set to 0 when using IEEE 802.11g.
+# default: 255
+#ap_table_max_size=255
+
+# Number of seconds of no frames received after which entries may be deleted
+# from the AP table. Since passive scanning is not usually performed frequently
+# this should not be set to very small value. In addition, there is no
+# guarantee that every scan cycle will receive beacon frames from the
+# neighboring APs.
+# default: 60
+#ap_table_expiration_time=3600
+
+
+##### Wi-Fi Protected Setup (WPS) #############################################
+
+# WPS state
+# 0 = WPS disabled (default)
+# 1 = WPS enabled, not configured
+# 2 = WPS enabled, configured
+#wps_state=2
+
+# AP can be configured into a locked state where new WPS Registrar are not
+# accepted, but previously authorized Registrars (including the internal one)
+# can continue to add new Enrollees.
+#ap_setup_locked=1
+
+# Universally Unique IDentifier (UUID; see RFC 4122) of the device
+# This value is used as the UUID for the internal WPS Registrar. If the AP
+# is also using UPnP, this value should be set to the device's UPnP UUID.
+# If not configured, UUID will be generated based on the local MAC address.
+#uuid=12345678-9abc-def0-1234-56789abcdef0
+
+# Note: If wpa_psk_file is set, WPS is used to generate random, per-device PSKs
+# that will be appended to the wpa_psk_file. If wpa_psk_file is not set, the
+# default PSK (wpa_psk/wpa_passphrase) will be delivered to Enrollees. Use of
+# per-device PSKs is recommended as the more secure option (i.e., make sure to
+# set wpa_psk_file when using WPS with WPA-PSK).
+
+# When an Enrollee requests access to the network with PIN method, the Enrollee
+# PIN will need to be entered for the Registrar. PIN request notifications are
+# sent to hostapd ctrl_iface monitor. In addition, they can be written to a
+# text file that could be used, e.g., to populate the AP administration UI with
+# pending PIN requests. If the following variable is set, the PIN requests will
+# be written to the configured file.
+#wps_pin_requests=/var/run/hostapd_wps_pin_requests
+
+# Device Name
+# User-friendly description of device; up to 32 octets encoded in UTF-8
+#device_name=Wireless AP
+
+# Manufacturer
+# The manufacturer of the device (up to 64 ASCII characters)
+#manufacturer=Company
+
+# Model Name
+# Model of the device (up to 32 ASCII characters)
+#model_name=WAP
+
+# Model Number
+# Additional device description (up to 32 ASCII characters)
+#model_number=123
+
+# Serial Number
+# Serial number of the device (up to 32 characters)
+#serial_number=12345
+
+# Primary Device Type
+# Used format: <categ>-<OUI>-<subcateg>
+# categ = Category as an integer value
+# OUI = OUI and type octet as a 4-octet hex-encoded value; 0050F204 for
+#       default WPS OUI
+# subcateg = OUI-specific Sub Category as an integer value
+# Examples:
+#   1-0050F204-1 (Computer / PC)
+#   1-0050F204-2 (Computer / Server)
+#   5-0050F204-1 (Storage / NAS)
+#   6-0050F204-1 (Network Infrastructure / AP)
+#device_type=6-0050F204-1
+
+# OS Version
+# 4-octet operating system version number (hex string)
+#os_version=01020300
+
+# Config Methods
+# List of the supported configuration methods
+# Available methods: usba ethernet label display ext_nfc_token int_nfc_token
+#      nfc_interface push_button keypad virtual_display physical_display
+#      virtual_push_button physical_push_button
+#config_methods=label virtual_display virtual_push_button keypad
+
+# WPS capability discovery workaround for PBC with Windows 7
+# Windows 7 uses incorrect way of figuring out AP's WPS capabilities by acting
+# as a Registrar and using M1 from the AP. The config methods attribute in that
+# message is supposed to indicate only the configuration method supported by
+# the AP in Enrollee role, i.e., to add an external Registrar. For that case,
+# PBC shall not be used and as such, the PushButton config method is removed
+# from M1 by default. If pbc_in_m1=1 is included in the configuration file,
+# the PushButton config method is left in M1 (if included in config_methods
+# parameter) to allow Windows 7 to use PBC instead of PIN (e.g., from a label
+# in the AP).
+#pbc_in_m1=1
+
+# Static access point PIN for initial configuration and adding Registrars
+# If not set, hostapd will not allow external WPS Registrars to control the
+# access point. The AP PIN can also be set at runtime with hostapd_cli
+# wps_ap_pin command. Use of temporary (enabled by user action) and random
+# AP PIN is much more secure than configuring a static AP PIN here. As such,
+# use of the ap_pin parameter is not recommended if the AP device has means for
+# displaying a random PIN.
+#ap_pin=12345670
+
+# Skip building of automatic WPS credential
+# This can be used to allow the automatically generated Credential attribute to
+# be replaced with pre-configured Credential(s).
+#skip_cred_build=1
+
+# Additional Credential attribute(s)
+# This option can be used to add pre-configured Credential attributes into M8
+# message when acting as a Registrar. If skip_cred_build=1, this data will also
+# be able to override the Credential attribute that would have otherwise been
+# automatically generated based on network configuration. This configuration
+# option points to an external file that much contain the WPS Credential
+# attribute(s) as binary data.
+#extra_cred=hostapd.cred
+
+# Credential processing
+#   0 = process received credentials internally (default)
+#   1 = do not process received credentials; just pass them over ctrl_iface to
+#      external program(s)
+#   2 = process received credentials internally and pass them over ctrl_iface
+#      to external program(s)
+# Note: With wps_cred_processing=1, skip_cred_build should be set to 1 and
+# extra_cred be used to provide the Credential data for Enrollees.
+#
+# wps_cred_processing=1 will disabled automatic updates of hostapd.conf file
+# both for Credential processing and for marking AP Setup Locked based on
+# validation failures of AP PIN. An external program is responsible on updating
+# the configuration appropriately in this case.
+#wps_cred_processing=0
+
+# AP Settings Attributes for M7
+# By default, hostapd generates the AP Settings Attributes for M7 based on the
+# current configuration. It is possible to override this by providing a file
+# with pre-configured attributes. This is similar to extra_cred file format,
+# but the AP Settings attributes are not encapsulated in a Credential
+# attribute.
+#ap_settings=hostapd.ap_settings
+
+# WPS UPnP interface
+# If set, support for external Registrars is enabled.
+#upnp_iface=br0
+
+# Friendly Name (required for UPnP)
+# Short description for end use. Should be less than 64 characters.
+#friendly_name=WPS Access Point
+
+# Manufacturer URL (optional for UPnP)
+#manufacturer_url=http://www.example.com/
+
+# Model Description (recommended for UPnP)
+# Long description for end user. Should be less than 128 characters.
+#model_description=Wireless Access Point
+
+# Model URL (optional for UPnP)
+#model_url=http://www.example.com/model/
+
+# Universal Product Code (optional for UPnP)
+# 12-digit, all-numeric code that identifies the consumer package.
+#upc=123456789012
+
+# WPS RF Bands (a = 5G, b = 2.4G, g = 2.4G, ag = dual band)
+# This value should be set according to RF band(s) supported by the AP if
+# hw_mode is not set. For dual band dual concurrent devices, this needs to be
+# set to ag to allow both RF bands to be advertized.
+#wps_rf_bands=ag
+
+##### Wi-Fi Direct (P2P) ######################################################
+
+# Enable P2P Device management
+#manage_p2p=1
+
+# Allow cross connection
+#allow_cross_connection=1
+
+#### TDLS (IEEE 802.11z-2010) #################################################
+
+# Prohibit use of TDLS in this BSS
+#tdls_prohibit=1
+
+# Prohibit use of TDLS Channel Switching in this BSS
+#tdls_prohibit_chan_switch=1
+
+##### IEEE 802.11v-2011 #######################################################
+
+# Time advertisement
+# 0 = disabled (default)
+# 2 = UTC time at which the TSF timer is 0
+#time_advertisement=2
+
+# Local time zone as specified in 8.3 of IEEE Std 1003.1-2004:
+# stdoffset[dst[offset][,start[/time],end[/time]]]
+#time_zone=EST5
+
+##### IEEE 802.11u-2011 #######################################################
+
+# Enable Interworking service
+#interworking=1
+
+# Access Network Type
+# 0 = Private network
+# 1 = Private network with guest access
+# 2 = Chargeable public network
+# 3 = Free public network
+# 4 = Personal device network
+# 5 = Emergency services only network
+# 14 = Test or experimental
+# 15 = Wildcard
+#access_network_type=0
+
+# Whether the network provides connectivity to the Internet
+# 0 = Unspecified
+# 1 = Network provides connectivity to the Internet
+#internet=1
+
+# Additional Step Required for Access
+# Note: This is only used with open network, i.e., ASRA shall ne set to 0 if
+# RSN is used.
+#asra=0
+
+# Emergency services reachable
+#esr=0
+
+# Unauthenticated emergency service accessible
+#uesa=0
+
+# Venue Info (optional)
+# The available values are defined in IEEE Std 802.11u-2011, 7.3.1.34.
+# Example values (group,type):
+# 0,0 = Unspecified
+# 1,7 = Convention Center
+# 1,13 = Coffee Shop
+# 2,0 = Unspecified Business
+# 7,1  Private Residence
+#venue_group=7
+#venue_type=1
+
+# Homogeneous ESS identifier (optional; dot11HESSID)
+# If set, this shall be identifical to one of the BSSIDs in the homogeneous
+# ESS and this shall be set to the same value across all BSSs in homogeneous
+# ESS.
+#hessid=02:03:04:05:06:07
+
+# Roaming Consortium List
+# Arbitrary number of Roaming Consortium OIs can be configured with each line
+# adding a new OI to the list. The first three entries are available through
+# Beacon and Probe Response frames. Any additional entry will be available only
+# through ANQP queries. Each OI is between 3 and 15 octets and is configured a
+# a hexstring.
+#roaming_consortium=021122
+#roaming_consortium=2233445566
+
+##### Multiple BSSID support ##################################################
+#
+# Above configuration is using the default interface (wlan#, or multi-SSID VLAN
+# interfaces). Other BSSIDs can be added by using separator 'bss' with
+# default interface name to be allocated for the data packets of the new BSS.
+#
+# hostapd will generate BSSID mask based on the BSSIDs that are
+# configured. hostapd will verify that dev_addr & MASK == dev_addr. If this is
+# not the case, the MAC address of the radio must be changed before starting
+# hostapd (ifconfig wlan0 hw ether <MAC addr>). If a BSSID is configured for
+# every secondary BSS, this limitation is not applied at hostapd and other
+# masks may be used if the driver supports them (e.g., swap the locally
+# administered bit)
+#
+# BSSIDs are assigned in order to each BSS, unless an explicit BSSID is
+# specified using the 'bssid' parameter.
+# If an explicit BSSID is specified, it must be chosen such that it:
+# - results in a valid MASK that covers it and the dev_addr
+# - is not the same as the MAC address of the radio
+# - is not the same as any other explicitly specified BSSID
+#
+# Please note that hostapd uses some of the values configured for the first BSS
+# as the defaults for the following BSSes. However, it is recommended that all
+# BSSes include explicit configuration of all relevant configuration items.
+#
+#bss=wlan0_0
+#ssid=test2
+# most of the above items can be used here (apart from radio interface specific
+# items, like channel)
+
+#bss=wlan0_1
+#bssid=00:13:10:95:fe:0b
+# ...
diff --git a/hostapd/hostapd.deny b/hostapd/hostapd.deny
new file mode 100644 (file)
index 0000000..1616678
--- /dev/null
@@ -0,0 +1,5 @@
+# List of MAC addresses that are not allowed to authenticate (IEEE 802.11)
+# with the AP.
+00:20:30:40:50:60
+00:ab:cd:ef:12:34
+00:00:30:40:50:60
diff --git a/hostapd/hostapd.eap_user b/hostapd/hostapd.eap_user
new file mode 100644 (file)
index 0000000..ac9a5d8
--- /dev/null
@@ -0,0 +1,91 @@
+# hostapd user database for integrated EAP server
+
+# Each line must contain an identity, EAP method(s), and an optional password
+# separated with whitespace (space or tab). The identity and password must be
+# double quoted ("user"). Password can alternatively be stored as
+# NtPasswordHash (16-byte MD4 hash of the unicode presentation of the password
+# in unicode) if it is used for MSCHAP or MSCHAPv2 authentication. This means
+# that the plaintext password does not need to be included in the user file.
+# Password hash is stored as hash:<16-octets of hex data> without quotation
+# marks.
+
+# [2] flag in the end of the line can be used to mark users for tunneled phase
+# 2 authentication (e.g., within EAP-PEAP). In these cases, an anonymous
+# identity can be used in the unencrypted phase 1 and the real user identity
+# is transmitted only within the encrypted tunnel in phase 2. If non-anonymous
+# access is needed, two user entries is needed, one for phase 1 and another
+# with the same username for phase 2.
+#
+# EAP-TLS, EAP-PEAP, EAP-TTLS, EAP-FAST, EAP-SIM, and EAP-AKA do not use
+# password option.
+# EAP-MD5, EAP-MSCHAPV2, EAP-GTC, EAP-PAX, EAP-PSK, and EAP-SAKE require a
+# password.
+# EAP-PEAP, EAP-TTLS, and EAP-FAST require Phase 2 configuration.
+#
+# * can be used as a wildcard to match any user identity. The main purposes for
+# this are to set anonymous phase 1 identity for EAP-PEAP and EAP-TTLS and to
+# avoid having to configure every certificate for EAP-TLS authentication. The
+# first matching entry is selected, so * should be used as the last phase 1
+# user entry.
+#
+# "prefix"* can be used to match the given prefix and anything after this. The
+# main purpose for this is to be able to avoid EAP method negotiation when the
+# method is using known prefix in identities (e.g., EAP-SIM and EAP-AKA). This
+# is only allowed for phase 1 identities.
+#
+# Multiple methods can be configured to make the authenticator try them one by
+# one until the peer accepts one. The method names are separated with a
+# comma (,).
+#
+# [ver=0] and [ver=1] flags after EAP type PEAP can be used to force PEAP
+# version based on the Phase 1 identity. Without this flag, the EAP
+# authenticator advertises the highest supported version and select the version
+# based on the first PEAP packet from the supplicant.
+#
+# EAP-TTLS supports both EAP and non-EAP authentication inside the tunnel.
+# Tunneled EAP methods are configured with standard EAP method name and [2]
+# flag. Non-EAP methods can be enabled by following method names: TTLS-PAP,
+# TTLS-CHAP, TTLS-MSCHAP, TTLS-MSCHAPV2. TTLS-PAP and TTLS-CHAP require a
+# plaintext password while TTLS-MSCHAP and TTLS-MSCHAPV2 can use NT password
+# hash.
+
+# Phase 1 users
+"user"         MD5     "password"
+"test user"    MD5     "secret"
+"example user" TLS
+"DOMAIN\user"  MSCHAPV2        "password"
+"gtc user"     GTC     "password"
+"pax user"     PAX     "unknown"
+"pax.user@example.com" PAX     0123456789abcdef0123456789abcdef
+"psk user"     PSK     "unknown"
+"psk.user@example.com" PSK     0123456789abcdef0123456789abcdef
+"sake.user@example.com"        SAKE    0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+"ttls"         TTLS
+"not anonymous"        PEAP
+# Default to EAP-SIM and EAP-AKA based on fixed identity prefixes
+"0"*           AKA,TTLS,TLS,PEAP,SIM
+"1"*           SIM,TTLS,TLS,PEAP,AKA
+"2"*           AKA,TTLS,TLS,PEAP,SIM
+"3"*           SIM,TTLS,TLS,PEAP,AKA
+"4"*           AKA,TTLS,TLS,PEAP,SIM
+"5"*           SIM,TTLS,TLS,PEAP,AKA
+
+# Wildcard for all other identities
+*              PEAP,TTLS,TLS,SIM,AKA
+
+# Phase 2 (tunnelled within EAP-PEAP or EAP-TTLS) users
+"t-md5"                MD5     "password"      [2]
+"DOMAIN\t-mschapv2"    MSCHAPV2        "password"      [2]
+"t-gtc"                GTC     "password"      [2]
+"not anonymous"        MSCHAPV2        "password"      [2]
+"user"         MD5,GTC,MSCHAPV2        "password"      [2]
+"test user"    MSCHAPV2        hash:000102030405060708090a0b0c0d0e0f   [2]
+"ttls-user"    TTLS-PAP,TTLS-CHAP,TTLS-MSCHAP,TTLS-MSCHAPV2    "password"      [2]
+
+# Default to EAP-SIM and EAP-AKA based on fixed identity prefixes in phase 2
+"0"*           AKA     [2]
+"1"*           SIM     [2]
+"2"*           AKA     [2]
+"3"*           SIM     [2]
+"4"*           AKA     [2]
+"5"*           SIM     [2]
diff --git a/hostapd/hostapd.radius_clients b/hostapd/hostapd.radius_clients
new file mode 100644 (file)
index 0000000..3980427
--- /dev/null
@@ -0,0 +1,4 @@
+# RADIUS client configuration for the RADIUS server
+10.1.2.3       secret passphrase
+192.168.1.0/24 another very secret passphrase
+0.0.0.0/0      radius
diff --git a/hostapd/hostapd.sim_db b/hostapd/hostapd.sim_db
new file mode 100644 (file)
index 0000000..01c593d
--- /dev/null
@@ -0,0 +1,9 @@
+# Example GSM authentication triplet file for EAP-SIM authenticator
+# IMSI:Kc:SRES:RAND
+# IMSI: ASCII string (numbers)
+# Kc: hex, 8 octets
+# SRES: hex, 4 octets
+# RAND: hex, 16 octets
+234567898765432:A0A1A2A3A4A5A6A7:D1D2D3D4:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+234567898765432:B0B1B2B3B4B5B6B7:E1E2E3E4:BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
+234567898765432:C0C1C2C3C4C5C6C7:F1F2F3F4:CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
diff --git a/hostapd/hostapd.vlan b/hostapd/hostapd.vlan
new file mode 100644 (file)
index 0000000..98254fa
--- /dev/null
@@ -0,0 +1,9 @@
+# VLAN ID to network interface mapping
+1      vlan1
+2      vlan2
+3      vlan3
+100    guest
+# Optional wildcard entry matching all VLAN IDs. The first # in the interface
+# name will be replaced with the VLAN ID. The network interfaces are created
+# (and removed) dynamically based on the use.
+*      vlan#
diff --git a/hostapd/hostapd.wpa_psk b/hostapd/hostapd.wpa_psk
new file mode 100644 (file)
index 0000000..0a9499a
--- /dev/null
@@ -0,0 +1,9 @@
+# List of WPA PSKs. Each line, except for empty lines and lines starting
+# with #, must contain a MAC address and PSK separated with a space.
+# Special MAC address 00:00:00:00:00:00 can be used to configure PSKs that
+# anyone can use. PSK can be configured as an ASCII passphrase of 8..63
+# characters or as a 256-bit hex PSK (64 hex digits).
+00:00:00:00:00:00 secret passphrase
+00:11:22:33:44:55 another passphrase
+00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+00:00:00:00:00:00 another passphrase for all STAs
diff --git a/hostapd/hostapd_cli.1 b/hostapd/hostapd_cli.1
new file mode 100644 (file)
index 0000000..218ea15
--- /dev/null
@@ -0,0 +1,89 @@
+.TH HOSTAPD_CLI 1 "April  7, 2005" hostapd_cli "hostapd command-line interface"
+.SH NAME
+hostapd_cli \- hostapd command-line interface
+.SH SYNOPSIS
+.B hostapd_cli
+[\-p<path>] [\-i<ifname>] [\-a<path>] [\-hvB] [command..]
+.SH DESCRIPTION
+This manual page documents briefly the
+.B hostapd_cli
+utility.
+.PP
+.B hostapd_cli
+is a command-line interface for the
+.B hostapd
+daemon.
+
+.B hostapd
+is a user space daemon for access point and authentication servers.
+It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server.
+For more information about
+.B hostapd
+refer to the
+.BR hostapd (8)
+man page.
+.SH OPTIONS
+A summary of options is included below.
+For a complete description, run
+.BR hostapd_cli
+from the command line.
+.TP
+.B \-p<path>
+Path to find control sockets.
+
+Default: /var/run/hostapd
+.TP
+.B \-i<ifname>
+Interface to listen on.
+
+Default: first interface found in socket path.
+.TP
+.B \-a<path>
+Run in daemon mode executing the action file based on events from hostapd.
+.TP
+.B \-B
+Run a daemon in the background.
+.TP
+.B \-h
+Show usage.
+.TP
+.B \-v
+Show hostapd_cli version.
+.SH COMMANDS
+A summary of commands is included below.
+For a complete description, run
+.BR hostapd_cli
+from the command line.
+.TP
+.B mib
+Get MIB variables (dot1x, dot11, radius).
+.TP
+.B sta <addr>
+Get MIB variables for one station.
+.TP
+.B all_sta
+Get MIB variables for all stations.
+.TP
+.B help
+Get usage help.
+.TP
+.B interface [ifname] 
+Show interfaces/select interface.
+.TP
+.B level <debug level>
+Change debug level.
+.TP
+.B license
+Show full
+.B hostapd_cli
+license.
+.TP
+.B quit
+Exit hostapd_cli.
+.SH SEE ALSO
+.BR hostapd (8).
+.SH AUTHOR
+hostapd_cli was written by Jouni Malinen <j@w1.fi>. 
+.PP
+This manual page was written by Faidon Liambotis <faidon@cube.gr>,
+for the Debian project (but may be used by others).
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
new file mode 100644 (file)
index 0000000..527860c
--- /dev/null
@@ -0,0 +1,1086 @@
+/*
+ * hostapd - command line interface for hostapd daemon
+ * 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.
+ */
+
+#include "includes.h"
+#include <dirent.h>
+
+#include "common/wpa_ctrl.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/edit.h"
+#include "common/version.h"
+
+
+static const char *hostapd_cli_version =
+"hostapd_cli v" VERSION_STR "\n"
+"Copyright (c) 2004-2011, 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";
+
+static const char *hostapd_cli_full_license =
+"This program is free software; you can redistribute it and/or modify\n"
+"it under the terms of the GNU General Public License version 2 as\n"
+"published by the Free Software Foundation.\n"
+"\n"
+"This program is distributed in the hope that it will be useful,\n"
+"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
+"GNU General Public License for more details.\n"
+"\n"
+"You should have received a copy of the GNU General Public License\n"
+"along with this program; if not, write to the Free Software\n"
+"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n"
+"\n"
+"Alternatively, this software may be distributed under the terms of the\n"
+"BSD license.\n"
+"\n"
+"Redistribution and use in source and binary forms, with or without\n"
+"modification, are permitted provided that the following conditions are\n"
+"met:\n"
+"\n"
+"1. Redistributions of source code must retain the above copyright\n"
+"   notice, this list of conditions and the following disclaimer.\n"
+"\n"
+"2. Redistributions in binary form must reproduce the above copyright\n"
+"   notice, this list of conditions and the following disclaimer in the\n"
+"   documentation and/or other materials provided with the distribution.\n"
+"\n"
+"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
+"   names of its contributors may be used to endorse or promote products\n"
+"   derived from this software without specific prior written permission.\n"
+"\n"
+"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
+"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
+"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
+"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
+"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
+"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
+"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
+"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
+"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
+"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
+"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
+"\n";
+
+static const char *commands_help =
+"Commands:\n"
+"   mib                  get MIB variables (dot1x, dot11, radius)\n"
+"   sta <addr>           get MIB variables for one station\n"
+"   all_sta              get MIB variables for all stations\n"
+"   new_sta <addr>       add a new station\n"
+"   deauthenticate <addr>  deauthenticate a station\n"
+"   disassociate <addr>  disassociate a station\n"
+#ifdef CONFIG_IEEE80211W
+"   sa_query <addr>      send SA Query to a station\n"
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WPS
+"   wps_pin <uuid> <pin> [timeout] [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_ap_pin <cmd> [params..]  enable/disable AP PIN\n"
+"   wps_config <SSID> <auth> <encr> <key>  configure AP\n"
+#endif /* CONFIG_WPS */
+"   get_config           show current configuration\n"
+"   help                 show this usage help\n"
+"   interface [ifname]   show interfaces/select interface\n"
+"   level <debug level>  change debug level\n"
+"   license              show full hostapd_cli license\n"
+"   quit                 exit hostapd_cli\n";
+
+static struct wpa_ctrl *ctrl_conn;
+static int hostapd_cli_quit = 0;
+static int hostapd_cli_attached = 0;
+static const char *ctrl_iface_dir = "/var/run/hostapd";
+static char *ctrl_ifname = NULL;
+static const char *pid_file = NULL;
+static const char *action_file = NULL;
+static int ping_interval = 5;
+static int interactive = 0;
+
+
+static void usage(void)
+{
+       fprintf(stderr, "%s\n", hostapd_cli_version);
+       fprintf(stderr,
+               "\n"
+               "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
+               "[-a<path>] \\\n"
+               "                   [-G<ping interval>] [command..]\n"
+               "\n"
+               "Options:\n"
+               "   -h           help (show this usage text)\n"
+               "   -v           shown version information\n"
+               "   -p<path>     path to find control sockets (default: "
+               "/var/run/hostapd)\n"
+               "   -a<file>     run in daemon mode executing the action file "
+               "based on events\n"
+               "                from hostapd\n"
+               "   -B           run a daemon in the background\n"
+               "   -i<ifname>   Interface to listen on (default: first "
+               "interface found in the\n"
+               "                socket path)\n\n"
+               "%s",
+               commands_help);
+}
+
+
+static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
+{
+       char *cfile;
+       int flen;
+
+       if (ifname == NULL)
+               return NULL;
+
+       flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
+       cfile = malloc(flen);
+       if (cfile == NULL)
+               return NULL;
+       snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
+
+       ctrl_conn = wpa_ctrl_open(cfile);
+       free(cfile);
+       return ctrl_conn;
+}
+
+
+static void hostapd_cli_close_connection(void)
+{
+       if (ctrl_conn == NULL)
+               return;
+
+       if (hostapd_cli_attached) {
+               wpa_ctrl_detach(ctrl_conn);
+               hostapd_cli_attached = 0;
+       }
+       wpa_ctrl_close(ctrl_conn);
+       ctrl_conn = NULL;
+}
+
+
+static void hostapd_cli_msg_cb(char *msg, size_t len)
+{
+       printf("%s\n", msg);
+}
+
+
+static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
+{
+       char buf[4096];
+       size_t len;
+       int ret;
+
+       if (ctrl_conn == NULL) {
+               printf("Not connected to hostapd - command dropped.\n");
+               return -1;
+       }
+       len = sizeof(buf) - 1;
+       ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
+                              hostapd_cli_msg_cb);
+       if (ret == -2) {
+               printf("'%s' command timed out.\n", cmd);
+               return -2;
+       } else if (ret < 0) {
+               printf("'%s' command failed.\n", cmd);
+               return -1;
+       }
+       if (print) {
+               buf[len] = '\0';
+               printf("%s", buf);
+       }
+       return 0;
+}
+
+
+static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
+{
+       return _wpa_ctrl_command(ctrl, cmd, 1);
+}
+
+
+static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "PING");
+}
+
+
+static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "RELOG");
+}
+
+
+static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "MIB");
+}
+
+
+static int hostapd_cli_exec(const char *program, const char *arg1,
+                           const char *arg2)
+{
+       char *cmd;
+       size_t len;
+       int res;
+       int ret = 0;
+
+       len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
+       cmd = os_malloc(len);
+       if (cmd == NULL)
+               return -1;
+       res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
+       if (res < 0 || (size_t) res >= len) {
+               os_free(cmd);
+               return -1;
+       }
+       cmd[len - 1] = '\0';
+#ifndef _WIN32_WCE
+       if (system(cmd) < 0)
+               ret = -1;
+#endif /* _WIN32_WCE */
+       os_free(cmd);
+
+       return ret;
+}
+
+
+static void hostapd_cli_action_process(char *msg, size_t len)
+{
+       const char *pos;
+
+       pos = msg;
+       if (*pos == '<') {
+               pos = os_strchr(pos, '>');
+               if (pos)
+                       pos++;
+               else
+                       pos = msg;
+       }
+
+       hostapd_cli_exec(action_file, ctrl_ifname, pos);
+}
+
+
+static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       char buf[64];
+       if (argc != 1) {
+               printf("Invalid 'sta' command - exactly one argument, STA "
+                      "address, is required.\n");
+               return -1;
+       }
+       snprintf(buf, sizeof(buf), "STA %s", argv[0]);
+       return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
+                                  char *argv[])
+{
+       char buf[64];
+       if (argc != 1) {
+               printf("Invalid 'new_sta' command - exactly one argument, STA "
+                      "address, is required.\n");
+               return -1;
+       }
+       snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
+       return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
+                                         char *argv[])
+{
+       char buf[64];
+       if (argc < 1) {
+               printf("Invalid 'deauthenticate' command - exactly one "
+                      "argument, STA address, is required.\n");
+               return -1;
+       }
+       if (argc > 1)
+               os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
+                           argv[0], argv[1]);
+       else
+               os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
+       return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
+                                       char *argv[])
+{
+       char buf[64];
+       if (argc < 1) {
+               printf("Invalid 'disassociate' command - exactly one "
+                      "argument, STA address, is required.\n");
+               return -1;
+       }
+       if (argc > 1)
+               os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
+                           argv[0], argv[1]);
+       else
+               os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
+       return wpa_ctrl_command(ctrl, buf);
+}
+
+
+#ifdef CONFIG_IEEE80211W
+static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
+                                   char *argv[])
+{
+       char buf[64];
+       if (argc != 1) {
+               printf("Invalid 'sa_query' command - exactly one argument, "
+                      "STA address, is required.\n");
+               return -1;
+       }
+       snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
+       return wpa_ctrl_command(ctrl, buf);
+}
+#endif /* CONFIG_IEEE80211W */
+
+
+#ifdef CONFIG_WPS
+static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
+                                  char *argv[])
+{
+       char buf[256];
+       if (argc < 2) {
+               printf("Invalid 'wps_pin' command - at least two arguments, "
+                      "UUID and PIN, are required.\n");
+               return -1;
+       }
+       if (argc > 3)
+               snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
+                        argv[0], argv[1], argv[2], argv[3]);
+       else if (argc > 2)
+               snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
+                        argv[0], argv[1], argv[2]);
+       else
+               snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
+       return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
+                                        char *argv[])
+{
+       char cmd[256];
+       int res;
+
+       if (argc != 1 && argc != 2) {
+               printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
+                      "- PIN to be verified\n");
+               return -1;
+       }
+
+       if (argc == 2)
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
+                                 argv[0], argv[1]);
+       else
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
+                                 argv[0]);
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long WPS_CHECK_PIN command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
+                                  char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "WPS_PBC");
+}
+
+
+#ifdef CONFIG_WPS_OOB
+static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
+                                  char *argv[])
+{
+       char cmd[256];
+       int res;
+
+       if (argc != 3 && argc != 4) {
+               printf("Invalid WPS_OOB command: need three or four "
+                      "arguments:\n"
+                      "- DEV_TYPE: use 'ufd' or 'nfc'\n"
+                      "- PATH: path of OOB device like '/mnt'\n"
+                      "- METHOD: OOB method 'pin-e' or 'pin-r', "
+                      "'cred'\n"
+                      "- DEV_NAME: (only for NFC) device name like "
+                      "'pn531'\n");
+               return -1;
+       }
+
+       if (argc == 3)
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
+                                 argv[0], argv[1], argv[2]);
+       else
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
+                                 argv[0], argv[1], argv[2], argv[3]);
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long WPS_OOB command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+#endif /* CONFIG_WPS_OOB */
+
+
+static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
+                                     char *argv[])
+{
+       char buf[64];
+       if (argc < 1) {
+               printf("Invalid 'wps_ap_pin' command - at least one argument "
+                      "is required.\n");
+               return -1;
+       }
+       if (argc > 2)
+               snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
+                        argv[0], argv[1], argv[2]);
+       else if (argc > 1)
+               snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
+                        argv[0], argv[1]);
+       else
+               snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
+       return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
+                                     char *argv[])
+{
+       char buf[256];
+       char ssid_hex[2 * 32 + 1];
+       char key_hex[2 * 64 + 1];
+       int i;
+
+       if (argc < 1) {
+               printf("Invalid 'wps_config' command - at least two arguments "
+                      "are required.\n");
+               return -1;
+       }
+
+       ssid_hex[0] = '\0';
+       for (i = 0; i < 32; i++) {
+               if (argv[0][i] == '\0')
+                       break;
+               os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
+       }
+
+       key_hex[0] = '\0';
+       if (argc > 3) {
+               for (i = 0; i < 64; i++) {
+                       if (argv[3][i] == '\0')
+                               break;
+                       os_snprintf(&key_hex[i * 2], 3, "%02x",
+                                   argv[3][i]);
+               }
+       }
+
+       if (argc > 3)
+               snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
+                        ssid_hex, argv[1], argv[2], key_hex);
+       else if (argc > 2)
+               snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
+                        ssid_hex, argv[1], argv[2]);
+       else
+               snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
+                        ssid_hex, argv[1]);
+       return wpa_ctrl_command(ctrl, buf);
+}
+#endif /* CONFIG_WPS */
+
+
+static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
+                                       char *argv[])
+{
+       char buf[300];
+       int res;
+
+       if (argc < 2) {
+               printf("Invalid 'ess_disassoc' command - two arguments (STA "
+                      "addr and URL) are needed\n");
+               return -1;
+       }
+
+       res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s",
+                         argv[0], argv[1]);
+       if (res < 0 || res >= (int) sizeof(buf))
+               return -1;
+       return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
+                                     char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "GET_CONFIG");
+}
+
+
+static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
+                               char *addr, size_t addr_len)
+{
+       char buf[4096], *pos;
+       size_t len;
+       int ret;
+
+       if (ctrl_conn == NULL) {
+               printf("Not connected to hostapd - command dropped.\n");
+               return -1;
+       }
+       len = sizeof(buf) - 1;
+       ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
+                              hostapd_cli_msg_cb);
+       if (ret == -2) {
+               printf("'%s' command timed out.\n", cmd);
+               return -2;
+       } else if (ret < 0) {
+               printf("'%s' command failed.\n", cmd);
+               return -1;
+       }
+
+       buf[len] = '\0';
+       if (memcmp(buf, "FAIL", 4) == 0)
+               return -1;
+       printf("%s", buf);
+
+       pos = buf;
+       while (*pos != '\0' && *pos != '\n')
+               pos++;
+       *pos = '\0';
+       os_strlcpy(addr, buf, addr_len);
+       return 0;
+}
+
+
+static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
+                                  char *argv[])
+{
+       char addr[32], cmd[64];
+
+       if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
+               return 0;
+       do {
+               snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
+       } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
+
+       return -1;
+}
+
+
+static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       printf("%s", commands_help);
+       return 0;
+}
+
+
+static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
+                                  char *argv[])
+{
+       printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
+       return 0;
+}
+
+
+static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       hostapd_cli_quit = 1;
+       if (interactive)
+               eloop_terminate();
+       return 0;
+}
+
+
+static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       char cmd[256];
+       if (argc != 1) {
+               printf("Invalid LEVEL command: needs one argument (debug "
+                      "level)\n");
+               return 0;
+       }
+       snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
+{
+       struct dirent *dent;
+       DIR *dir;
+
+       dir = opendir(ctrl_iface_dir);
+       if (dir == NULL) {
+               printf("Control interface directory '%s' could not be "
+                      "openned.\n", ctrl_iface_dir);
+               return;
+       }
+
+       printf("Available interfaces:\n");
+       while ((dent = readdir(dir))) {
+               if (strcmp(dent->d_name, ".") == 0 ||
+                   strcmp(dent->d_name, "..") == 0)
+                       continue;
+               printf("%s\n", dent->d_name);
+       }
+       closedir(dir);
+}
+
+
+static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
+                                    char *argv[])
+{
+       if (argc < 1) {
+               hostapd_cli_list_interfaces(ctrl);
+               return 0;
+       }
+
+       hostapd_cli_close_connection();
+       free(ctrl_ifname);
+       ctrl_ifname = strdup(argv[0]);
+
+       if (hostapd_cli_open_connection(ctrl_ifname)) {
+               printf("Connected to interface '%s.\n", ctrl_ifname);
+               if (wpa_ctrl_attach(ctrl_conn) == 0) {
+                       hostapd_cli_attached = 1;
+               } else {
+                       printf("Warning: Failed to attach to "
+                              "hostapd.\n");
+               }
+       } else {
+               printf("Could not connect to interface '%s' - re-trying\n",
+                       ctrl_ifname);
+       }
+       return 0;
+}
+
+
+static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       char cmd[256];
+       int res;
+
+       if (argc != 2) {
+               printf("Invalid SET command: needs two arguments (variable "
+                      "name and value)\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long SET command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       char cmd[256];
+       int res;
+
+       if (argc != 1) {
+               printf("Invalid GET command: needs one argument (variable "
+                      "name)\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long GET command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+struct hostapd_cli_cmd {
+       const char *cmd;
+       int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
+};
+
+static struct hostapd_cli_cmd hostapd_cli_commands[] = {
+       { "ping", hostapd_cli_cmd_ping },
+       { "mib", hostapd_cli_cmd_mib },
+       { "relog", hostapd_cli_cmd_relog },
+       { "sta", hostapd_cli_cmd_sta },
+       { "all_sta", hostapd_cli_cmd_all_sta },
+       { "new_sta", hostapd_cli_cmd_new_sta },
+       { "deauthenticate", hostapd_cli_cmd_deauthenticate },
+       { "disassociate", hostapd_cli_cmd_disassociate },
+#ifdef CONFIG_IEEE80211W
+       { "sa_query", hostapd_cli_cmd_sa_query },
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WPS
+       { "wps_pin", hostapd_cli_cmd_wps_pin },
+       { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
+       { "wps_pbc", hostapd_cli_cmd_wps_pbc },
+#ifdef CONFIG_WPS_OOB
+       { "wps_oob", hostapd_cli_cmd_wps_oob },
+#endif /* CONFIG_WPS_OOB */
+       { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
+       { "wps_config", hostapd_cli_cmd_wps_config },
+#endif /* CONFIG_WPS */
+       { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
+       { "get_config", hostapd_cli_cmd_get_config },
+       { "help", hostapd_cli_cmd_help },
+       { "interface", hostapd_cli_cmd_interface },
+       { "level", hostapd_cli_cmd_level },
+       { "license", hostapd_cli_cmd_license },
+       { "quit", hostapd_cli_cmd_quit },
+       { "set", hostapd_cli_cmd_set },
+       { "get", hostapd_cli_cmd_get },
+       { NULL, NULL }
+};
+
+
+static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       struct hostapd_cli_cmd *cmd, *match = NULL;
+       int count;
+
+       count = 0;
+       cmd = hostapd_cli_commands;
+       while (cmd->cmd) {
+               if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
+                       match = cmd;
+                       if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
+                               /* we have an exact match */
+                               count = 1;
+                               break;
+                       }
+                       count++;
+               }
+               cmd++;
+       }
+
+       if (count > 1) {
+               printf("Ambiguous command '%s'; possible commands:", argv[0]);
+               cmd = hostapd_cli_commands;
+               while (cmd->cmd) {
+                       if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
+                           0) {
+                               printf(" %s", cmd->cmd);
+                       }
+                       cmd++;
+               }
+               printf("\n");
+       } else if (count == 0) {
+               printf("Unknown command '%s'\n", argv[0]);
+       } else {
+               match->handler(ctrl, argc - 1, &argv[1]);
+       }
+}
+
+
+static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
+                                    int action_monitor)
+{
+       int first = 1;
+       if (ctrl_conn == NULL)
+               return;
+       while (wpa_ctrl_pending(ctrl)) {
+               char buf[256];
+               size_t len = sizeof(buf) - 1;
+               if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
+                       buf[len] = '\0';
+                       if (action_monitor)
+                               hostapd_cli_action_process(buf, len);
+                       else {
+                               if (in_read && first)
+                                       printf("\n");
+                               first = 0;
+                               printf("%s\n", buf);
+                       }
+               } else {
+                       printf("Could not read pending message.\n");
+                       break;
+               }
+       }
+}
+
+
+#define max_args 10
+
+static int tokenize_cmd(char *cmd, char *argv[])
+{
+       char *pos;
+       int argc = 0;
+
+       pos = cmd;
+       for (;;) {
+               while (*pos == ' ')
+                       pos++;
+               if (*pos == '\0')
+                       break;
+               argv[argc] = pos;
+               argc++;
+               if (argc == max_args)
+                       break;
+               if (*pos == '"') {
+                       char *pos2 = os_strrchr(pos, '"');
+                       if (pos2)
+                               pos = pos2 + 1;
+               }
+               while (*pos != '\0' && *pos != ' ')
+                       pos++;
+               if (*pos == ' ')
+                       *pos++ = '\0';
+       }
+
+       return argc;
+}
+
+
+static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
+{
+       if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
+               printf("Connection to hostapd lost - trying to reconnect\n");
+               hostapd_cli_close_connection();
+       }
+       if (!ctrl_conn) {
+               ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
+               if (ctrl_conn) {
+                       printf("Connection to hostapd re-established\n");
+                       if (wpa_ctrl_attach(ctrl_conn) == 0) {
+                               hostapd_cli_attached = 1;
+                       } else {
+                               printf("Warning: Failed to attach to "
+                                      "hostapd.\n");
+                       }
+               }
+       }
+       if (ctrl_conn)
+               hostapd_cli_recv_pending(ctrl_conn, 1, 0);
+       eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
+}
+
+
+static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
+{
+       eloop_terminate();
+}
+
+
+static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
+{
+       char *argv[max_args];
+       int argc;
+       argc = tokenize_cmd(cmd, argv);
+       if (argc)
+               wpa_request(ctrl_conn, argc, argv);
+}
+
+
+static void hostapd_cli_edit_eof_cb(void *ctx)
+{
+       eloop_terminate();
+}
+
+
+static void hostapd_cli_interactive(void)
+{
+       printf("\nInteractive mode\n\n");
+
+       eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
+       edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
+                 NULL, NULL, NULL);
+       eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
+
+       eloop_run();
+
+       edit_deinit(NULL, NULL);
+       eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
+}
+
+
+static void hostapd_cli_cleanup(void)
+{
+       hostapd_cli_close_connection();
+       if (pid_file)
+               os_daemonize_terminate(pid_file);
+
+       os_program_deinit();
+}
+
+
+static void hostapd_cli_action(struct wpa_ctrl *ctrl)
+{
+       fd_set rfds;
+       int fd, res;
+       struct timeval tv;
+       char buf[256];
+       size_t len;
+
+       fd = wpa_ctrl_get_fd(ctrl);
+
+       while (!hostapd_cli_quit) {
+               FD_ZERO(&rfds);
+               FD_SET(fd, &rfds);
+               tv.tv_sec = ping_interval;
+               tv.tv_usec = 0;
+               res = select(fd + 1, &rfds, NULL, NULL, &tv);
+               if (res < 0 && errno != EINTR) {
+                       perror("select");
+                       break;
+               }
+
+               if (FD_ISSET(fd, &rfds))
+                       hostapd_cli_recv_pending(ctrl, 0, 1);
+               else {
+                       len = sizeof(buf) - 1;
+                       if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
+                                            hostapd_cli_action_process) < 0 ||
+                           len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
+                               printf("hostapd did not reply to PING "
+                                      "command - exiting\n");
+                               break;
+                       }
+               }
+       }
+}
+
+
+int main(int argc, char *argv[])
+{
+       int warning_displayed = 0;
+       int c;
+       int daemonize = 0;
+
+       if (os_program_init())
+               return -1;
+
+       for (;;) {
+               c = getopt(argc, argv, "a:BhG:i:p:v");
+               if (c < 0)
+                       break;
+               switch (c) {
+               case 'a':
+                       action_file = optarg;
+                       break;
+               case 'B':
+                       daemonize = 1;
+                       break;
+               case 'G':
+                       ping_interval = atoi(optarg);
+                       break;
+               case 'h':
+                       usage();
+                       return 0;
+               case 'v':
+                       printf("%s\n", hostapd_cli_version);
+                       return 0;
+               case 'i':
+                       os_free(ctrl_ifname);
+                       ctrl_ifname = os_strdup(optarg);
+                       break;
+               case 'p':
+                       ctrl_iface_dir = optarg;
+                       break;
+               default:
+                       usage();
+                       return -1;
+               }
+       }
+
+       interactive = (argc == optind) && (action_file == NULL);
+
+       if (interactive) {
+               printf("%s\n\n%s\n\n", hostapd_cli_version,
+                      hostapd_cli_license);
+       }
+
+       if (eloop_init())
+               return -1;
+
+       for (;;) {
+               if (ctrl_ifname == NULL) {
+                       struct dirent *dent;
+                       DIR *dir = opendir(ctrl_iface_dir);
+                       if (dir) {
+                               while ((dent = readdir(dir))) {
+                                       if (os_strcmp(dent->d_name, ".") == 0
+                                           ||
+                                           os_strcmp(dent->d_name, "..") == 0)
+                                               continue;
+                                       printf("Selected interface '%s'\n",
+                                              dent->d_name);
+                                       ctrl_ifname = os_strdup(dent->d_name);
+                                       break;
+                               }
+                               closedir(dir);
+                       }
+               }
+               ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
+               if (ctrl_conn) {
+                       if (warning_displayed)
+                               printf("Connection established.\n");
+                       break;
+               }
+
+               if (!interactive) {
+                       perror("Failed to connect to hostapd - "
+                              "wpa_ctrl_open");
+                       return -1;
+               }
+
+               if (!warning_displayed) {
+                       printf("Could not connect to hostapd - re-trying\n");
+                       warning_displayed = 1;
+               }
+               os_sleep(1, 0);
+               continue;
+       }
+
+       if (interactive || action_file) {
+               if (wpa_ctrl_attach(ctrl_conn) == 0) {
+                       hostapd_cli_attached = 1;
+               } else {
+                       printf("Warning: Failed to attach to hostapd.\n");
+                       if (action_file)
+                               return -1;
+               }
+       }
+
+       if (daemonize && os_daemonize(pid_file))
+               return -1;
+
+       if (interactive)
+               hostapd_cli_interactive();
+       else if (action_file)
+               hostapd_cli_action(ctrl_conn);
+       else
+               wpa_request(ctrl_conn, argc - optind, &argv[optind]);
+
+       os_free(ctrl_ifname);
+       eloop_destroy();
+       hostapd_cli_cleanup();
+       return 0;
+}
diff --git a/hostapd/logwatch/README b/hostapd/logwatch/README
new file mode 100644 (file)
index 0000000..3cba511
--- /dev/null
@@ -0,0 +1,9 @@
+Logwatch is a utility for analyzing system logs and provide a human
+readable summary. This directory has a configuration file and a log
+analyzer script for parsing hostapd system log entries for logwatch.
+These files can be installed by copying them to following locations:
+
+/etc/log.d/conf/services/hostapd.conf
+/etc/log.d/scripts/services/hostapd
+
+More information about logwatch is available from http://www.logwatch.org/
diff --git a/hostapd/logwatch/hostapd b/hostapd/logwatch/hostapd
new file mode 100755 (executable)
index 0000000..97b24ef
--- /dev/null
@@ -0,0 +1,65 @@
+#!/usr/bin/perl -w
+#
+# Logwatch script for hostapd
+#
+# Copyright 2005 Henrik Brix Andersen <brix@gentoo.org>
+# Distributed under the terms of the GNU General Public License v2
+# Alternatively, this file may be distributed under the terms of the BSD License
+
+use strict;
+
+my $debug = $ENV{'LOGWATCH_DEBUG'} || 0;
+my $detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0;
+my $debugcounter = 1;
+
+my %hostapd;
+my @unmatched;
+
+if ($debug >= 5) {
+       print STDERR "\n\nDEBUG: Inside HOSTAPD Filter\n\n";
+}
+
+while (defined(my $line = <STDIN>)) {
+       if ($debug >= 5) {
+               print STDERR "DEBUG($debugcounter): $line";
+               $debugcounter++;
+       }
+    chomp($line);
+
+       if (my ($iface,$mac,$layer,$details) = ($line =~ /(.*?): STA (.*?) (.*?): (.*?)$/i)) {
+               unless ($detail == 10) {
+                       # collapse association events
+                       $details =~ s/^(associated) .*$/$1/i;
+               }
+               $hostapd{$iface}->{$mac}->{$layer}->{$details}++;
+       } else {
+               push @unmatched, "$line\n";
+       }
+}
+
+if (keys %hostapd) {
+       foreach my $iface (sort keys %hostapd) {
+               print "Interface $iface:\n";
+               foreach my $mac (sort keys %{$hostapd{$iface}}) {
+                       print "  Client MAC Address $mac:\n";
+                       foreach my $layer (sort keys %{$hostapd{$iface}->{$mac}}) {
+                               print "    $layer:\n";
+                               foreach my $details (sort keys %{$hostapd{$iface}->{$mac}->{$layer}}) {
+                                       print "      $details";
+                                       my $count = $hostapd{$iface}->{$mac}->{$layer}->{$details};
+                                       if ($count > 1) {
+                                               print ": " . $count . " Times";
+                                       }
+                                       print "\n";
+                               }
+                       }
+               }
+       }
+}
+
+if ($#unmatched >= 0) {
+    print "\n**Unmatched Entries**\n";
+    print @unmatched;
+}
+
+exit(0);
diff --git a/hostapd/logwatch/hostapd.conf b/hostapd/logwatch/hostapd.conf
new file mode 100644 (file)
index 0000000..5bebe6a
--- /dev/null
@@ -0,0 +1,10 @@
+# Logwatch configuration for hostapd
+#
+# Copyright 2005 Henrik Brix Andersen <brix@gentoo.org>
+# Distributed under the terms of the GNU General Public License v2
+# Alternatively, this file may be distributed under the terms of the BSD License
+
+Title = "hostapd"
+LogFile = messages
+*OnlyService = hostapd
+*RemoveHeaders
diff --git a/hostapd/main.c b/hostapd/main.c
new file mode 100644 (file)
index 0000000..da8135b
--- /dev/null
@@ -0,0 +1,659 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+#ifndef CONFIG_NATIVE_WINDOWS
+#include <syslog.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "crypto/random.h"
+#include "crypto/tls.h"
+#include "common/version.h"
+#include "drivers/driver.h"
+#include "eap_server/eap.h"
+#include "eap_server/tncs.h"
+#include "ap/hostapd.h"
+#include "ap/ap_config.h"
+#include "config_file.h"
+#include "eap_register.h"
+#include "dump_state.h"
+#include "ctrl_iface.h"
+
+
+extern int wpa_debug_level;
+extern int wpa_debug_show_keys;
+extern int wpa_debug_timestamp;
+
+extern struct wpa_driver_ops *wpa_drivers[];
+
+
+struct hapd_global {
+       void **drv_priv;
+       size_t drv_count;
+};
+
+static struct hapd_global global;
+
+
+struct hapd_interfaces {
+       size_t count;
+       struct hostapd_iface **iface;
+};
+
+
+static int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
+                                     int (*cb)(struct hostapd_iface *iface,
+                                               void *ctx), void *ctx)
+{
+       size_t i;
+       int ret;
+
+       for (i = 0; i < interfaces->count; i++) {
+               ret = cb(interfaces->iface[i], ctx);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+
+#ifndef CONFIG_NO_HOSTAPD_LOGGER
+static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
+                             int level, const char *txt, size_t len)
+{
+       struct hostapd_data *hapd = ctx;
+       char *format, *module_str;
+       int maxlen;
+       int conf_syslog_level, conf_stdout_level;
+       unsigned int conf_syslog, conf_stdout;
+
+       maxlen = len + 100;
+       format = os_malloc(maxlen);
+       if (!format)
+               return;
+
+       if (hapd && hapd->conf) {
+               conf_syslog_level = hapd->conf->logger_syslog_level;
+               conf_stdout_level = hapd->conf->logger_stdout_level;
+               conf_syslog = hapd->conf->logger_syslog;
+               conf_stdout = hapd->conf->logger_stdout;
+       } else {
+               conf_syslog_level = conf_stdout_level = 0;
+               conf_syslog = conf_stdout = (unsigned int) -1;
+       }
+
+       switch (module) {
+       case HOSTAPD_MODULE_IEEE80211:
+               module_str = "IEEE 802.11";
+               break;
+       case HOSTAPD_MODULE_IEEE8021X:
+               module_str = "IEEE 802.1X";
+               break;
+       case HOSTAPD_MODULE_RADIUS:
+               module_str = "RADIUS";
+               break;
+       case HOSTAPD_MODULE_WPA:
+               module_str = "WPA";
+               break;
+       case HOSTAPD_MODULE_DRIVER:
+               module_str = "DRIVER";
+               break;
+       case HOSTAPD_MODULE_IAPP:
+               module_str = "IAPP";
+               break;
+       case HOSTAPD_MODULE_MLME:
+               module_str = "MLME";
+               break;
+       default:
+               module_str = NULL;
+               break;
+       }
+
+       if (hapd && hapd->conf && addr)
+               os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s",
+                           hapd->conf->iface, MAC2STR(addr),
+                           module_str ? " " : "", module_str, txt);
+       else if (hapd && hapd->conf)
+               os_snprintf(format, maxlen, "%s:%s%s %s",
+                           hapd->conf->iface, module_str ? " " : "",
+                           module_str, txt);
+       else if (addr)
+               os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s",
+                           MAC2STR(addr), module_str ? " " : "",
+                           module_str, txt);
+       else
+               os_snprintf(format, maxlen, "%s%s%s",
+                           module_str, module_str ? ": " : "", txt);
+
+       if ((conf_stdout & module) && level >= conf_stdout_level) {
+               wpa_debug_print_timestamp();
+               printf("%s\n", format);
+       }
+
+#ifndef CONFIG_NATIVE_WINDOWS
+       if ((conf_syslog & module) && level >= conf_syslog_level) {
+               int priority;
+               switch (level) {
+               case HOSTAPD_LEVEL_DEBUG_VERBOSE:
+               case HOSTAPD_LEVEL_DEBUG:
+                       priority = LOG_DEBUG;
+                       break;
+               case HOSTAPD_LEVEL_INFO:
+                       priority = LOG_INFO;
+                       break;
+               case HOSTAPD_LEVEL_NOTICE:
+                       priority = LOG_NOTICE;
+                       break;
+               case HOSTAPD_LEVEL_WARNING:
+                       priority = LOG_WARNING;
+                       break;
+               default:
+                       priority = LOG_INFO;
+                       break;
+               }
+               syslog(priority, "%s", format);
+       }
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+       os_free(format);
+}
+#endif /* CONFIG_NO_HOSTAPD_LOGGER */
+
+
+/**
+ * hostapd_init - Allocate and initialize per-interface data
+ * @config_file: Path to the configuration file
+ * Returns: Pointer to the allocated interface data or %NULL on failure
+ *
+ * This function is used to allocate main data structures for per-interface
+ * data. The allocated data buffer will be freed by calling
+ * hostapd_cleanup_iface().
+ */
+static struct hostapd_iface * hostapd_init(const char *config_file)
+{
+       struct hostapd_iface *hapd_iface = NULL;
+       struct hostapd_config *conf = NULL;
+       struct hostapd_data *hapd;
+       size_t i;
+
+       hapd_iface = os_zalloc(sizeof(*hapd_iface));
+       if (hapd_iface == NULL)
+               goto fail;
+
+       hapd_iface->reload_config = hostapd_reload_config;
+       hapd_iface->config_read_cb = hostapd_config_read;
+       hapd_iface->config_fname = os_strdup(config_file);
+       if (hapd_iface->config_fname == NULL)
+               goto fail;
+       hapd_iface->ctrl_iface_init = hostapd_ctrl_iface_init;
+       hapd_iface->ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
+       hapd_iface->for_each_interface = hostapd_for_each_interface;
+
+       conf = hostapd_config_read(hapd_iface->config_fname);
+       if (conf == NULL)
+               goto fail;
+       hapd_iface->conf = conf;
+
+       hapd_iface->num_bss = conf->num_bss;
+       hapd_iface->bss = os_zalloc(conf->num_bss *
+                                   sizeof(struct hostapd_data *));
+       if (hapd_iface->bss == NULL)
+               goto fail;
+
+       for (i = 0; i < conf->num_bss; i++) {
+               hapd = hapd_iface->bss[i] =
+                       hostapd_alloc_bss_data(hapd_iface, conf,
+                                              &conf->bss[i]);
+               if (hapd == NULL)
+                       goto fail;
+               hapd->msg_ctx = hapd;
+       }
+
+       return hapd_iface;
+
+fail:
+       if (conf)
+               hostapd_config_free(conf);
+       if (hapd_iface) {
+               os_free(hapd_iface->config_fname);
+               os_free(hapd_iface->bss);
+               os_free(hapd_iface);
+       }
+       return NULL;
+}
+
+
+static int hostapd_driver_init(struct hostapd_iface *iface)
+{
+       struct wpa_init_params params;
+       size_t i;
+       struct hostapd_data *hapd = iface->bss[0];
+       struct hostapd_bss_config *conf = hapd->conf;
+       u8 *b = conf->bssid;
+       struct wpa_driver_capa capa;
+
+       if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) {
+               wpa_printf(MSG_ERROR, "No hostapd driver wrapper available");
+               return -1;
+       }
+
+       /* Initialize the driver interface */
+       if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5]))
+               b = NULL;
+
+       os_memset(&params, 0, sizeof(params));
+       for (i = 0; wpa_drivers[i]; i++) {
+               if (wpa_drivers[i] != hapd->driver)
+                       continue;
+
+               if (global.drv_priv[i] == NULL &&
+                   wpa_drivers[i]->global_init) {
+                       global.drv_priv[i] = wpa_drivers[i]->global_init();
+                       if (global.drv_priv[i] == NULL) {
+                               wpa_printf(MSG_ERROR, "Failed to initialize "
+                                          "driver '%s'",
+                                          wpa_drivers[i]->name);
+                               return -1;
+                       }
+               }
+
+               params.global_priv = global.drv_priv[i];
+               break;
+       }
+       params.bssid = b;
+       params.ifname = hapd->conf->iface;
+       params.ssid = (const u8 *) hapd->conf->ssid.ssid;
+       params.ssid_len = hapd->conf->ssid.ssid_len;
+       params.test_socket = hapd->conf->test_socket;
+       params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
+
+       params.num_bridge = hapd->iface->num_bss;
+       params.bridge = os_zalloc(hapd->iface->num_bss * sizeof(char *));
+       if (params.bridge == NULL)
+               return -1;
+       for (i = 0; i < hapd->iface->num_bss; i++) {
+               struct hostapd_data *bss = hapd->iface->bss[i];
+               if (bss->conf->bridge[0])
+                       params.bridge[i] = bss->conf->bridge;
+       }
+
+       params.own_addr = hapd->own_addr;
+
+       hapd->drv_priv = hapd->driver->hapd_init(hapd, &params);
+       os_free(params.bridge);
+       if (hapd->drv_priv == NULL) {
+               wpa_printf(MSG_ERROR, "%s driver initialization failed.",
+                          hapd->driver->name);
+               hapd->driver = NULL;
+               return -1;
+       }
+
+       if (hapd->driver->get_capa &&
+           hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
+               iface->drv_flags = capa.flags;
+               iface->probe_resp_offloads = capa.probe_resp_offloads;
+       }
+
+       return 0;
+}
+
+
+static void hostapd_interface_deinit_free(struct hostapd_iface *iface)
+{
+       const struct wpa_driver_ops *driver;
+       void *drv_priv;
+       if (iface == NULL)
+               return;
+       driver = iface->bss[0]->driver;
+       drv_priv = iface->bss[0]->drv_priv;
+       hostapd_interface_deinit(iface);
+       if (driver && driver->hapd_deinit)
+               driver->hapd_deinit(drv_priv);
+       hostapd_interface_free(iface);
+}
+
+
+static struct hostapd_iface *
+hostapd_interface_init(struct hapd_interfaces *interfaces,
+                      const char *config_fname, int debug)
+{
+       struct hostapd_iface *iface;
+       int k;
+
+       wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
+       iface = hostapd_init(config_fname);
+       if (!iface)
+               return NULL;
+       iface->interfaces = interfaces;
+
+       for (k = 0; k < debug; k++) {
+               if (iface->bss[0]->conf->logger_stdout_level > 0)
+                       iface->bss[0]->conf->logger_stdout_level--;
+       }
+
+       if (hostapd_driver_init(iface) ||
+           hostapd_setup_interface(iface)) {
+               hostapd_interface_deinit_free(iface);
+               return NULL;
+       }
+
+       return iface;
+}
+
+
+/**
+ * handle_term - SIGINT and SIGTERM handler to terminate hostapd process
+ */
+static void handle_term(int sig, void *signal_ctx)
+{
+       wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig);
+       eloop_terminate();
+}
+
+
+#ifndef CONFIG_NATIVE_WINDOWS
+
+static int handle_reload_iface(struct hostapd_iface *iface, void *ctx)
+{
+       if (hostapd_reload_config(iface) < 0) {
+               wpa_printf(MSG_WARNING, "Failed to read new configuration "
+                          "file - continuing with old.");
+       }
+       return 0;
+}
+
+
+/**
+ * handle_reload - SIGHUP handler to reload configuration
+ */
+static void handle_reload(int sig, void *signal_ctx)
+{
+       struct hapd_interfaces *interfaces = signal_ctx;
+       wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration",
+                  sig);
+       hostapd_for_each_interface(interfaces, handle_reload_iface, NULL);
+}
+
+
+static void handle_dump_state(int sig, void *signal_ctx)
+{
+#ifdef HOSTAPD_DUMP_STATE
+       struct hapd_interfaces *interfaces = signal_ctx;
+       hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL);
+#endif /* HOSTAPD_DUMP_STATE */
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+static int hostapd_global_init(struct hapd_interfaces *interfaces,
+                              const char *entropy_file)
+{
+       int i;
+
+       os_memset(&global, 0, sizeof(global));
+
+       hostapd_logger_register_cb(hostapd_logger_cb);
+
+       if (eap_server_register_methods()) {
+               wpa_printf(MSG_ERROR, "Failed to register EAP methods");
+               return -1;
+       }
+
+       if (eloop_init()) {
+               wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+               return -1;
+       }
+
+       random_init(entropy_file);
+
+#ifndef CONFIG_NATIVE_WINDOWS
+       eloop_register_signal(SIGHUP, handle_reload, interfaces);
+       eloop_register_signal(SIGUSR1, handle_dump_state, interfaces);
+#endif /* CONFIG_NATIVE_WINDOWS */
+       eloop_register_signal_terminate(handle_term, interfaces);
+
+#ifndef CONFIG_NATIVE_WINDOWS
+       openlog("hostapd", 0, LOG_DAEMON);
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+       for (i = 0; wpa_drivers[i]; i++)
+               global.drv_count++;
+       if (global.drv_count == 0) {
+               wpa_printf(MSG_ERROR, "No drivers enabled");
+               return -1;
+       }
+       global.drv_priv = os_zalloc(global.drv_count * sizeof(void *));
+       if (global.drv_priv == NULL)
+               return -1;
+
+       return 0;
+}
+
+
+static void hostapd_global_deinit(const char *pid_file)
+{
+       int i;
+
+       for (i = 0; wpa_drivers[i] && global.drv_priv; i++) {
+               if (!global.drv_priv[i])
+                       continue;
+               wpa_drivers[i]->global_deinit(global.drv_priv[i]);
+       }
+       os_free(global.drv_priv);
+       global.drv_priv = NULL;
+
+#ifdef EAP_SERVER_TNC
+       tncs_global_deinit();
+#endif /* EAP_SERVER_TNC */
+
+       random_deinit();
+
+       eloop_destroy();
+
+#ifndef CONFIG_NATIVE_WINDOWS
+       closelog();
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+       eap_server_unregister_methods();
+
+       os_daemonize_terminate(pid_file);
+}
+
+
+static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
+                             const char *pid_file)
+{
+#ifdef EAP_SERVER_TNC
+       int tnc = 0;
+       size_t i, k;
+
+       for (i = 0; !tnc && i < ifaces->count; i++) {
+               for (k = 0; k < ifaces->iface[i]->num_bss; k++) {
+                       if (ifaces->iface[i]->bss[0]->conf->tnc) {
+                               tnc++;
+                               break;
+                       }
+               }
+       }
+
+       if (tnc && tncs_global_init() < 0) {
+               wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
+               return -1;
+       }
+#endif /* EAP_SERVER_TNC */
+
+       if (daemonize && os_daemonize(pid_file)) {
+               perror("daemon");
+               return -1;
+       }
+
+       eloop_run();
+
+       return 0;
+}
+
+
+static void show_version(void)
+{
+       fprintf(stderr,
+               "hostapd v" VERSION_STR "\n"
+               "User space daemon for IEEE 802.11 AP management,\n"
+               "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
+               "Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> "
+               "and contributors\n");
+}
+
+
+static void usage(void)
+{
+       show_version();
+       fprintf(stderr,
+               "\n"
+               "usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
+               "<configuration file(s)>\n"
+               "\n"
+               "options:\n"
+               "   -h   show this usage\n"
+               "   -d   show more debug messages (-dd for even more)\n"
+               "   -B   run daemon in the background\n"
+               "   -e   entropy file\n"
+               "   -P   PID file\n"
+               "   -K   include key data in debug messages\n"
+#ifdef CONFIG_DEBUG_FILE
+               "   -f   log output to debug file instead of stdout\n"
+#endif /* CONFIG_DEBUG_FILE */
+               "   -t   include timestamps in some debug messages\n"
+               "   -v   show hostapd version\n");
+
+       exit(1);
+}
+
+
+static const char * hostapd_msg_ifname_cb(void *ctx)
+{
+       struct hostapd_data *hapd = ctx;
+       if (hapd && hapd->iconf && hapd->iconf->bss)
+               return hapd->iconf->bss->iface;
+       return NULL;
+}
+
+
+int main(int argc, char *argv[])
+{
+       struct hapd_interfaces interfaces;
+       int ret = 1;
+       size_t i;
+       int c, debug = 0, daemonize = 0;
+       char *pid_file = NULL;
+       const char *log_file = NULL;
+       const char *entropy_file = NULL;
+
+       if (os_program_init())
+               return -1;
+
+       for (;;) {
+               c = getopt(argc, argv, "Bde:f:hKP:tv");
+               if (c < 0)
+                       break;
+               switch (c) {
+               case 'h':
+                       usage();
+                       break;
+               case 'd':
+                       debug++;
+                       if (wpa_debug_level > 0)
+                               wpa_debug_level--;
+                       break;
+               case 'B':
+                       daemonize++;
+                       break;
+               case 'e':
+                       entropy_file = optarg;
+                       break;
+               case 'f':
+                       log_file = optarg;
+                       break;
+               case 'K':
+                       wpa_debug_show_keys++;
+                       break;
+               case 'P':
+                       os_free(pid_file);
+                       pid_file = os_rel2abs_path(optarg);
+                       break;
+               case 't':
+                       wpa_debug_timestamp++;
+                       break;
+               case 'v':
+                       show_version();
+                       exit(1);
+                       break;
+
+               default:
+                       usage();
+                       break;
+               }
+       }
+
+       if (optind == argc)
+               usage();
+
+       wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
+
+       if (log_file)
+               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 (hostapd_global_init(&interfaces, entropy_file))
+               return -1;
+
+       /* Initialize interfaces */
+       for (i = 0; i < interfaces.count; i++) {
+               interfaces.iface[i] = hostapd_interface_init(&interfaces,
+                                                            argv[optind + i],
+                                                            debug);
+               if (!interfaces.iface[i])
+                       goto out;
+       }
+
+       if (hostapd_global_run(&interfaces, daemonize, pid_file))
+               goto out;
+
+       ret = 0;
+
+ out:
+       /* Deinitialize all interfaces */
+       for (i = 0; i < interfaces.count; i++)
+               hostapd_interface_deinit_free(interfaces.iface[i]);
+       os_free(interfaces.iface);
+
+       hostapd_global_deinit(pid_file);
+       os_free(pid_file);
+
+       if (log_file)
+               wpa_debug_close_file();
+
+       os_program_deinit();
+
+       return ret;
+}
diff --git a/hostapd/nt_password_hash.c b/hostapd/nt_password_hash.c
new file mode 100644 (file)
index 0000000..839802a
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/ms_funcs.h"
+
+
+int main(int argc, char *argv[])
+{
+       unsigned char password_hash[16];
+       size_t i;
+       char *password, buf[64], *pos;
+
+       if (argc > 1)
+               password = argv[1];
+       else {
+               if (fgets(buf, sizeof(buf), stdin) == NULL) {
+                       printf("Failed to read password\n");
+                       return 1;
+               }
+               buf[sizeof(buf) - 1] = '\0';
+               pos = buf;
+               while (*pos != '\0') {
+                       if (*pos == '\r' || *pos == '\n') {
+                               *pos = '\0';
+                               break;
+                       }
+                       pos++;
+               }
+               password = buf;
+       }
+
+       if (nt_password_hash((u8 *) password, strlen(password), password_hash))
+               return -1;
+       for (i = 0; i < sizeof(password_hash); i++)
+               printf("%02x", password_hash[i]);
+       printf("\n");
+
+       return 0;
+}
diff --git a/hostapd/wired.conf b/hostapd/wired.conf
new file mode 100644 (file)
index 0000000..956f8c5
--- /dev/null
@@ -0,0 +1,40 @@
+##### hostapd configuration file ##############################################
+# Empty lines and lines starting with # are ignored
+
+# Example configuration file for wired authenticator. See hostapd.conf for
+# more details.
+
+interface=eth0
+driver=wired
+logger_stdout=-1
+logger_stdout_level=1
+debug=2
+dump_file=/tmp/hostapd.dump
+
+ieee8021x=1
+eap_reauth_period=3600
+
+use_pae_group_addr=1
+
+
+##### RADIUS configuration ####################################################
+# for IEEE 802.1X with external Authentication Server, IEEE 802.11
+# authentication with external ACL for MAC addresses, and accounting
+
+# The own IP address of the access point (used as NAS-IP-Address)
+own_ip_addr=127.0.0.1
+
+# Optional NAS-Identifier string for RADIUS messages. When used, this should be
+# a unique to the NAS within the scope of the RADIUS server. For example, a
+# fully qualified domain name can be used here.
+nas_identifier=ap.example.com
+
+# RADIUS authentication server
+auth_server_addr=127.0.0.1
+auth_server_port=1812
+auth_server_shared_secret=radius
+
+# RADIUS accounting server
+acct_server_addr=127.0.0.1
+acct_server_port=1813
+acct_server_shared_secret=radius
diff --git a/mac80211_hwsim/tests/0001-wpa2-psk/hostapd.conf b/mac80211_hwsim/tests/0001-wpa2-psk/hostapd.conf
new file mode 100644 (file)
index 0000000..08cde7e
--- /dev/null
@@ -0,0 +1,11 @@
+interface=wlan0
+driver=nl80211
+
+hw_mode=g
+channel=1
+ssid=mac80211 test
+
+wpa=2
+wpa_key_mgmt=WPA-PSK
+wpa_pairwise=CCMP
+wpa_passphrase=12345678
diff --git a/mac80211_hwsim/tests/0001-wpa2-psk/test.txt b/mac80211_hwsim/tests/0001-wpa2-psk/test.txt
new file mode 100644 (file)
index 0000000..05d85a0
--- /dev/null
@@ -0,0 +1,7 @@
+# WPA2-Personal (PSK) with CCMP, AP and single client
+
+modprobe mac80211_hwsim
+
+hostapd hostapd.conf
+
+wpa_supplicant -Dwext -iwlan1 -c wpa_supplicant.conf
diff --git a/mac80211_hwsim/tests/0001-wpa2-psk/wpa_supplicant.conf b/mac80211_hwsim/tests/0001-wpa2-psk/wpa_supplicant.conf
new file mode 100644 (file)
index 0000000..299128c
--- /dev/null
@@ -0,0 +1,10 @@
+ctrl_interface=/var/run/wpa_supplicant
+
+network={
+       ssid="mac80211 test"
+       psk="12345678"
+       key_mgmt=WPA-PSK
+       proto=WPA2
+       pairwise=CCMP
+       group=CCMP
+}
diff --git a/mac80211_hwsim/tests/0002-vlan/hostapd.accept b/mac80211_hwsim/tests/0002-vlan/hostapd.accept
new file mode 100644 (file)
index 0000000..e97a175
--- /dev/null
@@ -0,0 +1,2 @@
+02:00:00:00:01:00      1
+02:00:00:00:02:00      2
diff --git a/mac80211_hwsim/tests/0002-vlan/hostapd.conf b/mac80211_hwsim/tests/0002-vlan/hostapd.conf
new file mode 100644 (file)
index 0000000..8698f0e
--- /dev/null
@@ -0,0 +1,12 @@
+interface=wlan0
+driver=nl80211
+
+hw_mode=g
+channel=1
+ssid=mac80211 test
+
+dynamic_vlan=2
+vlan_file=hostapd.vlan
+
+macaddr_acl=0
+accept_mac_file=hostapd.accept
diff --git a/mac80211_hwsim/tests/0002-vlan/hostapd.vlan b/mac80211_hwsim/tests/0002-vlan/hostapd.vlan
new file mode 100644 (file)
index 0000000..b3750b2
--- /dev/null
@@ -0,0 +1 @@
+*      vlan#
diff --git a/mac80211_hwsim/tests/0002-vlan/test.txt b/mac80211_hwsim/tests/0002-vlan/test.txt
new file mode 100644 (file)
index 0000000..8c92f1c
--- /dev/null
@@ -0,0 +1,15 @@
+# Plaintext connection, two clients, different VLANs
+
+modprobe mac80211_hwsim radios=3
+
+hostapd hostapd.conf
+
+ifconfig wlan1 up
+iwconfig wlan1 essid "mac80211 test"
+
+ifconfig wlan2 up
+iwconfig wlan2 essid "mac80211 test"
+
+# Expected results:
+# STA1(wlan1) is bound to vlan1
+# STA2(wlan2) is bound to vlan2
diff --git a/mac80211_hwsim/tools/Makefile b/mac80211_hwsim/tools/Makefile
new file mode 100644 (file)
index 0000000..ec0d2dc
--- /dev/null
@@ -0,0 +1,11 @@
+all: hwsim_test
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef CFLAGS
+CFLAGS = -O2 -Wall -g
+endif
+
+hwsim_test: hwsim_test.o
diff --git a/mac80211_hwsim/tools/hwsim_test.c b/mac80211_hwsim/tools/hwsim_test.c
new file mode 100644 (file)
index 0000000..d17ed61
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <netpacket/packet.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+
+#define HWSIM_ETHERTYPE ETHERTYPE_IP
+#define HWSIM_PACKETLEN 1500
+
+static unsigned char addr1[ETH_ALEN], addr2[ETH_ALEN], bcast[ETH_ALEN];
+
+static void tx(int s, const char *ifname, int ifindex,
+              const unsigned char *src, const unsigned char *dst)
+{
+       char buf[HWSIM_PACKETLEN], *pos;
+       struct ether_header *eth;
+       int i;
+
+       printf("TX: %s(ifindex=%d) " MACSTR " -> " MACSTR "\n",
+              ifname, ifindex, MAC2STR(src), MAC2STR(dst));
+
+       eth = (struct ether_header *) buf;
+       memcpy(eth->ether_dhost, dst, ETH_ALEN);
+       memcpy(eth->ether_shost, src, ETH_ALEN);
+       eth->ether_type = htons(HWSIM_ETHERTYPE);
+       pos = (char *) (eth + 1);
+       for (i = 0; i < sizeof(buf) - sizeof(*eth); i++)
+               *pos++ = i;
+
+       if (send(s, buf, sizeof(buf), 0) < 0)
+               perror("send");
+}
+
+
+struct rx_result {
+       int rx_unicast1:1;
+       int rx_broadcast1:1;
+       int rx_unicast2:1;
+       int rx_broadcast2:1;
+};
+
+
+static void rx(int s, int iface, const char *ifname, int ifindex,
+              struct rx_result *res)
+{
+       char buf[HWSIM_PACKETLEN + 1], *pos;
+       struct ether_header *eth;
+       int len, i;
+
+       len = recv(s, buf, sizeof(buf), 0);
+       if (len < 0) {
+               perror("recv");
+               return;
+       }
+       eth = (struct ether_header *) buf;
+
+       printf("RX: %s(ifindex=%d) " MACSTR " -> " MACSTR " (len=%d)\n",
+              ifname, ifindex,
+              MAC2STR(eth->ether_shost), MAC2STR(eth->ether_dhost), len);
+
+       if (len != HWSIM_PACKETLEN) {
+               printf("Ignore frame with unexpected RX length\n");
+               return;
+       }
+
+       pos = (char *) (eth + 1);
+       for (i = 0; i < sizeof(buf) - 1 - sizeof(*eth); i++) {
+               if ((unsigned char) *pos != (unsigned char) i) {
+                       printf("Ignore frame with unexpected contents\n");
+                       printf("i=%d received=0x%x expected=0x%x\n",
+                              i, (unsigned char) *pos, (unsigned char) i);
+                       return;
+               }
+               pos++;
+       }
+
+       if (iface == 1 &&
+                  memcmp(eth->ether_dhost, addr1, ETH_ALEN) == 0 &&
+                  memcmp(eth->ether_shost, addr2, ETH_ALEN) == 0)
+               res->rx_unicast1 = 1;
+       else if (iface == 1 &&
+                  memcmp(eth->ether_dhost, bcast, ETH_ALEN) == 0 &&
+                  memcmp(eth->ether_shost, addr2, ETH_ALEN) == 0)
+               res->rx_broadcast1 = 1;
+       else if (iface == 2 &&
+                  memcmp(eth->ether_dhost, addr2, ETH_ALEN) == 0 &&
+                  memcmp(eth->ether_shost, addr1, ETH_ALEN) == 0)
+               res->rx_unicast2 = 1;
+       else if (iface == 2 &&
+                  memcmp(eth->ether_dhost, bcast, ETH_ALEN) == 0 &&
+                  memcmp(eth->ether_shost, addr1, ETH_ALEN) == 0)
+               res->rx_broadcast2 = 1;
+}
+
+
+int main(int argc, char *argv[])
+{
+       int s1 = -1, s2 = -1, ret = -1;
+       struct ifreq ifr;
+       int ifindex1, ifindex2;
+       struct sockaddr_ll ll;
+       fd_set rfds;
+       struct timeval tv;
+       struct rx_result res;
+
+       if (argc != 3) {
+               fprintf(stderr, "usage: hwsim_test <ifname1> <ifname2>\n");
+               return -1;
+       }
+
+       memset(bcast, 0xff, ETH_ALEN);
+
+       s1 = socket(PF_PACKET, SOCK_RAW, htons(HWSIM_ETHERTYPE));
+       if (s1 < 0) {
+               perror("socket");
+               goto fail;
+       }
+
+       s2 = socket(PF_PACKET, SOCK_RAW, htons(HWSIM_ETHERTYPE));
+       if (s2 < 0) {
+               perror("socket");
+               goto fail;
+       }
+
+       memset(&ifr, 0, sizeof(ifr));
+       strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name));
+       if (ioctl(s1, SIOCGIFINDEX, &ifr) < 0) {
+               perror("ioctl[SIOCGIFINDEX]");
+               goto fail;
+       }
+       ifindex1 = ifr.ifr_ifindex;
+       if (ioctl(s1, SIOCGIFHWADDR, &ifr) < 0) {
+               perror("ioctl[SIOCGIFHWADDR]");
+               goto fail;
+       }
+       memcpy(addr1, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+       memset(&ifr, 0, sizeof(ifr));
+       strncpy(ifr.ifr_name, argv[2], sizeof(ifr.ifr_name));
+       if (ioctl(s2, SIOCGIFINDEX, &ifr) < 0) {
+               perror("ioctl[SIOCGIFINDEX]");
+               goto fail;
+       }
+       ifindex2 = ifr.ifr_ifindex;
+       if (ioctl(s2, SIOCGIFHWADDR, &ifr) < 0) {
+               perror("ioctl[SIOCGIFHWADDR]");
+               goto fail;
+       }
+       memcpy(addr2, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+       memset(&ll, 0, sizeof(ll));
+       ll.sll_family = PF_PACKET;
+       ll.sll_ifindex = ifindex1;
+       ll.sll_protocol = htons(HWSIM_ETHERTYPE);
+       if (bind(s1, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+               perror("bind");
+               goto fail;
+       }
+
+       memset(&ll, 0, sizeof(ll));
+       ll.sll_family = PF_PACKET;
+       ll.sll_ifindex = ifindex2;
+       ll.sll_protocol = htons(HWSIM_ETHERTYPE);
+       if (bind(s2, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+               perror("bind");
+               goto fail;
+       }
+
+       tx(s1, argv[1], ifindex1, addr1, addr2);
+       tx(s1, argv[1], ifindex1, addr1, bcast);
+       tx(s2, argv[2], ifindex2, addr2, addr1);
+       tx(s2, argv[2], ifindex2, addr2, bcast);
+
+       tv.tv_sec = 1;
+       tv.tv_usec = 0;
+
+       memset(&res, 0, sizeof(res));
+       for (;;) {
+               int r;
+               FD_ZERO(&rfds);
+               FD_SET(s1, &rfds);
+               FD_SET(s2, &rfds);
+
+               r = select(s2 + 1, &rfds, NULL, NULL, &tv);
+               if (r < 0) {
+                       perror("select");
+                       goto fail;
+               }
+
+               if (r == 0)
+                       break; /* timeout */
+
+               if (FD_ISSET(s1, &rfds))
+                       rx(s1, 1, argv[1], ifindex1, &res);
+               if (FD_ISSET(s2, &rfds))
+                       rx(s2, 2, argv[2], ifindex2, &res);
+
+               if (res.rx_unicast1 && res.rx_broadcast1 &&
+                   res.rx_unicast2 && res.rx_broadcast2) {
+                       ret = 0;
+                       break;
+               }
+       }
+
+       if (ret) {
+               printf("Did not receive all expected frames:\n"
+                      "rx_unicast1=%d rx_broadcast1=%d "
+                      "rx_unicast2=%d rx_broadcast2=%d\n",
+                      res.rx_unicast1, res.rx_broadcast1,
+                      res.rx_unicast2, res.rx_broadcast2);
+       } else {
+               printf("Both unicast and broadcast working in both "
+                      "directions\n");
+       }
+
+fail:
+       close(s1);
+       close(s2);
+
+       return ret;
+}
diff --git a/packaging/wpasupplicant.spec b/packaging/wpasupplicant.spec
new file mode 100644 (file)
index 0000000..6287b76
--- /dev/null
@@ -0,0 +1,79 @@
+#sbs-git:pkgs/w/wpasupplicant
+
+Name:      wpasupplicant
+Summary:    Support for WPA and WPA2 (IEEE 802.11i / RSN)
+Version:    0.8.0
+Release:    7
+Group:      System/Network
+License:    BSD license
+Source0:    %{name}-%{version}.tar.gz
+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+BuildRequires: pkgconfig(openssl)
+BuildRequires: pkgconfig(libssl)
+BuildRequires: pkgconfig(libcrypto)
+BuildRequires: pkgconfig(dbus-1)
+BuildRequires: pkgconfig(libnl-2.0)
+
+%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
+#CFLAGS="%{optflags} -fPIC"; export CFLAGS
+cp -v configurations/tizen.config wpa_supplicant/.config
+cd wpa_supplicant
+make %{?jobs:-j%jobs} all
+
+#cp -v configurations/tizen_hostapd.config hostapd/.config
+
+%install
+rm -rf %{buildroot}
+mkdir -p %{buildroot}%{_sbindir}/systemd/
+mkdir -p %{buildroot}%{_sbindir}/dbus/
+cd wpa_supplicant
+%make_install
+
+# D-Bus
+mkdir -p %{buildroot}/usr/etc/dbus-1/system.d/
+cp dbus/dbus-wpa_supplicant.conf %{buildroot}/usr/etc/dbus-1/system.d/wpa_supplicant.conf
+mkdir -p %{buildroot}/usr/share/dbus-1/services/
+cp dbus/fi.epitest.hostap.WPASupplicant.service %{buildroot}/usr/share/dbus-1/services/
+cp dbus/fi.w1.wpa_supplicant1.service %{buildroot}/usr/share/dbus-1/services/
+
+mkdir -p %{buildroot}/etc/rc.d/init.d
+cp ../etc/rc.d/init.d/wpa_supplicant %{buildroot}/etc/rc.d/init.d/wpa_supplicant
+mkdir -p %{buildroot}/etc/rc.d/rc3.d/
+ln -s ../init.d/wpa_supplicant %{buildroot}/etc/rc.d/rc3.d/S62wpasupplicant
+mkdir -p %{buildroot}/etc/rc.d/rc5.d/
+ln -s ../init.d/wpa_supplicant %{buildroot}/etc/rc.d/rc5.d/S62wpasupplicant
+
+# sanitise the example configuration
+mkdir -p %{buildroot}/usr/share/doc/wpasupplicant
+sed 's/^\([^#]\+=.*\|}\)/#\1/' < ./wpa_supplicant.conf | gzip > %{buildroot}/usr/share/doc/wpasupplicant/README.wpa_supplicant.conf.gz
+
+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
+%defattr(-,root,root,-)
+%{_sbindir}/wpa_cli
+%{_sbindir}/wpa_supplicant
+%attr(644,-,-) /usr/etc/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
diff --git a/radius_example/Makefile b/radius_example/Makefile
new file mode 100644 (file)
index 0000000..92e992c
--- /dev/null
@@ -0,0 +1,45 @@
+ALL=radius_example
+
+all: $(ALL)
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+CFLAGS += -I.
+CFLAGS += -I../src
+CFLAGS += -I../src/utils
+
+LIBS = ../src/radius/libradius.a
+LIBS += ../src/crypto/libcrypto.a
+LIBS += ../src/utils/libutils.a
+
+../src/utils/libutils.a:
+       $(MAKE) -C ../src/utils
+
+../src/crypto/libcrypto.a:
+       $(MAKE) -C ../src/crypto
+
+../src/radius/libradius.a:
+       $(MAKE) -C ../src/radius
+
+#CLAGS += -DCONFIG_IPV6
+
+OBJS_ex = radius_example.o
+
+radius_example: $(OBJS_ex) $(LIBS)
+       $(LDO) $(LDFLAGS) -o radius_example $(OBJS_ex) $(LIBS)
+
+clean:
+       $(MAKE) -C ../src clean
+       rm -f core *~ *.o *.d $(ALL)
+
+-include $(OBJS:%.o=%.d)
diff --git a/radius_example/README b/radius_example/README
new file mode 100644 (file)
index 0000000..7669fa3
--- /dev/null
@@ -0,0 +1,39 @@
+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 directory contains an example showing how the RADIUS client
+functionality from hostapd can be used as a library in another
+program. The example program initializes the RADIUS client and send a
+Access-Request using User-Name and User-Password attributes. A reply
+from the RADIUS authentication server will be processed and it is used
+as a trigger to terminate the example program.
+
+The RADIUS library links in couple of helper functions from src/utils and
+src/crypto directories. Most of these are suitable as-is, but it may
+be desirable to replace the debug output code in src/utils/wpa_debug.c
+by dropping this file from the library and re-implementing the
+functions there in a way that better fits in with the main
+application.
+
+RADIUS client implementation takes care of receiving messages,
+timeouts, and retransmissions of packets. Consequently, it requires
+functionality for registering timeouts and received packet
+notifications. This is implemented using the generic event loop
+implementation (see src/utils/eloop.h).
+
+The main application may either use the included event loop
+implementation or alternatively, implement eloop_* wrapper functions
+to use whatever event loop design is used in the main program. This
+would involve removing src/utils/eloop.o from the library and
+implementing following functions defines in src/utils/eloop.h:
+eloop_register_timeout(), eloop_cancel_timeout(),
+eloop_register_read_sock(), eloop_unregister_read_sock(), and
+eloop_terminated().
diff --git a/radius_example/radius_example.c b/radius_example/radius_example.c
new file mode 100644 (file)
index 0000000..fd7dbae
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "radius/radius.h"
+#include "radius/radius_client.h"
+
+extern int wpa_debug_level;
+
+struct radius_ctx {
+       struct radius_client_data *radius;
+       struct hostapd_radius_servers conf;
+       u8 radius_identifier;
+       struct in_addr own_ip_addr;
+};
+
+
+static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
+                             int level, const char *txt, size_t len)
+{
+       printf("%s\n", txt);
+}
+
+
+/* Process the RADIUS frames from Authentication Server */
+static RadiusRxResult receive_auth(struct radius_msg *msg,
+                                  struct radius_msg *req,
+                                  const u8 *shared_secret,
+                                  size_t shared_secret_len,
+                                  void *data)
+{
+       /* struct radius_ctx *ctx = data; */
+       printf("Received RADIUS Authentication message; code=%d\n",
+              radius_msg_get_hdr(msg)->code);
+
+       /* We're done for this example, so request eloop to terminate. */
+       eloop_terminate();
+
+       return RADIUS_RX_PROCESSED;
+}
+
+
+static void start_example(void *eloop_ctx, void *timeout_ctx)
+{
+       struct radius_ctx *ctx = eloop_ctx;
+       struct radius_msg *msg;
+
+       printf("Sending a RADIUS authentication message\n");
+
+       ctx->radius_identifier = radius_client_get_id(ctx->radius);
+       msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
+                            ctx->radius_identifier);
+       if (msg == NULL) {
+               printf("Could not create net RADIUS packet\n");
+               return;
+       }
+
+       radius_msg_make_authenticator(msg, (u8 *) ctx, sizeof(*ctx));
+
+       if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
+                                (u8 *) "user", 4)) {
+               printf("Could not add User-Name\n");
+               radius_msg_free(msg);
+               return;
+       }
+
+       if (!radius_msg_add_attr_user_password(
+                   msg, (u8 *) "password", 8,
+                   ctx->conf.auth_server->shared_secret,
+                   ctx->conf.auth_server->shared_secret_len)) {
+               printf("Could not add User-Password\n");
+               radius_msg_free(msg);
+               return;
+       }
+
+       if (!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
+                                (u8 *) &ctx->own_ip_addr, 4)) {
+               printf("Could not add NAS-IP-Address\n");
+               radius_msg_free(msg);
+               return;
+       }
+
+       radius_client_send(ctx->radius, msg, RADIUS_AUTH, NULL);
+}
+
+
+int main(int argc, char *argv[])
+{
+       struct radius_ctx ctx;
+       struct hostapd_radius_server *srv;
+
+       if (os_program_init())
+               return -1;
+
+       hostapd_logger_register_cb(hostapd_logger_cb);
+
+       os_memset(&ctx, 0, sizeof(ctx));
+       inet_aton("127.0.0.1", &ctx.own_ip_addr);
+
+       if (eloop_init()) {
+               printf("Failed to initialize event loop\n");
+               return -1;
+       }
+
+       srv = os_zalloc(sizeof(*srv));
+       if (srv == NULL)
+               return -1;
+
+       srv->addr.af = AF_INET;
+       srv->port = 1812;
+       if (hostapd_parse_ip_addr("127.0.0.1", &srv->addr) < 0) {
+               printf("Failed to parse IP address\n");
+               return -1;
+       }
+       srv->shared_secret = (u8 *) os_strdup("radius");
+       srv->shared_secret_len = 6;
+
+       ctx.conf.auth_server = ctx.conf.auth_servers = srv;
+       ctx.conf.num_auth_servers = 1;
+       ctx.conf.msg_dumps = 1;
+
+       ctx.radius = radius_client_init(&ctx, &ctx.conf);
+       if (ctx.radius == NULL) {
+               printf("Failed to initialize RADIUS client\n");
+               return -1;
+       }
+
+       if (radius_client_register(ctx.radius, RADIUS_AUTH, receive_auth,
+                                  &ctx) < 0) {
+               printf("Failed to register RADIUS authentication handler\n");
+               return -1;
+       }
+
+       eloop_register_timeout(0, 0, start_example, &ctx, NULL);
+
+       eloop_run();
+
+       radius_client_deinit(ctx.radius);
+       os_free(srv->shared_secret);
+       os_free(srv);
+
+       eloop_destroy();
+       os_program_deinit();
+
+       return 0;
+}
index f47da7b..d73a175 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet radius rsn_supp tls utils wps
+SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p radius rsn_supp tls utils wps
 
 all:
        for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done
index 7939c68..03421b3 100644 (file)
@@ -23,6 +23,7 @@
 #include "ieee802_1x.h"
 #include "ap_config.h"
 #include "sta_info.h"
+#include "ap_drv_ops.h"
 #include "accounting.h"
 
 
@@ -186,7 +187,7 @@ static int accounting_sta_update_stats(struct hostapd_data *hapd,
                                       struct sta_info *sta,
                                       struct hostap_sta_driver_data *data)
 {
-       if (hapd->drv.read_sta_data(hapd, data, sta->addr))
+       if (hostapd_drv_read_sta_data(hapd, data, sta->addr))
                return -1;
 
        if (sta->last_rx_bytes > data->rx_bytes)
@@ -235,6 +236,7 @@ static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
 void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
 {
        struct radius_msg *msg;
+       struct os_time t;
        int interval;
 
        if (sta->acct_session_started)
@@ -246,10 +248,11 @@ void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
                       "starting accounting session %08X-%08X",
                       sta->acct_session_id_hi, sta->acct_session_id_lo);
 
-       time(&sta->acct_session_start);
+       os_get_time(&t);
+       sta->acct_session_start = t.sec;
        sta->last_rx_bytes = sta->last_tx_bytes = 0;
        sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
-       hapd->drv.sta_clear_stats(hapd, sta->addr);
+       hostapd_drv_sta_clear_stats(hapd, sta->addr);
 
        if (!hapd->conf->radius->acct_server)
                return;
@@ -275,6 +278,7 @@ static void accounting_sta_report(struct hostapd_data *hapd,
        struct radius_msg *msg;
        int cause = sta->acct_terminate_cause;
        struct hostap_sta_driver_data data;
+       struct os_time now;
        u32 gigawords;
 
        if (!hapd->conf->radius->acct_server)
@@ -288,8 +292,9 @@ static void accounting_sta_report(struct hostapd_data *hapd,
                return;
        }
 
+       os_get_time(&now);
        if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
-                                      time(NULL) - sta->acct_session_start)) {
+                                      now.sec - sta->acct_session_start)) {
                printf("Could not add Acct-Session-Time\n");
                goto fail;
        }
@@ -344,7 +349,7 @@ static void accounting_sta_report(struct hostapd_data *hapd,
        }
 
        if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
-                                      time(NULL))) {
+                                      now.sec)) {
                printf("Could not add Event-Timestamp\n");
                goto fail;
        }
@@ -475,9 +480,12 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
  */
 int accounting_init(struct hostapd_data *hapd)
 {
+       struct os_time now;
+
        /* Acct-Session-Id should be unique over reboots. If reliable clock is
         * not available, this could be replaced with reboot counter, etc. */
-       hapd->acct_session_id_hi = time(NULL);
+       os_get_time(&now);
+       hapd->acct_session_id_hi = now.sec;
 
        if (radius_client_register(hapd->radius, RADIUS_ACCT,
                                   accounting_receive, hapd))
index 5996993..b24cd90 100644 (file)
@@ -74,6 +74,8 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
 
        bss->max_listen_interval = 65535;
 
+       bss->pwd_group = 19; /* ECC: GF(p=256) */
+
 #ifdef CONFIG_IEEE80211W
        bss->assoc_sa_query_max_timeout = 1000;
        bss->assoc_sa_query_retry_timeout = 201;
@@ -84,14 +86,22 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
        bss->pac_key_lifetime = 7 * 24 * 60 * 60;
        bss->pac_key_refresh_time = 1 * 24 * 60 * 60;
 #endif /* EAP_SERVER_FAST */
+
+       /* Set to -1 as defaults depends on HT in setup */
+       bss->wmm_enabled = -1;
+
+#ifdef CONFIG_IEEE80211R
+       bss->ft_over_ds = 1;
+#endif /* CONFIG_IEEE80211R */
 }
 
 
 struct hostapd_config * hostapd_config_defaults(void)
 {
+#define ecw2cw(ecw) ((1 << (ecw)) - 1)
+
        struct hostapd_config *conf;
        struct hostapd_bss_config *bss;
-       int i;
        const int aCWmin = 4, aCWmax = 10;
        const struct hostapd_wmm_ac_params ac_bk =
                { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
@@ -101,6 +111,17 @@ struct hostapd_config * hostapd_config_defaults(void)
                { aCWmin - 1, aCWmin, 2, 3000 / 32, 1 };
        const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
                { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 1 };
+       const struct hostapd_tx_queue_params txq_bk =
+               { 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 };
+       const struct hostapd_tx_queue_params txq_be =
+               { 3, ecw2cw(aCWmin), 4 * (ecw2cw(aCWmin) + 1) - 1, 0};
+       const struct hostapd_tx_queue_params txq_vi =
+               { 1, (ecw2cw(aCWmin) + 1) / 2 - 1, ecw2cw(aCWmin), 30};
+       const struct hostapd_tx_queue_params txq_vo =
+               { 1, (ecw2cw(aCWmin) + 1) / 4 - 1,
+                 (ecw2cw(aCWmin) + 1) / 2 - 1, 15};
+
+#undef ecw2cw
 
        conf = os_zalloc(sizeof(*conf));
        bss = os_zalloc(sizeof(*bss));
@@ -129,14 +150,16 @@ struct hostapd_config * hostapd_config_defaults(void)
        conf->fragm_threshold = -1; /* user driver default: 2346 */
        conf->send_probe_response = 1;
 
-       for (i = 0; i < NUM_TX_QUEUES; i++)
-               conf->tx_queue[i].aifs = -1; /* use hw default */
-
        conf->wmm_ac_params[0] = ac_be;
        conf->wmm_ac_params[1] = ac_bk;
        conf->wmm_ac_params[2] = ac_vi;
        conf->wmm_ac_params[3] = ac_vo;
 
+       conf->tx_queue[0] = txq_vo;
+       conf->tx_queue[1] = txq_vi;
+       conf->tx_queue[2] = txq_be;
+       conf->tx_queue[3] = txq_bk;
+
        conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED;
 
        return conf;
@@ -403,6 +426,8 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
                ssid->dyn_vlan_keys = NULL;
        }
 
+       os_free(conf->time_zone);
+
 #ifdef CONFIG_IEEE80211R
        {
                struct ft_remote_r0kh *r0kh, *r0kh_prev;
@@ -433,7 +458,6 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
        os_free(conf->model_name);
        os_free(conf->model_number);
        os_free(conf->serial_number);
-       os_free(conf->device_type);
        os_free(conf->config_methods);
        os_free(conf->ap_pin);
        os_free(conf->extra_cred);
@@ -445,6 +469,12 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
        os_free(conf->model_url);
        os_free(conf->upc);
 #endif /* CONFIG_WPS */
+
+       os_free(conf->roaming_consortium);
+
+#ifdef CONFIG_RADIUS_TEST
+       os_free(conf->dump_msk_file);
+#endif /* CONFIG_RADIUS_TEST */
 }
 
 
index f509b5b..cc7122c 100644 (file)
@@ -18,6 +18,7 @@
 #include "common/defs.h"
 #include "ip_addr.h"
 #include "common/wpa_common.h"
+#include "wps/wps.h"
 
 #define MAX_STA_COUNT 2007
 #define MAX_VLAN_ID 4094
@@ -103,7 +104,6 @@ struct hostapd_wpa_psk {
        u8 addr[ETH_ALEN];
 };
 
-#define EAP_USER_MAX_METHODS 8
 struct hostapd_eap_user {
        struct hostapd_eap_user *next;
        u8 *identity;
@@ -111,7 +111,7 @@ struct hostapd_eap_user {
        struct {
                int vendor;
                u32 method;
-       } methods[EAP_USER_MAX_METHODS];
+       } methods[EAP_MAX_METHODS];
        u8 *password;
        size_t password_len;
        int phase2;
@@ -123,14 +123,13 @@ struct hostapd_eap_user {
 };
 
 
-#define NUM_TX_QUEUES 8
+#define NUM_TX_QUEUES 4
 
 struct hostapd_tx_queue_params {
        int aifs;
        int cwmin;
        int cwmax;
        int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
-       int configured;
 };
 
 struct hostapd_wmm_ac_params {
@@ -142,12 +141,20 @@ struct hostapd_wmm_ac_params {
 };
 
 
+#define MAX_ROAMING_CONSORTIUM_LEN 15
+
+struct hostapd_roaming_consortium {
+       u8 len;
+       u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
+};
+
 /**
  * struct hostapd_bss_config - Per-BSS configuration
  */
 struct hostapd_bss_config {
        char iface[IFNAMSIZ + 1];
        char bridge[IFNAMSIZ + 1];
+       char wds_bridge[IFNAMSIZ + 1];
 
        enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
 
@@ -198,6 +205,7 @@ struct hostapd_bss_config {
        struct mac_acl_entry *deny_mac;
        int num_deny_mac;
        int wds_sta;
+       int isolate;
 
        int auth_algs; /* bitfield of allowed IEEE 802.11 authentication
                        * algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
@@ -211,6 +219,11 @@ struct hostapd_bss_config {
        /* dot11AssociationSAQueryRetryTimeout (in TUs) */
        int assoc_sa_query_retry_timeout;
 #endif /* CONFIG_IEEE80211W */
+       enum {
+               PSK_RADIUS_IGNORED = 0,
+               PSK_RADIUS_ACCEPTED = 1,
+               PSK_RADIUS_REQUIRED = 2
+       } wpa_psk_radius;
        int wpa_pairwise;
        int wpa_group;
        int wpa_group_rekey;
@@ -231,6 +244,7 @@ struct hostapd_bss_config {
        struct ft_remote_r0kh *r0kh_list;
        struct ft_remote_r1kh *r1kh_list;
        int pmk_r1_push;
+       int ft_over_ds;
 #endif /* CONFIG_IEEE80211R */
 
        char *ctrl_interface; /* directory for UNIX domain sockets */
@@ -254,6 +268,8 @@ struct hostapd_bss_config {
        int pac_key_refresh_time;
        int eap_sim_aka_result_ind;
        int tnc;
+       int fragment_size;
+       u16 pwd_group;
 
        char *radius_server_clients;
        int radius_server_auth_port;
@@ -283,6 +299,7 @@ struct hostapd_bss_config {
         */
        u16 max_listen_interval;
 
+       int disable_pmksa_caching;
        int okc; /* Opportunistic Key Caching */
 
        int wps_state;
@@ -295,7 +312,7 @@ struct hostapd_bss_config {
        char *model_name;
        char *model_number;
        char *serial_number;
-       char *device_type;
+       u8 device_type[WPS_DEV_TYPE_LEN];
        char *config_methods;
        u8 os_version[4];
        char *ap_pin;
@@ -311,7 +328,49 @@ struct hostapd_bss_config {
        char *model_description;
        char *model_url;
        char *upc;
+       struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
 #endif /* CONFIG_WPS */
+       int pbc_in_m1;
+
+#define P2P_ENABLED BIT(0)
+#define P2P_GROUP_OWNER BIT(1)
+#define P2P_GROUP_FORMATION BIT(2)
+#define P2P_MANAGE BIT(3)
+#define P2P_ALLOW_CROSS_CONNECTION BIT(4)
+       int p2p;
+
+       int disassoc_low_ack;
+
+#define TDLS_PROHIBIT BIT(0)
+#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
+       int tdls;
+       int disable_11n;
+
+       /* IEEE 802.11v */
+       int time_advertisement;
+       char *time_zone;
+
+       /* IEEE 802.11u - Interworking */
+       int interworking;
+       int access_network_type;
+       int internet;
+       int asra;
+       int esr;
+       int uesa;
+       int venue_info_set;
+       u8 venue_group;
+       u8 venue_type;
+       u8 hessid[ETH_ALEN];
+
+       /* IEEE 802.11u - Roaming Consortium list */
+       unsigned int roaming_consortium_count;
+       struct hostapd_roaming_consortium *roaming_consortium;
+
+       u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
+
+#ifdef CONFIG_RADIUS_TEST
+       char *dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
 };
 
 
@@ -332,12 +391,6 @@ struct hostapd_config {
                LONG_PREAMBLE = 0,
                SHORT_PREAMBLE = 1
        } preamble;
-       enum {
-               CTS_PROTECTION_AUTOMATIC = 0,
-               CTS_PROTECTION_FORCE_ENABLED = 1,
-               CTS_PROTECTION_FORCE_DISABLED = 2,
-               CTS_PROTECTION_AUTOMATIC_NO_OLBC = 3,
-       } cts_protection_type;
 
        int *supported_rates;
        int *basic_rates;
@@ -371,6 +424,7 @@ struct hostapd_config {
        u16 ht_capab;
        int ieee80211n;
        int secondary_channel;
+       int require_ht;
 };
 
 
index f264a3e..429c187 100644 (file)
 #include "utils/common.h"
 #include "drivers/driver.h"
 #include "common/ieee802_11_defs.h"
+#include "wps/wps.h"
 #include "hostapd.h"
 #include "ieee802_11.h"
 #include "sta_info.h"
 #include "ap_config.h"
+#include "p2p_hostapd.h"
 #include "ap_drv_ops.h"
 
 
-static int hostapd_sta_flags_to_drv(int flags)
+u32 hostapd_sta_flags_to_drv(u32 flags)
 {
        int res = 0;
        if (flags & WLAN_STA_AUTHORIZED)
@@ -39,45 +41,166 @@ static int hostapd_sta_flags_to_drv(int flags)
 }
 
 
-static int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
+int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
+                              struct wpabuf **beacon_ret,
+                              struct wpabuf **proberesp_ret,
+                              struct wpabuf **assocresp_ret)
 {
-       struct wpabuf *beacon, *proberesp;
-       int ret;
+       struct wpabuf *beacon = NULL, *proberesp = NULL, *assocresp = NULL;
+       u8 buf[200], *pos;
 
-       if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
-               return 0;
+       *beacon_ret = *proberesp_ret = *assocresp_ret = NULL;
 
-       beacon = hapd->wps_beacon_ie;
-       proberesp = hapd->wps_probe_resp_ie;
+       pos = buf;
+       pos = hostapd_eid_time_adv(hapd, pos);
+       if (pos != buf) {
+               if (wpabuf_resize(&beacon, pos - buf) != 0)
+                       goto fail;
+               wpabuf_put_data(beacon, buf, pos - buf);
+       }
+       pos = hostapd_eid_time_zone(hapd, pos);
+       if (pos != buf) {
+               if (wpabuf_resize(&proberesp, pos - buf) != 0)
+                       goto fail;
+               wpabuf_put_data(proberesp, buf, pos - buf);
+       }
 
-       ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp);
+       pos = buf;
+       pos = hostapd_eid_ext_capab(hapd, pos);
+       if (pos != buf) {
+               if (wpabuf_resize(&assocresp, pos - buf) != 0)
+                       goto fail;
+               wpabuf_put_data(assocresp, buf, pos - buf);
+       }
+       pos = hostapd_eid_interworking(hapd, pos);
+       pos = hostapd_eid_adv_proto(hapd, pos);
+       pos = hostapd_eid_roaming_consortium(hapd, pos);
+       if (pos != buf) {
+               if (wpabuf_resize(&beacon, pos - buf) != 0)
+                       goto fail;
+               wpabuf_put_data(beacon, buf, pos - buf);
+
+               if (wpabuf_resize(&proberesp, pos - buf) != 0)
+                       goto fail;
+               wpabuf_put_data(proberesp, buf, pos - buf);
+       }
 
-       return ret;
+       if (hapd->wps_beacon_ie) {
+               if (wpabuf_resize(&beacon, wpabuf_len(hapd->wps_beacon_ie)) <
+                   0)
+                       goto fail;
+               wpabuf_put_buf(beacon, hapd->wps_beacon_ie);
+       }
+
+       if (hapd->wps_probe_resp_ie) {
+               if (wpabuf_resize(&proberesp,
+                                 wpabuf_len(hapd->wps_probe_resp_ie)) < 0)
+                       goto fail;
+               wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie);
+       }
+
+#ifdef CONFIG_P2P
+       if (hapd->p2p_beacon_ie) {
+               if (wpabuf_resize(&beacon, wpabuf_len(hapd->p2p_beacon_ie)) <
+                   0)
+                       goto fail;
+               wpabuf_put_buf(beacon, hapd->p2p_beacon_ie);
+       }
+
+       if (hapd->p2p_probe_resp_ie) {
+               if (wpabuf_resize(&proberesp,
+                                 wpabuf_len(hapd->p2p_probe_resp_ie)) < 0)
+                       goto fail;
+               wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie);
+       }
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_P2P_MANAGER
+       if (hapd->conf->p2p & P2P_MANAGE) {
+               if (wpabuf_resize(&beacon, 100) == 0) {
+                       u8 *start, *p;
+                       start = wpabuf_put(beacon, 0);
+                       p = hostapd_eid_p2p_manage(hapd, start);
+                       wpabuf_put(beacon, p - start);
+               }
+
+               if (wpabuf_resize(&proberesp, 100) == 0) {
+                       u8 *start, *p;
+                       start = wpabuf_put(proberesp, 0);
+                       p = hostapd_eid_p2p_manage(hapd, start);
+                       wpabuf_put(proberesp, p - start);
+               }
+       }
+#endif /* CONFIG_P2P_MANAGER */
+
+#ifdef CONFIG_WPS2
+       if (hapd->conf->wps_state) {
+               struct wpabuf *a = wps_build_assoc_resp_ie();
+               if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
+                       wpabuf_put_buf(assocresp, a);
+               wpabuf_free(a);
+       }
+#endif /* CONFIG_WPS2 */
+
+#ifdef CONFIG_P2P_MANAGER
+       if (hapd->conf->p2p & P2P_MANAGE) {
+               if (wpabuf_resize(&assocresp, 100) == 0) {
+                       u8 *start, *p;
+                       start = wpabuf_put(assocresp, 0);
+                       p = hostapd_eid_p2p_manage(hapd, start);
+                       wpabuf_put(assocresp, p - start);
+               }
+       }
+#endif /* CONFIG_P2P_MANAGER */
+
+       *beacon_ret = beacon;
+       *proberesp_ret = proberesp;
+       *assocresp_ret = assocresp;
+
+       return 0;
+
+fail:
+       wpabuf_free(beacon);
+       wpabuf_free(proberesp);
+       wpabuf_free(assocresp);
+       return -1;
 }
 
 
-static int hostapd_send_mgmt_frame(struct hostapd_data *hapd, const void *msg,
-                          size_t len)
+void hostapd_free_ap_extra_ies(struct hostapd_data *hapd,
+                              struct wpabuf *beacon,
+                              struct wpabuf *proberesp,
+                              struct wpabuf *assocresp)
 {
-       if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
-               return 0;
-       return hapd->driver->send_mlme(hapd->drv_priv, msg, len);
+       wpabuf_free(beacon);
+       wpabuf_free(proberesp);
+       wpabuf_free(assocresp);
 }
 
 
-static int hostapd_send_eapol(struct hostapd_data *hapd, const u8 *addr,
-                             const u8 *data, size_t data_len, int encrypt)
+int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
 {
-       if (hapd->driver == NULL || hapd->driver->hapd_send_eapol == NULL)
+       struct wpabuf *beacon, *proberesp, *assocresp;
+       int ret;
+
+       if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
                return 0;
-       return hapd->driver->hapd_send_eapol(hapd->drv_priv, addr, data,
-                                            data_len, encrypt,
-                                            hapd->own_addr);
+
+       if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) <
+           0)
+               return -1;
+
+       ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp,
+                                         assocresp);
+
+       hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
+
+       return ret;
 }
 
 
-static int hostapd_set_authorized(struct hostapd_data *hapd,
-                                 struct sta_info *sta, int authorized)
+int hostapd_set_authorized(struct hostapd_data *hapd,
+                          struct sta_info *sta, int authorized)
 {
        if (authorized) {
                return hostapd_sta_set_flags(hapd, sta->addr,
@@ -92,39 +215,7 @@ static int hostapd_set_authorized(struct hostapd_data *hapd,
 }
 
 
-static int hostapd_set_key(const char *ifname, struct hostapd_data *hapd,
-                          enum wpa_alg alg, const u8 *addr, int key_idx,
-                          int set_tx, const u8 *seq, size_t seq_len,
-                          const u8 *key, size_t key_len)
-{
-       if (hapd->driver == NULL || hapd->driver->set_key == NULL)
-               return 0;
-       return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr,
-                                    key_idx, set_tx, seq, seq_len, key,
-                                    key_len);
-}
-
-
-static int hostapd_read_sta_data(struct hostapd_data *hapd,
-                                struct hostap_sta_driver_data *data,
-                                const u8 *addr)
-{
-       if (hapd->driver == NULL || hapd->driver->read_sta_data == NULL)
-               return -1;
-       return hapd->driver->read_sta_data(hapd->drv_priv, data, addr);
-}
-
-
-static int hostapd_sta_clear_stats(struct hostapd_data *hapd, const u8 *addr)
-{
-       if (hapd->driver == NULL || hapd->driver->sta_clear_stats == NULL)
-               return 0;
-       return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
-}
-
-
-static int hostapd_set_sta_flags(struct hostapd_data *hapd,
-                                struct sta_info *sta)
+int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta)
 {
        int set_flags, total_flags, flags_and, flags_or;
        total_flags = hostapd_sta_flags_to_drv(sta->flags);
@@ -140,8 +231,8 @@ static int hostapd_set_sta_flags(struct hostapd_data *hapd,
 }
 
 
-static int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd,
-                                    const char *ifname, int enabled)
+int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
+                             int enabled)
 {
        struct wpa_bss_params params;
        os_memset(&params, 0, sizeof(params));
@@ -154,166 +245,80 @@ static int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd,
                params.wpa_pairwise = hapd->conf->wpa_pairwise;
                params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
                params.rsn_preauth = hapd->conf->rsn_preauth;
+#ifdef CONFIG_IEEE80211W
+               params.ieee80211w = hapd->conf->ieee80211w;
+#endif /* CONFIG_IEEE80211W */
        }
        return hostapd_set_ieee8021x(hapd, &params);
 }
 
 
-static int hostapd_set_radius_acl_auth(struct hostapd_data *hapd,
-                                      const u8 *mac, int accepted,
-                                      u32 session_timeout)
-{
-       if (hapd->driver == NULL || hapd->driver->set_radius_acl_auth == NULL)
-               return 0;
-       return hapd->driver->set_radius_acl_auth(hapd->drv_priv, mac, accepted,
-                                                session_timeout);
-}
-
-
-static int hostapd_set_radius_acl_expire(struct hostapd_data *hapd,
-                                        const u8 *mac)
-{
-       if (hapd->driver == NULL ||
-           hapd->driver->set_radius_acl_expire == NULL)
-               return 0;
-       return hapd->driver->set_radius_acl_expire(hapd->drv_priv, mac);
-}
-
-
-static int hostapd_set_bss_params(struct hostapd_data *hapd,
-                                 int use_protection)
-{
-       int ret = 0;
-       int preamble;
-#ifdef CONFIG_IEEE80211N
-       u8 buf[60], *ht_capab, *ht_oper, *pos;
-
-       pos = buf;
-       ht_capab = pos;
-       pos = hostapd_eid_ht_capabilities(hapd, pos);
-       ht_oper = pos;
-       pos = hostapd_eid_ht_operation(hapd, pos);
-       if (pos > ht_oper && ht_oper > ht_capab &&
-           hostapd_set_ht_params(hapd, ht_capab + 2, ht_capab[1],
-                                 ht_oper + 2, ht_oper[1])) {
-               wpa_printf(MSG_ERROR, "Could not set HT capabilities "
-                          "for kernel driver");
-               ret = -1;
-       }
-
-#endif /* CONFIG_IEEE80211N */
-
-       if (hostapd_set_cts_protect(hapd, use_protection)) {
-               wpa_printf(MSG_ERROR, "Failed to set CTS protect in kernel "
-                          "driver");
-               ret = -1;
-       }
-
-       if (hapd->iface->current_mode &&
-           hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
-           hostapd_set_short_slot_time(hapd,
-                                       hapd->iface->num_sta_no_short_slot_time
-                                       > 0 ? 0 : 1)) {
-               wpa_printf(MSG_ERROR, "Failed to set Short Slot Time option "
-                          "in kernel driver");
-               ret = -1;
-       }
-
-       if (hapd->iface->num_sta_no_short_preamble == 0 &&
-           hapd->iconf->preamble == SHORT_PREAMBLE)
-               preamble = SHORT_PREAMBLE;
-       else
-               preamble = LONG_PREAMBLE;
-       if (hostapd_set_preamble(hapd, preamble)) {
-               wpa_printf(MSG_ERROR, "Could not set preamble for kernel "
-                          "driver");
-               ret = -1;
-       }
-
-       return ret;
-}
-
-
-static int hostapd_set_beacon(struct hostapd_data *hapd,
-                             const u8 *head, size_t head_len,
-                             const u8 *tail, size_t tail_len, int dtim_period,
-                             int beacon_int)
-{
-       if (hapd->driver == NULL || hapd->driver->set_beacon == NULL)
-               return 0;
-       return hapd->driver->set_beacon(hapd->drv_priv,
-                                       head, head_len, tail, tail_len,
-                                       dtim_period, beacon_int);
-}
-
-
-static int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
+int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
 {
        char force_ifname[IFNAMSIZ];
        u8 if_addr[ETH_ALEN];
-       return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, NULL, NULL, NULL,
-                             force_ifname, if_addr);
+       return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr,
+                             NULL, NULL, force_ifname, if_addr, NULL);
 }
 
-static int hostapd_vlan_if_remove(struct hostapd_data *hapd,
-                                 const char *ifname)
+
+int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname)
 {
        return hostapd_if_remove(hapd, WPA_IF_AP_VLAN, ifname);
 }
 
 
-static int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr,
-                              int aid, int val)
+int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
+                       int val)
 {
-       if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL)
-               return 0;
-       return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val);
-}
-
+       const char *bridge = NULL;
 
-static int hostapd_set_sta_vlan(const char *ifname, struct hostapd_data *hapd,
-                               const u8 *addr, int vlan_id)
-{
-       if (hapd->driver == NULL || hapd->driver->set_sta_vlan == NULL)
+       if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL)
                return 0;
-       return hapd->driver->set_sta_vlan(hapd->drv_priv, addr, ifname,
-                                         vlan_id);
+       if (hapd->conf->wds_bridge[0])
+               bridge = hapd->conf->wds_bridge;
+       else if (hapd->conf->bridge[0])
+               bridge = hapd->conf->bridge;
+       return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val,
+                                        bridge);
 }
 
 
-static int hostapd_get_inact_sec(struct hostapd_data *hapd, const u8 *addr)
+int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
+                        u16 auth_alg)
 {
-       if (hapd->driver == NULL || hapd->driver->get_inact_sec == NULL)
+       if (hapd->driver == NULL || hapd->driver->add_sta_node == NULL)
                return 0;
-       return hapd->driver->get_inact_sec(hapd->drv_priv, addr);
+       return hapd->driver->add_sta_node(hapd->drv_priv, addr, auth_alg);
 }
 
 
-static int hostapd_sta_deauth(struct hostapd_data *hapd, const u8 *addr,
-                             int reason)
+int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
+                    u16 seq, u16 status, const u8 *ie, size_t len)
 {
-       if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
+       if (hapd->driver == NULL || hapd->driver->sta_auth == NULL)
                return 0;
-       return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr,
-                                       reason);
+       return hapd->driver->sta_auth(hapd->drv_priv, hapd->own_addr, addr,
+                                     seq, status, ie, len);
 }
 
 
-static int hostapd_sta_disassoc(struct hostapd_data *hapd, const u8 *addr,
-                               int reason)
+int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr,
+                     int reassoc, u16 status, const u8 *ie, size_t len)
 {
-       if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
+       if (hapd->driver == NULL || hapd->driver->sta_assoc == NULL)
                return 0;
-       return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
-                                         reason);
+       return hapd->driver->sta_assoc(hapd->drv_priv, hapd->own_addr, addr,
+                                      reassoc, status, ie, len);
 }
 
 
-static int hostapd_sta_add(struct hostapd_data *hapd,
-                          const u8 *addr, u16 aid, u16 capability,
-                          const u8 *supp_rates, size_t supp_rates_len,
-                          u16 listen_interval,
-                          const struct ieee80211_ht_capabilities *ht_capab)
+int hostapd_sta_add(struct hostapd_data *hapd,
+                   const u8 *addr, u16 aid, u16 capability,
+                   const u8 *supp_rates, size_t supp_rates_len,
+                   u16 listen_interval,
+                   const struct ieee80211_ht_capabilities *ht_capab,
+                   u32 flags, u8 qosinfo)
 {
        struct hostapd_sta_add_params params;
 
@@ -330,52 +335,19 @@ static 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.flags = hostapd_sta_flags_to_drv(flags);
+       params.qosinfo = qosinfo;
        return hapd->driver->sta_add(hapd->drv_priv, &params);
 }
 
 
-static int hostapd_sta_remove(struct hostapd_data *hapd, const u8 *addr)
+int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
+                     u8 *tspec_ie, size_t tspec_ielen)
 {
-       if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
+       if (hapd->driver == NULL || hapd->driver->add_tspec == NULL)
                return 0;
-       return hapd->driver->sta_remove(hapd->drv_priv, addr);
-}
-
-
-static int hostapd_set_countermeasures(struct hostapd_data *hapd, int enabled)
-{
-       if (hapd->driver == NULL ||
-           hapd->driver->hapd_set_countermeasures == NULL)
-               return 0;
-       return hapd->driver->hapd_set_countermeasures(hapd->drv_priv, enabled);
-}
-
-
-void hostapd_set_driver_ops(struct hostapd_driver_ops *ops)
-{
-       ops->set_ap_wps_ie = hostapd_set_ap_wps_ie;
-       ops->send_mgmt_frame = hostapd_send_mgmt_frame;
-       ops->send_eapol = hostapd_send_eapol;
-       ops->set_authorized = hostapd_set_authorized;
-       ops->set_key = hostapd_set_key;
-       ops->read_sta_data = hostapd_read_sta_data;
-       ops->sta_clear_stats = hostapd_sta_clear_stats;
-       ops->set_sta_flags = hostapd_set_sta_flags;
-       ops->set_drv_ieee8021x = hostapd_set_drv_ieee8021x;
-       ops->set_radius_acl_auth = hostapd_set_radius_acl_auth;
-       ops->set_radius_acl_expire = hostapd_set_radius_acl_expire;
-       ops->set_bss_params = hostapd_set_bss_params;
-       ops->set_beacon = hostapd_set_beacon;
-       ops->vlan_if_add = hostapd_vlan_if_add;
-       ops->vlan_if_remove = hostapd_vlan_if_remove;
-       ops->set_wds_sta = hostapd_set_wds_sta;
-       ops->set_sta_vlan = hostapd_set_sta_vlan;
-       ops->get_inact_sec = hostapd_get_inact_sec;
-       ops->sta_deauth = hostapd_sta_deauth;
-       ops->sta_disassoc = hostapd_sta_disassoc;
-       ops->sta_add = hostapd_sta_add;
-       ops->sta_remove = hostapd_sta_remove;
-       ops->set_countermeasures = hostapd_set_countermeasures;
+       return hapd->driver->add_tspec(hapd->drv_priv, addr, tspec_ie,
+                                      tspec_ielen);
 }
 
 
@@ -414,12 +386,14 @@ int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len)
 
 int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
                   const char *ifname, const u8 *addr, void *bss_ctx,
-                  void **drv_priv, char *force_ifname, u8 *if_addr)
+                  void **drv_priv, char *force_ifname, u8 *if_addr,
+                  const char *bridge)
 {
        if (hapd->driver == NULL || hapd->driver->if_add == NULL)
                return -1;
        return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
-                                   bss_ctx, drv_priv, force_ifname, if_addr);
+                                   bss_ctx, drv_priv, force_ifname, if_addr,
+                                   bridge);
 }
 
 
@@ -502,16 +476,6 @@ int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
 }
 
 
-int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
-                         int *basic_rates, int mode)
-{
-       if (hapd->driver == NULL || hapd->driver->set_rate_sets == NULL)
-               return 0;
-       return hapd->driver->set_rate_sets(hapd->drv_priv, supp_rates,
-                                          basic_rates, mode);
-}
-
-
 int hostapd_set_country(struct hostapd_data *hapd, const char *country)
 {
        if (hapd->driver == NULL ||
@@ -521,30 +485,6 @@ int hostapd_set_country(struct hostapd_data *hapd, const char *country)
 }
 
 
-int hostapd_set_cts_protect(struct hostapd_data *hapd, int value)
-{
-       if (hapd->driver == NULL || hapd->driver->set_cts_protect == NULL)
-               return 0;
-       return hapd->driver->set_cts_protect(hapd->drv_priv, value);
-}
-
-
-int hostapd_set_preamble(struct hostapd_data *hapd, int value)
-{
-       if (hapd->driver == NULL || hapd->driver->set_preamble == NULL)
-               return 0;
-       return hapd->driver->set_preamble(hapd->drv_priv, value);
-}
-
-
-int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value)
-{
-       if (hapd->driver == NULL || hapd->driver->set_short_slot_time == NULL)
-               return 0;
-       return hapd->driver->set_short_slot_time(hapd->drv_priv, value);
-}
-
-
 int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
                                int cw_min, int cw_max, int burst_time)
 {
@@ -555,15 +495,6 @@ int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
 }
 
 
-int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
-                          const u8 *mask)
-{
-       if (hapd->driver == NULL || hapd->driver->valid_bss_mask == NULL)
-               return 1;
-       return hapd->driver->valid_bss_mask(hapd->drv_priv, addr, mask);
-}
-
-
 struct hostapd_hw_modes *
 hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
                            u16 *flags)
@@ -584,19 +515,6 @@ int hostapd_driver_commit(struct hostapd_data *hapd)
 }
 
 
-int hostapd_set_ht_params(struct hostapd_data *hapd,
-                         const u8 *ht_capab, size_t ht_capab_len,
-                         const u8 *ht_oper, size_t ht_oper_len)
-{
-       if (hapd->driver == NULL || hapd->driver->set_ht_params == NULL ||
-           ht_capab == NULL || ht_oper == NULL)
-               return 0;
-       return hapd->driver->set_ht_params(hapd->drv_priv,
-                                          ht_capab, ht_capab_len,
-                                          ht_oper, ht_oper_len);
-}
-
-
 int hostapd_drv_none(struct hostapd_data *hapd)
 {
        return hapd->driver && os_strcmp(hapd->driver->name, "none") == 0;
@@ -619,3 +537,56 @@ struct wpa_scan_results * hostapd_driver_get_scan_results(
                return hapd->driver->get_scan_results2(hapd->drv_priv);
        return NULL;
 }
+
+
+int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
+                          int duration)
+{
+       if (hapd->driver && hapd->driver->set_noa)
+               return hapd->driver->set_noa(hapd->drv_priv, count, start,
+                                            duration);
+       return -1;
+}
+
+
+int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
+                       enum wpa_alg alg, const u8 *addr,
+                       int key_idx, int set_tx,
+                       const u8 *seq, size_t seq_len,
+                       const u8 *key, size_t key_len)
+{
+       if (hapd->driver == NULL || hapd->driver->set_key == NULL)
+               return 0;
+       return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr,
+                                    key_idx, set_tx, seq, seq_len, key,
+                                    key_len);
+}
+
+
+int hostapd_drv_send_mlme(struct hostapd_data *hapd,
+                         const void *msg, size_t len, int noack)
+{
+       if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
+               return 0;
+       return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack);
+}
+
+
+int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
+                          const u8 *addr, int reason)
+{
+       if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
+               return 0;
+       return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr,
+                                       reason);
+}
+
+
+int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
+                            const u8 *addr, int reason)
+{
+       if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
+               return 0;
+       return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
+                                         reason);
+}
index 9b75d09..835cdde 100644 (file)
 enum wpa_driver_if_type;
 struct wpa_bss_params;
 struct wpa_driver_scan_params;
+struct ieee80211_ht_capabilities;
 
-void hostapd_set_driver_ops(struct hostapd_driver_ops *ops);
+u32 hostapd_sta_flags_to_drv(u32 flags);
+int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
+                              struct wpabuf **beacon,
+                              struct wpabuf **proberesp,
+                              struct wpabuf **assocresp);
+void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon,
+                              struct wpabuf *proberesp,
+                              struct wpabuf *assocresp);
+int hostapd_set_ap_wps_ie(struct hostapd_data *hapd);
+int hostapd_set_authorized(struct hostapd_data *hapd,
+                          struct sta_info *sta, int authorized);
+int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta);
+int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
+                             int enabled);
+int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname);
+int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname);
+int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
+                       int val);
+int hostapd_sta_add(struct hostapd_data *hapd,
+                   const u8 *addr, u16 aid, u16 capability,
+                   const u8 *supp_rates, size_t supp_rates_len,
+                   u16 listen_interval,
+                   const struct ieee80211_ht_capabilities *ht_capab,
+                   u32 flags, u8 qosinfo);
 int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
 int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
                             size_t elem_len);
@@ -27,7 +51,8 @@ int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len);
 int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len);
 int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
                   const char *ifname, const u8 *addr, void *bss_ctx,
-                  void **drv_priv, char *force_ifname, u8 *if_addr);
+                  void **drv_priv, char *force_ifname, u8 *if_addr,
+                  const char *bridge);
 int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
                      const char *ifname);
 int hostapd_set_ieee8021x(struct hostapd_data *hapd,
@@ -41,27 +66,150 @@ int hostapd_set_rts(struct hostapd_data *hapd, int rts);
 int hostapd_set_frag(struct hostapd_data *hapd, int frag);
 int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
                          int total_flags, int flags_or, int flags_and);
-int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
-                         int *basic_rates, int mode);
 int hostapd_set_country(struct hostapd_data *hapd, const char *country);
-int hostapd_set_cts_protect(struct hostapd_data *hapd, int value);
-int hostapd_set_preamble(struct hostapd_data *hapd, int value);
-int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value);
 int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
                                int cw_min, int cw_max, int burst_time);
-int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
-                          const u8 *mask);
 struct hostapd_hw_modes *
 hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
                            u16 *flags);
 int hostapd_driver_commit(struct hostapd_data *hapd);
-int hostapd_set_ht_params(struct hostapd_data *hapd,
-                         const u8 *ht_capab, size_t ht_capab_len,
-                         const u8 *ht_oper, size_t ht_oper_len);
 int hostapd_drv_none(struct hostapd_data *hapd);
 int hostapd_driver_scan(struct hostapd_data *hapd,
                        struct wpa_driver_scan_params *params);
 struct wpa_scan_results * hostapd_driver_get_scan_results(
        struct hostapd_data *hapd);
+int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
+                          int duration);
+int hostapd_drv_set_key(const char *ifname,
+                       struct hostapd_data *hapd,
+                       enum wpa_alg alg, const u8 *addr,
+                       int key_idx, int set_tx,
+                       const u8 *seq, size_t seq_len,
+                       const u8 *key, size_t key_len);
+int hostapd_drv_send_mlme(struct hostapd_data *hapd,
+                         const void *msg, size_t len, int noack);
+int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
+                          const u8 *addr, int reason);
+int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
+                            const u8 *addr, int reason);
+int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
+                        u16 auth_alg);
+int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
+                    u16 seq, u16 status, const u8 *ie, size_t len);
+int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr,
+                     int reassoc, u16 status, const u8 *ie, size_t len);
+int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
+                     u8 *tspec_ie, size_t tspec_ielen);
+
+
+#include "drivers/driver.h"
+
+static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
+                                                 int enabled)
+{
+       if (hapd->driver == NULL ||
+           hapd->driver->hapd_set_countermeasures == NULL)
+               return 0;
+       return hapd->driver->hapd_set_countermeasures(hapd->drv_priv, enabled);
+}
+
+static inline int hostapd_drv_set_sta_vlan(const char *ifname,
+                                          struct hostapd_data *hapd,
+                                          const u8 *addr, int vlan_id)
+{
+       if (hapd->driver == NULL || hapd->driver->set_sta_vlan == NULL)
+               return 0;
+       return hapd->driver->set_sta_vlan(hapd->drv_priv, addr, ifname,
+                                         vlan_id);
+}
+
+static inline int hostapd_drv_get_inact_sec(struct hostapd_data *hapd,
+                                           const u8 *addr)
+{
+       if (hapd->driver == NULL || hapd->driver->get_inact_sec == NULL)
+               return 0;
+       return hapd->driver->get_inact_sec(hapd->drv_priv, addr);
+}
+
+static inline int hostapd_drv_sta_remove(struct hostapd_data *hapd,
+                                        const u8 *addr)
+{
+       if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
+               return 0;
+       return hapd->driver->sta_remove(hapd->drv_priv, addr);
+}
+
+static inline int hostapd_drv_hapd_send_eapol(struct hostapd_data *hapd,
+                                             const u8 *addr, const u8 *data,
+                                             size_t data_len, int encrypt,
+                                             u32 flags)
+{
+       if (hapd->driver == NULL || hapd->driver->hapd_send_eapol == NULL)
+               return 0;
+       return hapd->driver->hapd_send_eapol(hapd->drv_priv, addr, data,
+                                            data_len, encrypt,
+                                            hapd->own_addr, flags);
+}
+
+static inline int hostapd_drv_read_sta_data(
+       struct hostapd_data *hapd, struct hostap_sta_driver_data *data,
+       const u8 *addr)
+{
+       if (hapd->driver == NULL || hapd->driver->read_sta_data == NULL)
+               return -1;
+       return hapd->driver->read_sta_data(hapd->drv_priv, data, addr);
+}
+
+static inline int hostapd_drv_sta_clear_stats(struct hostapd_data *hapd,
+                                             const u8 *addr)
+{
+       if (hapd->driver == NULL || hapd->driver->sta_clear_stats == NULL)
+               return 0;
+       return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
+}
+
+static inline int hostapd_drv_set_ap(struct hostapd_data *hapd,
+                                    struct wpa_driver_ap_params *params)
+{
+       if (hapd->driver == NULL || hapd->driver->set_ap == NULL)
+               return 0;
+       return hapd->driver->set_ap(hapd->drv_priv, params);
+}
+
+static inline int hostapd_drv_set_radius_acl_auth(struct hostapd_data *hapd,
+                                                 const u8 *mac, int accepted,
+                                                 u32 session_timeout)
+{
+       if (hapd->driver == NULL || hapd->driver->set_radius_acl_auth == NULL)
+               return 0;
+       return hapd->driver->set_radius_acl_auth(hapd->drv_priv, mac, accepted,
+                                                session_timeout);
+}
+
+static inline int hostapd_drv_set_radius_acl_expire(struct hostapd_data *hapd,
+                                                   const u8 *mac)
+{
+       if (hapd->driver == NULL ||
+           hapd->driver->set_radius_acl_expire == NULL)
+               return 0;
+       return hapd->driver->set_radius_acl_expire(hapd->drv_priv, mac);
+}
+
+static inline int hostapd_drv_set_authmode(struct hostapd_data *hapd,
+                                          int auth_algs)
+{
+       if (hapd->driver == NULL || hapd->driver->set_authmode == NULL)
+               return 0;
+       return hapd->driver->set_authmode(hapd->drv_priv, auth_algs);
+}
+
+static inline void hostapd_drv_poll_client(struct hostapd_data *hapd,
+                                          const u8 *own_addr, const u8 *addr,
+                                          int qos)
+{
+       if (hapd->driver == NULL || hapd->driver->poll_client == NULL)
+               return;
+       hapd->driver->poll_client(hapd->drv_priv, own_addr, addr, qos);
+}
 
 #endif /* AP_DRV_OPS */
index 5297dbf..9b9fc9e 100644 (file)
@@ -227,6 +227,7 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
                            struct hostapd_frame_info *fi)
 {
        struct ap_info *ap;
+       struct os_time now;
        int new_ap = 0;
        size_t len;
        int set_beacon = 0;
@@ -292,7 +293,8 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
                ap->ht_support = 0;
 
        ap->num_beacons++;
-       time(&ap->last_beacon);
+       os_get_time(&now);
+       ap->last_beacon = now.sec;
        if (fi) {
                ap->ssi_signal = fi->ssi_signal;
                ap->datarate = fi->datarate;
@@ -331,7 +333,7 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
 static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
 {
        struct hostapd_iface *iface = eloop_ctx;
-       time_t now;
+       struct os_time now;
        struct ap_info *ap;
        int set_beacon = 0;
 
@@ -340,12 +342,12 @@ static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
        if (!iface->ap_list)
                return;
 
-       time(&now);
+       os_get_time(&now);
 
        while (iface->ap_list) {
                ap = iface->ap_list->prev;
                if (ap->last_beacon + iface->conf->ap_table_expiration_time >=
-                   now)
+                   now.sec)
                        break;
 
                ap_free_ap(iface, ap);
index f49f58b..6df8981 100644 (file)
@@ -45,7 +45,7 @@ struct ap_info {
        int ht_support;
 
        unsigned int num_beacons; /* number of beacon frames received */
-       time_t last_beacon;
+       os_time_t last_beacon;
 
        int already_seen; /* whether API call AP-NEW has already fetched
                           * information about this AP */
index 0ab0668..6f56c95 100644 (file)
@@ -60,7 +60,7 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
                                       struct eap_user *user)
 {
        const struct hostapd_eap_user *eap_user;
-       int i, count;
+       int i;
 
        eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2);
        if (eap_user == NULL)
@@ -70,10 +70,7 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
                return 0;
 
        os_memset(user, 0, sizeof(*user));
-       count = EAP_USER_MAX_METHODS;
-       if (count > EAP_MAX_METHODS)
-               count = EAP_MAX_METHODS;
-       for (i = 0; i < count; i++) {
+       for (i = 0; i < EAP_MAX_METHODS; i++) {
                user->methods[i].vendor = eap_user->methods[i].vendor;
                user->methods[i].method = eap_user->methods[i].method;
        }
@@ -119,6 +116,10 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
        srv.get_eap_user = hostapd_radius_get_eap_user;
        srv.eap_req_id_text = conf->eap_req_id_text;
        srv.eap_req_id_text_len = conf->eap_req_id_text_len;
+       srv.pwd_group = conf->pwd_group;
+#ifdef CONFIG_RADIUS_TEST
+       srv.dump_msk_file = conf->dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
 
        hapd->radius_srv = radius_server_init(&srv);
        if (hapd->radius_srv == NULL) {
index 004cc8a..4d8b277 100644 (file)
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "drivers/driver.h"
+#include "wps/wps_defs.h"
+#include "p2p/p2p.h"
 #include "hostapd.h"
 #include "ieee802_11.h"
 #include "wpa_auth.h"
 #include "wmm.h"
 #include "ap_config.h"
 #include "sta_info.h"
+#include "p2p_hostapd.h"
+#include "ap_drv_ops.h"
 #include "beacon.h"
 
 
+#ifdef NEED_AP_MLME
+
 static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
 {
        u8 erp = 0;
@@ -39,23 +45,11 @@ static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
            hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
                return 0;
 
-       switch (hapd->iconf->cts_protection_type) {
-       case CTS_PROTECTION_FORCE_ENABLED:
-               erp |= ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION;
-               break;
-       case CTS_PROTECTION_FORCE_DISABLED:
-               erp = 0;
-               break;
-       case CTS_PROTECTION_AUTOMATIC:
-               if (hapd->iface->olbc)
-                       erp |= ERP_INFO_USE_PROTECTION;
-               /* continue */
-       case CTS_PROTECTION_AUTOMATIC_NO_OLBC:
-               if (hapd->iface->num_sta_non_erp > 0) {
-                       erp |= ERP_INFO_NON_ERP_PRESENT |
-                               ERP_INFO_USE_PROTECTION;
-               }
-               break;
+       if (hapd->iface->olbc)
+               erp |= ERP_INFO_USE_PROTECTION;
+       if (hapd->iface->num_sta_non_erp > 0) {
+               erp |= ERP_INFO_NON_ERP_PRESENT |
+                       ERP_INFO_USE_PROTECTION;
        }
        if (hapd->iface->num_sta_no_short_preamble > 0 ||
            hapd->iconf->preamble == LONG_PREAMBLE)
@@ -178,8 +172,7 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
 }
 
 
-static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len,
-                           struct sta_info *sta)
+static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
 {
        const u8 *ie;
        size_t ielen;
@@ -193,92 +186,35 @@ static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len,
 }
 
 
-void handle_probe_req(struct hostapd_data *hapd,
-                     const struct ieee80211_mgmt *mgmt, size_t len)
+static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
+                                  struct sta_info *sta,
+                                  const struct ieee80211_mgmt *req,
+                                  int is_p2p, size_t *resp_len)
 {
        struct ieee80211_mgmt *resp;
-       struct ieee802_11_elems elems;
-       char *ssid;
        u8 *pos, *epos;
-       const u8 *ie;
-       size_t ssid_len, ie_len;
-       struct sta_info *sta = NULL;
        size_t buflen;
-       size_t i;
-
-       ie = mgmt->u.probe_req.variable;
-       ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
-
-       for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
-               if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
-                                           mgmt->sa, ie, ie_len) > 0)
-                       return;
-
-       if (!hapd->iconf->send_probe_response)
-               return;
-
-       if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
-               wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR,
-                          MAC2STR(mgmt->sa));
-               return;
-       }
-
-       ssid = NULL;
-       ssid_len = 0;
-
-       if ((!elems.ssid || !elems.supp_rates)) {
-               wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request "
-                          "without SSID or supported rates element",
-                          MAC2STR(mgmt->sa));
-               return;
-       }
-
-       if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0) {
-               wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
-                          "broadcast SSID ignored", MAC2STR(mgmt->sa));
-               return;
-       }
-
-       sta = ap_get_sta(hapd, mgmt->sa);
 
-       if (elems.ssid_len == 0 ||
-           (elems.ssid_len == hapd->conf->ssid.ssid_len &&
-            os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) ==
-            0)) {
-               ssid = hapd->conf->ssid.ssid;
-               ssid_len = hapd->conf->ssid.ssid_len;
-               if (sta)
-                       sta->ssid_probe = &hapd->conf->ssid;
-       }
-
-       if (!ssid) {
-               if (!(mgmt->da[0] & 0x01)) {
-                       char ssid_txt[33];
-                       ieee802_11_print_ssid(ssid_txt, elems.ssid,
-                                             elems.ssid_len);
-                       wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
-                                  " for foreign SSID '%s'",
-                                  MAC2STR(mgmt->sa), ssid_txt);
-               }
-               return;
-       }
-
-       /* TODO: verify that supp_rates contains at least one matching rate
-        * with AP configuration */
 #define MAX_PROBERESP_LEN 768
        buflen = MAX_PROBERESP_LEN;
 #ifdef CONFIG_WPS
        if (hapd->wps_probe_resp_ie)
                buflen += wpabuf_len(hapd->wps_probe_resp_ie);
 #endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+       if (hapd->p2p_probe_resp_ie)
+               buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
+#endif /* CONFIG_P2P */
        resp = os_zalloc(buflen);
        if (resp == NULL)
-               return;
+               return NULL;
+
        epos = ((u8 *) resp) + MAX_PROBERESP_LEN;
 
        resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
                                           WLAN_FC_STYPE_PROBE_RESP);
-       os_memcpy(resp->da, mgmt->sa, ETH_ALEN);
+       if (req)
+               os_memcpy(resp->da, req->sa, ETH_ALEN);
        os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
 
        os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
@@ -291,9 +227,9 @@ void handle_probe_req(struct hostapd_data *hapd,
 
        pos = resp->u.probe_resp.variable;
        *pos++ = WLAN_EID_SSID;
-       *pos++ = ssid_len;
-       os_memcpy(pos, ssid, ssid_len);
-       pos += ssid_len;
+       *pos++ = hapd->conf->ssid.ssid_len;
+       os_memcpy(pos, hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len);
+       pos += hapd->conf->ssid.ssid_len;
 
        /* Supported rates */
        pos = hostapd_eid_supp_rates(hapd, pos);
@@ -310,13 +246,22 @@ void handle_probe_req(struct hostapd_data *hapd,
        pos = hostapd_eid_ext_supp_rates(hapd, pos);
 
        /* RSN, MDIE, WPA */
-       pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta);
+       pos = hostapd_eid_wpa(hapd, pos, epos - pos);
 
 #ifdef CONFIG_IEEE80211N
        pos = hostapd_eid_ht_capabilities(hapd, pos);
        pos = hostapd_eid_ht_operation(hapd, pos);
 #endif /* CONFIG_IEEE80211N */
 
+       pos = hostapd_eid_ext_capab(hapd, pos);
+
+       pos = hostapd_eid_time_adv(hapd, pos);
+       pos = hostapd_eid_time_zone(hapd, pos);
+
+       pos = hostapd_eid_interworking(hapd, pos);
+       pos = hostapd_eid_adv_proto(hapd, pos);
+       pos = hostapd_eid_roaming_consortium(hapd, pos);
+
        /* Wi-Fi Alliance WMM */
        pos = hostapd_eid_wmm(hapd, pos);
 
@@ -328,23 +273,225 @@ void handle_probe_req(struct hostapd_data *hapd,
        }
 #endif /* CONFIG_WPS */
 
-       if (hapd->drv.send_mgmt_frame(hapd, resp, pos - (u8 *) resp) < 0)
+#ifdef CONFIG_P2P
+       if ((hapd->conf->p2p & P2P_ENABLED) && is_p2p &&
+           hapd->p2p_probe_resp_ie) {
+               os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie),
+                         wpabuf_len(hapd->p2p_probe_resp_ie));
+               pos += wpabuf_len(hapd->p2p_probe_resp_ie);
+       }
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_P2P_MANAGER
+       if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
+           P2P_MANAGE)
+               pos = hostapd_eid_p2p_manage(hapd, pos);
+#endif /* CONFIG_P2P_MANAGER */
+
+       *resp_len = pos - (u8 *) resp;
+       return (u8 *) resp;
+}
+
+
+void handle_probe_req(struct hostapd_data *hapd,
+                     const struct ieee80211_mgmt *mgmt, size_t len)
+{
+       u8 *resp;
+       struct ieee802_11_elems elems;
+       const u8 *ie;
+       size_t ie_len;
+       struct sta_info *sta = NULL;
+       size_t i, resp_len;
+       int noack;
+
+       ie = mgmt->u.probe_req.variable;
+       if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+               return;
+       ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+
+       for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
+               if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
+                                           mgmt->sa, mgmt->da, mgmt->bssid,
+                                           ie, ie_len) > 0)
+                       return;
+
+       if (!hapd->iconf->send_probe_response)
+               return;
+
+       if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
+               wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR,
+                          MAC2STR(mgmt->sa));
+               return;
+       }
+
+       if ((!elems.ssid || !elems.supp_rates)) {
+               wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request "
+                          "without SSID or supported rates element",
+                          MAC2STR(mgmt->sa));
+               return;
+       }
+
+#ifdef CONFIG_P2P
+       if (hapd->p2p && elems.wps_ie) {
+               struct wpabuf *wps;
+               wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
+               if (wps && !p2p_group_match_dev_type(hapd->p2p_group, wps)) {
+                       wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request "
+                                  "due to mismatch with Requested Device "
+                                  "Type");
+                       wpabuf_free(wps);
+                       return;
+               }
+               wpabuf_free(wps);
+       }
+#endif /* CONFIG_P2P */
+
+       if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0) {
+               wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
+                          "broadcast SSID ignored", MAC2STR(mgmt->sa));
+               return;
+       }
+
+       sta = ap_get_sta(hapd, mgmt->sa);
+
+#ifdef CONFIG_P2P
+       if ((hapd->conf->p2p & P2P_GROUP_OWNER) &&
+           elems.ssid_len == P2P_WILDCARD_SSID_LEN &&
+           os_memcmp(elems.ssid, P2P_WILDCARD_SSID,
+                     P2P_WILDCARD_SSID_LEN) == 0) {
+               /* Process P2P Wildcard SSID like Wildcard SSID */
+               elems.ssid_len = 0;
+       }
+#endif /* CONFIG_P2P */
+
+       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)) {
+               if (sta)
+                       sta->ssid_probe = &hapd->conf->ssid;
+       } else {
+               if (!(mgmt->da[0] & 0x01)) {
+                       char ssid_txt[33];
+                       ieee802_11_print_ssid(ssid_txt, elems.ssid,
+                                             elems.ssid_len);
+                       wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
+                                  " for foreign SSID '%s' (DA " MACSTR ")",
+                                  MAC2STR(mgmt->sa), ssid_txt,
+                                  MAC2STR(mgmt->da));
+               }
+               return;
+       }
+
+#ifdef CONFIG_INTERWORKING
+       if (elems.interworking && elems.interworking_len >= 1) {
+               u8 ant = elems.interworking[0] & 0x0f;
+               if (ant != INTERWORKING_ANT_WILDCARD &&
+                   ant != hapd->conf->access_network_type) {
+                       wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
+                                  " for mismatching ANT %u ignored",
+                                  MAC2STR(mgmt->sa), ant);
+                       return;
+               }
+       }
+
+       if (elems.interworking &&
+           (elems.interworking_len == 7 || elems.interworking_len == 9)) {
+               const u8 *hessid;
+               if (elems.interworking_len == 7)
+                       hessid = elems.interworking + 1;
+               else
+                       hessid = elems.interworking + 1 + 2;
+               if (!is_broadcast_ether_addr(hessid) &&
+                   os_memcmp(hessid, hapd->conf->hessid, ETH_ALEN) != 0) {
+                       wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
+                                  " for mismatching HESSID " MACSTR
+                                  " ignored",
+                                  MAC2STR(mgmt->sa), MAC2STR(hessid));
+                       return;
+               }
+       }
+#endif /* CONFIG_INTERWORKING */
+
+       /* TODO: verify that supp_rates contains at least one matching rate
+        * with AP configuration */
+
+       resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL,
+                                     &resp_len);
+       if (resp == NULL)
+               return;
+
+       /*
+        * If this is a broadcast probe request, apply no ack policy to avoid
+        * excessive retries.
+        */
+       noack = !!(elems.ssid_len == 0 && is_broadcast_ether_addr(mgmt->da));
+
+       if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0)
                perror("handle_probe_req: send");
 
        os_free(resp);
 
-       wpa_printf(MSG_MSGDUMP, "STA " MACSTR " sent probe request for %s "
+       wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s "
                   "SSID", MAC2STR(mgmt->sa),
                   elems.ssid_len == 0 ? "broadcast" : "our");
 }
 
 
+static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
+                                       size_t *resp_len)
+{
+       /* check probe response offloading caps and print warnings */
+       if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD))
+               return NULL;
+
+#ifdef CONFIG_WPS
+       if (hapd->conf->wps_state && hapd->wps_probe_resp_ie &&
+           (!(hapd->iface->probe_resp_offloads &
+              (WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS |
+               WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2))))
+               wpa_printf(MSG_WARNING, "Device is trying to offload WPS "
+                          "Probe Response while not supporting this");
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+       if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_probe_resp_ie &&
+           !(hapd->iface->probe_resp_offloads &
+             WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P))
+               wpa_printf(MSG_WARNING, "Device is trying to offload P2P "
+                          "Probe Response while not supporting this");
+#endif  /* CONFIG_P2P */
+
+       if (hapd->conf->interworking &&
+           !(hapd->iface->probe_resp_offloads &
+             WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING))
+               wpa_printf(MSG_WARNING, "Device is trying to offload "
+                          "Interworking Probe Response while not supporting "
+                          "this");
+
+       /* Generate a Probe Response template for the non-P2P case */
+       return hostapd_gen_probe_resp(hapd, NULL, NULL, 0, resp_len);
+}
+
+#endif /* NEED_AP_MLME */
+
+
 void ieee802_11_set_beacon(struct hostapd_data *hapd)
 {
-       struct ieee80211_mgmt *head;
-       u8 *pos, *tail, *tailpos;
+       struct ieee80211_mgmt *head = NULL;
+       u8 *tail = NULL;
+       size_t head_len = 0, tail_len = 0;
+       u8 *resp = NULL;
+       size_t resp_len = 0;
+       struct wpa_driver_ap_params params;
+       struct wpabuf *beacon, *proberesp, *assocresp;
+#ifdef NEED_AP_MLME
        u16 capab_info;
-       size_t head_len, tail_len;
+       u8 *pos, *tailpos;
+#endif /* NEED_AP_MLME */
+
+       hapd->beacon_set_done = 1;
+
+#ifdef NEED_AP_MLME
 
 #define BEACON_HEAD_BUF_SIZE 256
 #define BEACON_TAIL_BUF_SIZE 512
@@ -354,6 +501,10 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
        if (hapd->conf->wps_state && hapd->wps_beacon_ie)
                tail_len += wpabuf_len(hapd->wps_beacon_ie);
 #endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+       if (hapd->p2p_beacon_ie)
+               tail_len += wpabuf_len(hapd->p2p_beacon_ie);
+#endif /* CONFIG_P2P */
        tailpos = tail = os_malloc(tail_len);
        if (head == NULL || tail == NULL) {
                wpa_printf(MSG_ERROR, "Failed to set beacon data");
@@ -412,13 +563,25 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
 
        /* RSN, MDIE, WPA */
        tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
-                                 tailpos, NULL);
+                                 tailpos);
 
 #ifdef CONFIG_IEEE80211N
        tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
        tailpos = hostapd_eid_ht_operation(hapd, tailpos);
 #endif /* CONFIG_IEEE80211N */
 
+       tailpos = hostapd_eid_ext_capab(hapd, tailpos);
+
+       /*
+        * TODO: Time Advertisement element should only be included in some
+        * DTIM Beacon frames.
+        */
+       tailpos = hostapd_eid_time_adv(hapd, tailpos);
+
+       tailpos = hostapd_eid_interworking(hapd, tailpos);
+       tailpos = hostapd_eid_adv_proto(hapd, tailpos);
+       tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
+
        /* Wi-Fi Alliance WMM */
        tailpos = hostapd_eid_wmm(hapd, tailpos);
 
@@ -430,19 +593,90 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
        }
 #endif /* CONFIG_WPS */
 
+#ifdef CONFIG_P2P
+       if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_beacon_ie) {
+               os_memcpy(tailpos, wpabuf_head(hapd->p2p_beacon_ie),
+                         wpabuf_len(hapd->p2p_beacon_ie));
+               tailpos += wpabuf_len(hapd->p2p_beacon_ie);
+       }
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_P2P_MANAGER
+       if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
+           P2P_MANAGE)
+               tailpos = hostapd_eid_p2p_manage(hapd, tailpos);
+#endif /* CONFIG_P2P_MANAGER */
+
        tail_len = tailpos > tail ? tailpos - tail : 0;
 
-       if (hapd->drv.set_beacon(hapd, (u8 *) head, head_len,
-                                tail, tail_len, hapd->conf->dtim_period,
-                                hapd->iconf->beacon_int))
-               wpa_printf(MSG_ERROR, "Failed to set beacon head/tail or DTIM "
-                          "period");
+       resp = hostapd_probe_resp_offloads(hapd, &resp_len);
+#endif /* NEED_AP_MLME */
+
+       os_memset(&params, 0, sizeof(params));
+       params.head = (u8 *) head;
+       params.head_len = head_len;
+       params.tail = tail;
+       params.tail_len = tail_len;
+       params.proberesp = resp;
+       params.proberesp_len = resp_len;
+       params.dtim_period = hapd->conf->dtim_period;
+       params.beacon_int = hapd->iconf->beacon_int;
+       params.basic_rates = hapd->iconf->basic_rates;
+       params.ssid = (u8 *) hapd->conf->ssid.ssid;
+       params.ssid_len = hapd->conf->ssid.ssid_len;
+       params.pairwise_ciphers = hapd->conf->rsn_pairwise ?
+               hapd->conf->rsn_pairwise : hapd->conf->wpa_pairwise;
+       params.group_cipher = hapd->conf->wpa_group;
+       params.key_mgmt_suites = hapd->conf->wpa_key_mgmt;
+       params.auth_algs = hapd->conf->auth_algs;
+       params.wpa_version = hapd->conf->wpa;
+       params.privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
+               (hapd->conf->ieee802_1x &&
+                (hapd->conf->default_wep_key_len ||
+                 hapd->conf->individual_wep_key_len));
+       switch (hapd->conf->ignore_broadcast_ssid) {
+       case 0:
+               params.hide_ssid = NO_SSID_HIDING;
+               break;
+       case 1:
+               params.hide_ssid = HIDDEN_SSID_ZERO_LEN;
+               break;
+       case 2:
+               params.hide_ssid = HIDDEN_SSID_ZERO_CONTENTS;
+               break;
+       }
+       hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp);
+       params.beacon_ies = beacon;
+       params.proberesp_ies = proberesp;
+       params.assocresp_ies = assocresp;
+       params.isolate = hapd->conf->isolate;
+#ifdef NEED_AP_MLME
+       params.cts_protect = !!(ieee802_11_erp_info(hapd) &
+                               ERP_INFO_USE_PROTECTION);
+       params.preamble = hapd->iface->num_sta_no_short_preamble == 0 &&
+               hapd->iconf->preamble == SHORT_PREAMBLE;
+       if (hapd->iface->current_mode &&
+           hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+               params.short_slot_time =
+                       hapd->iface->num_sta_no_short_slot_time > 0 ? 0 : 1;
+       else
+               params.short_slot_time = -1;
+       if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
+               params.ht_opmode = -1;
+       else
+               params.ht_opmode = hapd->iface->ht_op_mode;
+#endif /* NEED_AP_MLME */
+       params.interworking = hapd->conf->interworking;
+       if (hapd->conf->interworking &&
+           !is_zero_ether_addr(hapd->conf->hessid))
+               params.hessid = hapd->conf->hessid;
+       params.access_network_type = hapd->conf->access_network_type;
+       if (hostapd_drv_set_ap(hapd, &params))
+               wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
+       hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
 
        os_free(tail);
        os_free(head);
-
-       hapd->drv.set_bss_params(hapd, !!(ieee802_11_erp_info(hapd) &
-                                         ERP_INFO_USE_PROTECTION));
+       os_free(resp);
 }
 
 
index c1510e1..a944f5f 100644 (file)
@@ -20,17 +20,7 @@ struct ieee80211_mgmt;
 
 void handle_probe_req(struct hostapd_data *hapd,
                      const struct ieee80211_mgmt *mgmt, size_t len);
-#ifdef NEED_AP_MLME
 void ieee802_11_set_beacon(struct hostapd_data *hapd);
 void ieee802_11_set_beacons(struct hostapd_iface *iface);
-#else /* NEED_AP_MLME */
-static inline void ieee802_11_set_beacon(struct hostapd_data *hapd)
-{
-}
-
-static inline void ieee802_11_set_beacons(struct hostapd_iface *iface)
-{
-}
-#endif /* NEED_AP_MLME */
 
 #endif /* BEACON_H */
index e50b0a7..d348dc1 100644 (file)
@@ -21,6 +21,7 @@
 #include "ieee802_11.h"
 #include "sta_info.h"
 #include "wps_hostapd.h"
+#include "p2p_hostapd.h"
 #include "ctrl_iface_ap.h"
 
 
@@ -57,6 +58,9 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
                                      buflen - len);
        if (res >= 0)
                len += res;
+       res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
+       if (res >= 0)
+               len += res;
 
        return len;
 }
index 26ef584..b7febdc 100644 (file)
 #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 "hostapd.h"
 #include "ieee802_11.h"
 #include "sta_info.h"
 #include "accounting.h"
 #include "tkip_countermeasures.h"
-#include "iapp.h"
 #include "ieee802_1x.h"
 #include "wpa_auth.h"
-#include "wmm.h"
 #include "wps_hostapd.h"
+#include "ap_drv_ops.h"
 #include "ap_config.h"
 
 
 int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
-                       const u8 *ie, size_t ielen)
+                       const u8 *req_ies, size_t req_ies_len, int reassoc)
 {
        struct sta_info *sta;
        int new_assoc, res;
        struct ieee802_11_elems elems;
+       const u8 *ie;
+       size_t ielen;
+       u16 reason = WLAN_REASON_UNSPECIFIED;
 
        if (addr == NULL) {
                /*
@@ -52,11 +56,12 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
                           "no address");
                return -1;
        }
+       random_add_randomness(addr, ETH_ALEN);
 
        hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
                       HOSTAPD_LEVEL_INFO, "associated");
 
-       ieee802_11_parse_elems(ie, ielen, &elems, 0);
+       ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0);
        if (elems.wps_ie) {
                ie = elems.wps_ie - 2;
                ielen = elems.wps_ie_len + 2;
@@ -84,10 +89,19 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
                if (sta == NULL)
                        return -1;
        }
-       sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
+       sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
+
+#ifdef CONFIG_P2P
+       if (elems.p2p) {
+               wpabuf_free(sta->p2p_ie);
+               sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
+                                                         P2P_IE_VENDOR_TYPE);
+       }
+#endif /* CONFIG_P2P */
 
        if (hapd->conf->wpa) {
                if (ie == NULL || ielen == 0) {
+#ifdef CONFIG_WPS
                        if (hapd->conf->wps_state) {
                                wpa_printf(MSG_DEBUG, "STA did not include "
                                           "WPA/RSN IE in (Re)Association "
@@ -95,15 +109,29 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
                                sta->flags |= WLAN_STA_MAYBE_WPS;
                                goto skip_wpa_check;
                        }
+#endif /* CONFIG_WPS */
 
                        wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
                        return -1;
                }
+#ifdef CONFIG_WPS
                if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
                    os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
+                       struct wpabuf *wps;
                        sta->flags |= WLAN_STA_WPS;
+                       wps = ieee802_11_vendor_ie_concat(ie, ielen,
+                                                         WPS_IE_VENDOR_TYPE);
+                       if (wps) {
+                               if (wps_is_20(wps)) {
+                                       wpa_printf(MSG_DEBUG, "WPS: STA "
+                                                  "supports WPS 2.0");
+                                       sta->flags |= WLAN_STA_WPS2;
+                               }
+                               wpabuf_free(wps);
+                       }
                        goto skip_wpa_check;
                }
+#endif /* CONFIG_WPS */
 
                if (sta->wpa_sm == NULL)
                        sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
@@ -116,36 +144,55 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
                res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
                                          ie, ielen, NULL, 0);
                if (res != WPA_IE_OK) {
-                       int resp;
                        wpa_printf(MSG_DEBUG, "WPA/RSN information element "
                                   "rejected? (res %u)", res);
                        wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
                        if (res == WPA_INVALID_GROUP)
-                               resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+                               reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
                        else if (res == WPA_INVALID_PAIRWISE)
-                               resp = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
+                               reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
                        else if (res == WPA_INVALID_AKMP)
-                               resp = WLAN_REASON_AKMP_NOT_VALID;
+                               reason = WLAN_REASON_AKMP_NOT_VALID;
 #ifdef CONFIG_IEEE80211W
                        else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
-                               resp = WLAN_REASON_INVALID_IE;
+                               reason = WLAN_REASON_INVALID_IE;
                        else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
-                               resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+                               reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
 #endif /* CONFIG_IEEE80211W */
                        else
-                               resp = WLAN_REASON_INVALID_IE;
-                       hapd->drv.sta_disassoc(hapd, sta->addr, resp);
-                       ap_free_sta(hapd, sta);
-                       return -1;
+                               reason = WLAN_REASON_INVALID_IE;
+                       goto fail;
                }
        } else if (hapd->conf->wps_state) {
-               if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 &&
-                   os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
+#ifdef CONFIG_WPS
+               struct wpabuf *wps;
+               if (req_ies)
+                       wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
+                                                         WPS_IE_VENDOR_TYPE);
+               else
+                       wps = NULL;
+#ifdef CONFIG_WPS_STRICT
+               if (wps && wps_validate_assoc_req(wps) < 0) {
+                       reason = WLAN_REASON_INVALID_IE;
+                       wpabuf_free(wps);
+                       goto fail;
+               }
+#endif /* CONFIG_WPS_STRICT */
+               if (wps) {
                        sta->flags |= WLAN_STA_WPS;
+                       if (wps_is_20(wps)) {
+                               wpa_printf(MSG_DEBUG, "WPS: STA supports "
+                                          "WPS 2.0");
+                               sta->flags |= WLAN_STA_WPS2;
+                       }
                } else
                        sta->flags |= WLAN_STA_MAYBE_WPS;
+               wpabuf_free(wps);
+#endif /* CONFIG_WPS */
        }
+#ifdef CONFIG_WPS
 skip_wpa_check:
+#endif /* CONFIG_WPS */
 
        new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
        sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
@@ -155,7 +202,19 @@ skip_wpa_check:
 
        ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
 
+#ifdef CONFIG_P2P
+       if (req_ies) {
+               p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
+                                     req_ies, req_ies_len);
+       }
+#endif /* CONFIG_P2P */
+
        return 0;
+
+fail:
+       hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
+       ap_free_sta(hapd, sta);
+       return -1;
 }
 
 
@@ -163,6 +222,19 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
 {
        struct sta_info *sta;
 
+       if (addr == NULL) {
+               /*
+                * This could potentially happen with unexpected event from the
+                * driver wrapper. This was seen at least in one case where the
+                * driver ended up reporting a station mode event while hostapd
+                * was running, so better make sure we stop processing such an
+                * event here.
+                */
+               wpa_printf(MSG_DEBUG, "hostapd_notif_disassoc: Skip event "
+                          "with no address");
+               return;
+       }
+
        hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
                       HOSTAPD_LEVEL_INFO, "disassociated");
 
@@ -173,9 +245,8 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
                return;
        }
 
+       ap_sta_set_authorized(hapd, sta, 0);
        sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
-       wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-               MAC2STR(sta->addr));
        wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
        sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
        ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
@@ -183,50 +254,47 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
 }
 
 
-#ifdef HOSTAPD
+void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
+{
+       struct sta_info *sta = ap_get_sta(hapd, addr);
 
-#ifdef NEED_AP_MLME
+       if (!sta || !hapd->conf->disassoc_low_ack)
+               return;
 
-static const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
+       hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+                      HOSTAPD_LEVEL_INFO, "disconnected due to excessive "
+                      "missing ACKs");
+       hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK);
+       if (sta)
+               ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
+}
+
+
+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)
 {
-       u16 fc, type, stype;
+       size_t i;
+       int ret = 0;
 
-       /*
-        * PS-Poll frames are 16 bytes. All other frames are
-        * 24 bytes or longer.
-        */
-       if (len < 16)
-               return NULL;
+       if (sa == NULL || ie == NULL)
+               return -1;
 
-       fc = le_to_host16(hdr->frame_control);
-       type = WLAN_FC_GET_TYPE(fc);
-       stype = WLAN_FC_GET_STYPE(fc);
-
-       switch (type) {
-       case WLAN_FC_TYPE_DATA:
-               if (len < 24)
-                       return NULL;
-               switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
-               case WLAN_FC_FROMDS | WLAN_FC_TODS:
-               case WLAN_FC_TODS:
-                       return hdr->addr1;
-               case WLAN_FC_FROMDS:
-                       return hdr->addr2;
-               default:
-                       return NULL;
+       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) {
+                       ret = 1;
+                       break;
                }
-       case WLAN_FC_TYPE_CTRL:
-               if (stype != WLAN_FC_STYPE_PSPOLL)
-                       return NULL;
-               return hdr->addr1;
-       case WLAN_FC_TYPE_MGMT:
-               return hdr->addr3;
-       default:
-               return NULL;
        }
+       return ret;
 }
 
 
+#ifdef HOSTAPD
+
+#ifdef NEED_AP_MLME
+
 #define HAPD_BROADCAST ((struct hostapd_data *) -1)
 
 static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
@@ -250,17 +318,14 @@ static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
 
 
 static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
-                                       const u8 *frame, size_t len)
+                                       const u8 *bssid, const u8 *addr,
+                                       int wds)
 {
-       const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame;
-       u16 fc = le_to_host16(hdr->frame_control);
-       hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
+       hapd = get_hapd_bssid(hapd->iface, bssid);
        if (hapd == NULL || hapd == HAPD_BROADCAST)
                return;
 
-       ieee802_11_rx_from_unknown(hapd, hdr->addr2,
-                                  (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
-                                  (WLAN_FC_TODS | WLAN_FC_FROMDS));
+       ieee802_11_rx_from_unknown(hapd, addr, wds);
 }
 
 
@@ -303,6 +368,48 @@ static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
                                        rx_mgmt->frame_len, &fi);
        } else
                ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, &fi);
+
+       random_add_randomness(&fi, sizeof(fi));
+}
+
+
+static void hostapd_rx_action(struct hostapd_data *hapd,
+                             struct rx_action *rx_action)
+{
+       struct rx_mgmt rx_mgmt;
+       u8 *buf;
+       struct ieee80211_hdr *hdr;
+
+       wpa_printf(MSG_DEBUG, "EVENT_RX_ACTION DA=" MACSTR " SA=" MACSTR
+                  " BSSID=" MACSTR " category=%u",
+                  MAC2STR(rx_action->da), MAC2STR(rx_action->sa),
+                  MAC2STR(rx_action->bssid), rx_action->category);
+       wpa_hexdump(MSG_MSGDUMP, "Received action frame contents",
+                   rx_action->data, rx_action->len);
+
+       buf = os_zalloc(24 + 1 + rx_action->len);
+       if (buf == NULL)
+               return;
+       hdr = (struct ieee80211_hdr *) buf;
+       hdr->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+                                         WLAN_FC_STYPE_ACTION);
+       if (rx_action->category == WLAN_ACTION_SA_QUERY) {
+               /*
+                * Assume frame was protected; it would have been dropped if
+                * not.
+                */
+               hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+       }
+       os_memcpy(hdr->addr1, rx_action->da, ETH_ALEN);
+       os_memcpy(hdr->addr2, rx_action->sa, ETH_ALEN);
+       os_memcpy(hdr->addr3, rx_action->bssid, ETH_ALEN);
+       buf[24] = rx_action->category;
+       os_memcpy(buf + 24 + 1, rx_action->data, rx_action->len);
+       os_memset(&rx_mgmt, 0, sizeof(rx_mgmt));
+       rx_mgmt.frame = buf;
+       rx_mgmt.frame_len = 24 + 1 + rx_action->len;
+       hostapd_mgmt_rx(hapd, &rx_mgmt);
+       os_free(buf);
 }
 
 
@@ -320,23 +427,6 @@ static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
 #endif /* NEED_AP_MLME */
 
 
-static int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa,
-                               const u8 *ie, size_t ie_len)
-{
-       size_t i;
-       int ret = 0;
-
-       for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
-               if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
-                                           sa, ie, ie_len) > 0) {
-                       ret = 1;
-                       break;
-               }
-       }
-       return ret;
-}
-
-
 static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr)
 {
        struct sta_info *sta = ap_get_sta(hapd, addr);
@@ -379,6 +469,23 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                          union wpa_event_data *data)
 {
        struct hostapd_data *hapd = ctx;
+#ifndef CONFIG_NO_STDOUT_DEBUG
+       int level = MSG_DEBUG;
+
+       if (event == EVENT_RX_MGMT && data && data->rx_mgmt.frame &&
+           data->rx_mgmt.frame_len >= 24) {
+               const struct ieee80211_hdr *hdr;
+               u16 fc;
+               hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
+               fc = le_to_host16(hdr->frame_control);
+               if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+                   WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
+                       level = MSG_EXCESSIVE;
+       }
+
+       wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received",
+               event_to_string(event), event);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
 
        switch (event) {
        case EVENT_MICHAEL_MIC_FAILURE:
@@ -395,7 +502,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                break;
 #endif /* CONFIG_IEEE80211R */
        case EVENT_WPS_BUTTON_PUSHED:
-               hostapd_wps_button_pushed(hapd);
+               hostapd_wps_button_pushed(hapd, NULL);
                break;
 #ifdef NEED_AP_MLME
        case EVENT_TX_STATUS:
@@ -414,16 +521,31 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                        break;
                }
                break;
+       case EVENT_EAPOL_TX_STATUS:
+               hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst,
+                                       data->eapol_tx_status.data,
+                                       data->eapol_tx_status.data_len,
+                                       data->eapol_tx_status.ack);
+               break;
+       case EVENT_DRIVER_CLIENT_POLL_OK:
+               hostapd_client_poll_ok(hapd, data->client_poll.addr);
+               break;
        case EVENT_RX_FROM_UNKNOWN:
-               hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.frame,
-                                           data->rx_from_unknown.len);
+               hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid,
+                                           data->rx_from_unknown.addr,
+                                           data->rx_from_unknown.wds);
                break;
        case EVENT_RX_MGMT:
                hostapd_mgmt_rx(hapd, &data->rx_mgmt);
                break;
 #endif /* NEED_AP_MLME */
        case EVENT_RX_PROBE_REQ:
+               if (data->rx_probe_req.sa == NULL ||
+                   data->rx_probe_req.ie == NULL)
+                       break;
                hostapd_probe_req_rx(hapd, data->rx_probe_req.sa,
+                                    data->rx_probe_req.da,
+                                    data->rx_probe_req.bssid,
                                     data->rx_probe_req.ie,
                                     data->rx_probe_req.ie_len);
                break;
@@ -438,7 +560,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
        case EVENT_ASSOC:
                hostapd_notif_assoc(hapd, data->assoc_info.addr,
                                    data->assoc_info.req_ies,
-                                   data->assoc_info.req_ies_len);
+                                   data->assoc_info.req_ies_len,
+                                   data->assoc_info.reassoc);
                break;
        case EVENT_DISASSOC:
                if (data)
@@ -448,6 +571,19 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                if (data)
                        hostapd_notif_disassoc(hapd, data->deauth_info.addr);
                break;
+       case EVENT_STATION_LOW_ACK:
+               if (!data)
+                       break;
+               hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
+               break;
+#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;
+               hostapd_rx_action(hapd, &data->rx_action);
+               break;
+#endif /* NEED_AP_MLME */
        default:
                wpa_printf(MSG_DEBUG, "Unknown event %d", event);
                break;
index 841f9c5..0c5ee2e 100644 (file)
 #include "wpa_auth_glue.h"
 #include "ap_drv_ops.h"
 #include "ap_config.h"
+#include "p2p_hostapd.h"
 
 
 static int hostapd_flush_old_stations(struct hostapd_data *hapd);
 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;
 
 
-int hostapd_reload_config(struct hostapd_iface *iface)
+static void hostapd_reload_bss(struct hostapd_data *hapd)
 {
-       struct hostapd_data *hapd = iface->bss[0];
-       struct hostapd_config *newconf, *oldconf;
-       size_t j;
-
-       if (iface->config_read_cb == NULL)
-               return -1;
-       newconf = iface->config_read_cb(iface->config_fname);
-       if (newconf == NULL)
-               return -1;
-
-       /*
-        * Deauthenticate all stations since the new configuration may not
-        * allow them to use the BSS anymore.
-        */
-       for (j = 0; j < iface->num_bss; j++)
-               hostapd_flush_old_stations(iface->bss[j]);
-
 #ifndef CONFIG_NO_RADIUS
-       /* TODO: update dynamic data based on changed configuration
-        * items (e.g., open/close sockets, etc.) */
-       radius_client_flush(hapd->radius, 0);
+       radius_client_reconfig(hapd->radius, hapd->conf->radius);
 #endif /* CONFIG_NO_RADIUS */
 
-       oldconf = hapd->iconf;
-       hapd->iconf = newconf;
-       hapd->conf = &newconf->bss[0];
-       iface->conf = newconf;
-
        if (hostapd_setup_wpa_psk(hapd->conf)) {
                wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK "
                           "after reloading configuration");
        }
 
        if (hapd->conf->ieee802_1x || hapd->conf->wpa)
-               hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 1);
+               hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1);
        else
-               hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
+               hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
 
-       if (hapd->conf->wpa && hapd->wpa_auth == NULL)
+       if (hapd->conf->wpa && hapd->wpa_auth == NULL) {
                hostapd_setup_wpa(hapd);
-       else if (hapd->conf->wpa) {
+               if (hapd->wpa_auth)
+                       wpa_init_keys(hapd->wpa_auth);
+       } else if (hapd->conf->wpa) {
                const u8 *wpa_ie;
                size_t wpa_ie_len;
                hostapd_reconfig_wpa(hapd);
@@ -110,10 +90,49 @@ int hostapd_reload_config(struct hostapd_iface *iface)
                wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
                /* try to continue */
        }
+       wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface);
+}
+
+
+int hostapd_reload_config(struct hostapd_iface *iface)
+{
+       struct hostapd_data *hapd = iface->bss[0];
+       struct hostapd_config *newconf, *oldconf;
+       size_t j;
+
+       if (iface->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_broadcast_wep_clear(iface->bss[j]);
+
+#ifndef CONFIG_NO_RADIUS
+               /* TODO: update dynamic data based on changed configuration
+                * items (e.g., open/close sockets, etc.) */
+               radius_client_flush(iface->bss[j]->radius, 0);
+#endif /* CONFIG_NO_RADIUS */
+       }
+
+       oldconf = hapd->iconf;
+       iface->conf = newconf;
+
+       for (j = 0; j < iface->num_bss; j++) {
+               hapd = iface->bss[j];
+               hapd->iconf = newconf;
+               hapd->conf = &newconf->bss[j];
+               hostapd_reload_bss(hapd);
+       }
 
        hostapd_config_free(oldconf);
 
-       wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface);
 
        return 0;
 }
@@ -125,8 +144,8 @@ static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
        int i;
 
        for (i = 0; i < NUM_WEP_KEYS; i++) {
-               if (hapd->drv.set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
-                                     i == 0 ? 1 : 0, NULL, 0, NULL, 0)) {
+               if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
+                                       0, NULL, 0, NULL, 0)) {
                        wpa_printf(MSG_DEBUG, "Failed to clear default "
                                   "encryption keys (ifname=%s keyidx=%d)",
                                   ifname, i);
@@ -135,9 +154,9 @@ static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
 #ifdef CONFIG_IEEE80211W
        if (hapd->conf->ieee80211w) {
                for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
-                       if (hapd->drv.set_key(ifname, hapd, WPA_ALG_NONE, NULL,
-                                             i, i == 0 ? 1 : 0, NULL, 0,
-                                             NULL, 0)) {
+                       if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE,
+                                               NULL, i, 0, NULL,
+                                               0, NULL, 0)) {
                                wpa_printf(MSG_DEBUG, "Failed to clear "
                                           "default mgmt encryption keys "
                                           "(ifname=%s keyidx=%d)", ifname, i);
@@ -162,11 +181,10 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
 
        idx = ssid->wep.idx;
        if (ssid->wep.default_len &&
-           hapd->drv.set_key(hapd->conf->iface,
-                             hapd, WPA_ALG_WEP, NULL, idx,
-                             idx == ssid->wep.idx,
-                             NULL, 0, ssid->wep.key[idx],
-                             ssid->wep.len[idx])) {
+           hostapd_drv_set_key(hapd->conf->iface,
+                               hapd, WPA_ALG_WEP, broadcast_ether_addr, idx,
+                               1, NULL, 0, ssid->wep.key[idx],
+                               ssid->wep.len[idx])) {
                wpa_printf(MSG_WARNING, "Could not set WEP encryption.");
                errors++;
        }
@@ -184,9 +202,10 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
                                continue;
 
                        idx = key->idx;
-                       if (hapd->drv.set_key(ifname, hapd, WPA_ALG_WEP, NULL,
-                                             idx, idx == key->idx, NULL, 0,
-                                             key->key[idx], key->len[idx])) {
+                       if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_WEP,
+                                               broadcast_ether_addr, idx, 1,
+                                               NULL, 0, key->key[idx],
+                                               key->len[idx])) {
                                wpa_printf(MSG_WARNING, "Could not set "
                                           "dynamic VLAN WEP encryption.");
                                errors++;
@@ -235,6 +254,15 @@ static void hostapd_cleanup(struct hostapd_data *hapd)
 
        os_free(hapd->probereq_cb);
        hapd->probereq_cb = NULL;
+
+#ifdef CONFIG_P2P
+       wpabuf_free(hapd->p2p_beacon_ie);
+       hapd->p2p_beacon_ie = NULL;
+       wpabuf_free(hapd->p2p_probe_resp_ie);
+       hapd->p2p_probe_resp_ie = NULL;
+#endif /* CONFIG_P2P */
+
+       wpabuf_free(hapd->time_adv);
 }
 
 
@@ -263,6 +291,8 @@ static void hostapd_cleanup_iface(struct hostapd_iface *iface)
        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_config_free(iface->conf);
        iface->conf = NULL;
@@ -284,12 +314,18 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
                return 0;
        }
 
+       /*
+        * When IEEE 802.1X is not enabled, the driver may need to know how to
+        * set authentication algorithms for static WEP.
+        */
+       hostapd_drv_set_authmode(hapd, hapd->conf->auth_algs);
+
        for (i = 0; i < 4; i++) {
                if (hapd->conf->ssid.wep.key[i] &&
-                   hapd->drv.set_key(iface, hapd, WPA_ALG_WEP, NULL, i,
-                                     i == hapd->conf->ssid.wep.idx, NULL, 0,
-                                     hapd->conf->ssid.wep.key[i],
-                                     hapd->conf->ssid.wep.len[i])) {
+                   hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i,
+                                       i == hapd->conf->ssid.wep.idx, NULL, 0,
+                                       hapd->conf->ssid.wep.key[i],
+                                       hapd->conf->ssid.wep.len[i])) {
                        wpa_printf(MSG_WARNING, "Could not set WEP "
                                   "encryption.");
                        return -1;
@@ -306,27 +342,21 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
 static int hostapd_flush_old_stations(struct hostapd_data *hapd)
 {
        int ret = 0;
+       u8 addr[ETH_ALEN];
 
        if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL)
                return 0;
 
-       wpa_printf(MSG_DEBUG, "Flushing old station entries");
+       wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Flushing old station entries");
        if (hostapd_flush(hapd)) {
-               wpa_printf(MSG_WARNING, "Could not connect to kernel driver.");
+               wpa_msg(hapd->msg_ctx, MSG_WARNING, "Could not connect to "
+                       "kernel driver");
                ret = -1;
        }
-       wpa_printf(MSG_DEBUG, "Deauthenticate all stations");
-
-       /* New Prism2.5/3 STA firmware versions seem to have issues with this
-        * broadcast deauth frame. This gets the firmware in odd state where
-        * nothing works correctly, so let's skip sending this for the hostap
-        * driver. */
-       if (hapd->driver && os_strcmp(hapd->driver->name, "hostap") != 0) {
-               u8 addr[ETH_ALEN];
-               os_memset(addr, 0xff, ETH_ALEN);
-               hapd->drv.sta_deauth(hapd, addr,
-                                    WLAN_REASON_PREV_AUTH_NOT_VALID);
-       }
+       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_free_stas(hapd);
 
        return ret;
 }
@@ -344,7 +374,6 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
        u8 mask[ETH_ALEN] = { 0 };
        struct hostapd_data *hapd = iface->bss[0];
        unsigned int i = iface->conf->num_bss, bits = 0, j;
-       int res;
        int auto_addr = 0;
 
        if (hostapd_drv_none(hapd))
@@ -408,17 +437,6 @@ skip_mask_ext:
        wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)",
                   (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits);
 
-       res = hostapd_valid_bss_mask(hapd, hapd->own_addr, mask);
-       if (res == 0)
-               return 0;
-
-       if (res < 0) {
-               wpa_printf(MSG_ERROR, "Driver did not accept BSSID mask "
-                          MACSTR " for start address " MACSTR ".",
-                          MAC2STR(mask), MAC2STR(hapd->own_addr));
-               return -1;
-       }
-
        if (!auto_addr)
                return 0;
 
@@ -495,13 +513,18 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
                hapd->interface_added = 1;
                if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
                                   hapd->conf->iface, hapd->own_addr, hapd,
-                                  &hapd->drv_priv, force_ifname, if_addr)) {
+                                  &hapd->drv_priv, force_ifname, if_addr,
+                                  hapd->conf->bridge[0] ? hapd->conf->bridge :
+                                  NULL)) {
                        wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
                                   MACSTR ")", MAC2STR(hapd->own_addr));
                        return -1;
                }
        }
 
+       if (conf->wmm_enabled < 0)
+               conf->wmm_enabled = hapd->iconf->ieee80211n;
+
        hostapd_flush_old_stations(hapd);
        hostapd_set_privacy(hapd, 0);
 
@@ -611,6 +634,12 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
 
        ieee802_11_set_beacon(hapd);
 
+       if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
+               return -1;
+
+       if (hapd->driver && hapd->driver->set_operstate)
+               hapd->driver->set_operstate(hapd->drv_priv, 1);
+
        return 0;
 }
 
@@ -624,9 +653,6 @@ static void hostapd_tx_queue_params(struct hostapd_iface *iface)
        for (i = 0; i < NUM_TX_QUEUES; i++) {
                p = &iface->conf->tx_queue[i];
 
-               if (!p->configured)
-                       continue;
-
                if (hostapd_set_tx_queue_params(hapd, i, p->aifs, p->cwmin,
                                                p->cwmax, p->burst)) {
                        wpa_printf(MSG_DEBUG, "Failed to set TX queue "
@@ -717,6 +743,17 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
                }
        }
 
+       if (iface->current_mode) {
+               if (hostapd_prepare_rates(iface, iface->current_mode)) {
+                       wpa_printf(MSG_ERROR, "Failed to prepare rates "
+                                  "table.");
+                       hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+                                      HOSTAPD_LEVEL_WARNING,
+                                      "Failed to prepare rates table.");
+                       return -1;
+               }
+       }
+
        if (hapd->iconf->rts_threshold > -1 &&
            hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) {
                wpa_printf(MSG_ERROR, "Could not set RTS threshold for "
@@ -753,6 +790,20 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
                return -1;
        }
 
+       /*
+        * WPS UPnP module can be initialized only when the "upnp_iface" is up.
+        * If "interface" and "upnp_iface" are the same (e.g., non-bridge
+        * mode), the interface is up only after driver_commit, so initialize
+        * WPS after driver_commit.
+        */
+       for (j = 0; j < iface->num_bss; j++) {
+               if (hostapd_init_wps_complete(iface->bss[j]))
+                       return -1;
+       }
+
+       if (hapd->setup_complete_cb)
+               hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
+
        wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
                   iface->bss[0]->conf->iface);
 
@@ -807,7 +858,6 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
        if (hapd == NULL)
                return NULL;
 
-       hostapd_set_driver_ops(&hapd->drv);
        hapd->new_assoc_sta_cb = hostapd_new_assoc_sta;
        hapd->iconf = conf;
        hapd->conf = bss;
@@ -859,8 +909,8 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
                           int reassoc)
 {
        if (hapd->tkip_countermeasures) {
-               hapd->drv.sta_deauth(hapd, sta->addr,
-                                    WLAN_REASON_MICHAEL_MIC_FAILURE);
+               hostapd_drv_sta_deauth(hapd, sta->addr,
+                                      WLAN_REASON_MICHAEL_MIC_FAILURE);
                return;
        }
 
@@ -870,6 +920,15 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
        if (hapd->conf->ieee802_11f)
                iapp_new_station(hapd->iapp, sta);
 
+#ifdef CONFIG_P2P
+       if (sta->p2p_ie == NULL && !sta->no_p2p_set) {
+               sta->no_p2p_set = 1;
+               hapd->num_sta_no_p2p++;
+               if (hapd->num_sta_no_p2p == 1)
+                       hostapd_p2p_non_p2p_sta_connected(hapd);
+       }
+#endif /* CONFIG_P2P */
+
        /* Start accounting here, if IEEE 802.1X and WPA are not used.
         * IEEE 802.1X/WPA code will start accounting after the station has
         * been authorized. */
index d0d67c8..5b72768 100644 (file)
@@ -27,9 +27,12 @@ struct sta_info;
 struct hostap_sta_driver_data;
 struct ieee80211_ht_capabilities;
 struct full_dynamic_vlan;
+enum wps_event;
+union wps_event_data;
 
 struct hostapd_probereq_cb {
-       int (*cb)(void *ctx, const u8 *sa, const u8 *ie, size_t ie_len);
+       int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid,
+                 const u8 *ie, size_t ie_len);
        void *ctx;
 };
 
@@ -47,55 +50,6 @@ struct hostapd_frame_info {
 };
 
 
-struct hostapd_driver_ops {
-       int (*set_ap_wps_ie)(struct hostapd_data *hapd);
-       int (*send_mgmt_frame)(struct hostapd_data *hapd, const void *msg,
-                              size_t len);
-       int (*send_eapol)(struct hostapd_data *hapd, const u8 *addr,
-                         const u8 *data, size_t data_len, int encrypt);
-       int (*set_authorized)(struct hostapd_data *hapd, struct sta_info *sta,
-                             int authorized);
-       int (*set_key)(const char *ifname, struct hostapd_data *hapd,
-                      enum wpa_alg alg, const u8 *addr, int key_idx,
-                      int set_tx, const u8 *seq, size_t seq_len,
-                      const u8 *key, size_t key_len);
-       int (*read_sta_data)(struct hostapd_data *hapd,
-                            struct hostap_sta_driver_data *data,
-                            const u8 *addr);
-       int (*sta_clear_stats)(struct hostapd_data *hapd, const u8 *addr);
-       int (*set_sta_flags)(struct hostapd_data *hapd, struct sta_info *sta);
-       int (*set_drv_ieee8021x)(struct hostapd_data *hapd, const char *ifname,
-                                int enabled);
-       int (*set_radius_acl_auth)(struct hostapd_data *hapd,
-                                  const u8 *mac, int accepted,
-                                  u32 session_timeout);
-       int (*set_radius_acl_expire)(struct hostapd_data *hapd,
-                                    const u8 *mac);
-       int (*set_bss_params)(struct hostapd_data *hapd, int use_protection);
-       int (*set_beacon)(struct hostapd_data *hapd,
-                         const u8 *head, size_t head_len,
-                         const u8 *tail, size_t tail_len, int dtim_period,
-                         int beacon_int);
-       int (*vlan_if_add)(struct hostapd_data *hapd, const char *ifname);
-       int (*vlan_if_remove)(struct hostapd_data *hapd, const char *ifname);
-       int (*set_wds_sta)(struct hostapd_data *hapd, const u8 *addr, int aid,
-                          int val);
-       int (*set_sta_vlan)(const char *ifname, struct hostapd_data *hapd,
-                           const u8 *addr, int vlan_id);
-       int (*get_inact_sec)(struct hostapd_data *hapd, const u8 *addr);
-       int (*sta_deauth)(struct hostapd_data *hapd, const u8 *addr,
-                         int reason);
-       int (*sta_disassoc)(struct hostapd_data *hapd, const u8 *addr,
-                           int reason);
-       int (*sta_add)(struct hostapd_data *hapd,
-                      const u8 *addr, u16 aid, u16 capability,
-                      const u8 *supp_rates, size_t supp_rates_len,
-                      u16 listen_interval,
-                      const struct ieee80211_ht_capabilities *ht_capab);
-       int (*sta_remove)(struct hostapd_data *hapd, const u8 *addr);
-       int (*set_countermeasures)(struct hostapd_data *hapd, int enabled);
-};
-
 /**
  * struct hostapd_data - hostapd per-BSS data structure
  */
@@ -123,12 +77,12 @@ struct hostapd_data {
 
        const struct wpa_driver_ops *driver;
        void *drv_priv;
-       struct hostapd_driver_ops drv;
 
        void (*new_assoc_sta_cb)(struct hostapd_data *hapd,
                                 struct sta_info *sta, int reassoc);
 
        void *msg_ctx; /* ctx for wpa_msg() calls */
+       void *msg_ctx_parent; /* parent interface ctx for wpa_msg() calls */
 
        struct radius_client_data *radius;
        u32 acct_session_id_hi, acct_session_id_lo;
@@ -155,6 +109,10 @@ struct hostapd_data {
 
        int parameter_set_count;
 
+       /* Time Advertisement */
+       u8 time_update_counter;
+       struct wpabuf *time_adv;
+
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
        struct full_dynamic_vlan *full_dynamic_vlan;
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
@@ -162,6 +120,7 @@ struct hostapd_data {
        struct l2_packet_data *l2;
        struct wps_context *wps;
 
+       int beacon_set_done;
        struct wpabuf *wps_beacon_ie;
        struct wpabuf *wps_probe_resp_ie;
 #ifdef CONFIG_WPS
@@ -177,9 +136,39 @@ struct hostapd_data {
                                 int freq);
        void *public_action_cb_ctx;
 
+       int (*vendor_action_cb)(void *ctx, const u8 *buf, size_t len,
+                               int freq);
+       void *vendor_action_cb_ctx;
+
        void (*wps_reg_success_cb)(void *ctx, const u8 *mac_addr,
                                   const u8 *uuid_e);
        void *wps_reg_success_cb_ctx;
+
+       void (*wps_event_cb)(void *ctx, enum wps_event event,
+                            union wps_event_data *data);
+       void *wps_event_cb_ctx;
+
+       void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr,
+                                 int authorized);
+       void *sta_authorized_cb_ctx;
+
+       void (*setup_complete_cb)(void *ctx);
+       void *setup_complete_cb_ctx;
+
+#ifdef CONFIG_P2P
+       struct p2p_data *p2p;
+       struct p2p_group *p2p_group;
+       struct wpabuf *p2p_beacon_ie;
+       struct wpabuf *p2p_probe_resp_ie;
+
+       /* Number of non-P2P association stations */
+       int num_sta_no_p2p;
+
+       /* Periodic NoA (used only when no non-P2P clients in the group) */
+       int noa_enabled;
+       int noa_start;
+       int noa_duration;
+#endif /* CONFIG_P2P */
 };
 
 
@@ -202,6 +191,14 @@ struct hostapd_iface {
        struct ap_info *ap_hash[STA_HASH_SIZE];
        struct ap_info *ap_iter_list;
 
+       unsigned int drv_flags;
+
+       /*
+        * A bitmap of supported protocols for probe response offload. See
+        * struct wpa_driver_capa in driver.h
+        */
+       unsigned int probe_resp_offloads;
+
        struct hostapd_hw_modes *hw_features;
        int num_hw_features;
        struct hostapd_hw_modes *current_mode;
@@ -209,6 +206,7 @@ struct hostapd_iface {
         * current_mode->channels */
        int num_rates;
        struct hostapd_rate_data *current_rates;
+       int *basic_rates;
        int freq;
 
        u16 hw_flags;
@@ -264,13 +262,17 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
 /* 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),
                                 void *ctx);
 void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
 
 /* drv_callbacks.c (TODO: move to somewhere else?) */
 int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
-                       const u8 *ie, size_t ielen);
+                       const u8 *ie, size_t ielen, int reassoc);
 void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
+void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
+int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
+                        const u8 *bssid, const u8 *ie, size_t ie_len);
 
 #endif /* HOSTAPD_H */
index 0159c72..8c6fef2 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-2009, Jouni Malinen <j@w1.fi>
+ * 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
@@ -101,8 +101,8 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
 }
 
 
-static int hostapd_prepare_rates(struct hostapd_data *hapd,
-                                struct hostapd_hw_modes *mode)
+int hostapd_prepare_rates(struct hostapd_iface *iface,
+                         struct hostapd_hw_modes *mode)
 {
        int i, num_basic_rates = 0;
        int basic_rates_a[] = { 60, 120, 240, -1 };
@@ -110,8 +110,8 @@ static int hostapd_prepare_rates(struct hostapd_data *hapd,
        int basic_rates_g[] = { 10, 20, 55, 110, -1 };
        int *basic_rates;
 
-       if (hapd->iconf->basic_rates)
-               basic_rates = hapd->iconf->basic_rates;
+       if (iface->conf->basic_rates)
+               basic_rates = iface->conf->basic_rates;
        else switch (mode->mode) {
        case HOSTAPD_MODE_IEEE80211A:
                basic_rates = basic_rates_a;
@@ -126,18 +126,20 @@ static int hostapd_prepare_rates(struct hostapd_data *hapd,
                return -1;
        }
 
-       if (hostapd_set_rate_sets(hapd, hapd->iconf->supported_rates,
-                                 basic_rates, mode->mode)) {
-               wpa_printf(MSG_ERROR, "Failed to update rate sets in kernel "
-                          "module");
-       }
+       i = 0;
+       while (basic_rates[i] >= 0)
+               i++;
+       os_free(iface->basic_rates);
+       iface->basic_rates = os_malloc(i * sizeof(int));
+       if (iface->basic_rates)
+               os_memcpy(iface->basic_rates, basic_rates, i * sizeof(int));
 
-       os_free(hapd->iface->current_rates);
-       hapd->iface->num_rates = 0;
+       os_free(iface->current_rates);
+       iface->num_rates = 0;
 
-       hapd->iface->current_rates =
+       iface->current_rates =
                os_zalloc(mode->num_rates * sizeof(struct hostapd_rate_data));
-       if (!hapd->iface->current_rates) {
+       if (!iface->current_rates) {
                wpa_printf(MSG_ERROR, "Failed to allocate memory for rate "
                           "table.");
                return -1;
@@ -146,26 +148,27 @@ static int hostapd_prepare_rates(struct hostapd_data *hapd,
        for (i = 0; i < mode->num_rates; i++) {
                struct hostapd_rate_data *rate;
 
-               if (hapd->iconf->supported_rates &&
-                   !hostapd_rate_found(hapd->iconf->supported_rates,
+               if (iface->conf->supported_rates &&
+                   !hostapd_rate_found(iface->conf->supported_rates,
                                        mode->rates[i]))
                        continue;
 
-               rate = &hapd->iface->current_rates[hapd->iface->num_rates];
+               rate = &iface->current_rates[iface->num_rates];
                rate->rate = mode->rates[i];
                if (hostapd_rate_found(basic_rates, rate->rate)) {
                        rate->flags |= HOSTAPD_RATE_BASIC;
                        num_basic_rates++;
                }
                wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x",
-                          hapd->iface->num_rates, rate->rate, rate->flags);
-               hapd->iface->num_rates++;
+                          iface->num_rates, rate->rate, rate->flags);
+               iface->num_rates++;
        }
 
-       if (hapd->iface->num_rates == 0 || num_basic_rates == 0) {
+       if ((iface->num_rates == 0 || num_basic_rates == 0) &&
+           (!iface->conf->ieee80211n || !iface->conf->require_ht)) {
                wpa_printf(MSG_ERROR, "No rates remaining in supported/basic "
                           "rate sets (%d,%d).",
-                          hapd->iface->num_rates, num_basic_rates);
+                          iface->num_rates, num_basic_rates);
                return -1;
        }
 
@@ -265,11 +268,11 @@ static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss,
                oper = (struct ieee80211_ht_operation *) elems.ht_operation;
                *pri_chan = oper->control_chan;
                if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) {
-                       if (oper->ht_param &
-                           HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+                       int sec = oper->ht_param &
+                               HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
+                       if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
                                *sec_chan = *pri_chan + 4;
-                       else if (oper->ht_param &
-                                HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+                       else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
                                *sec_chan = *pri_chan - 4;
                }
        }
@@ -406,24 +409,11 @@ static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface,
 }
 
 
-static void wpa_scan_results_free(struct wpa_scan_results *res)
-{
-       size_t i;
-
-       if (res == NULL)
-               return;
-
-       for (i = 0; i < res->num; i++)
-               os_free(res->res[i]);
-       os_free(res->res);
-       os_free(res);
-}
-
-
 static void ieee80211n_check_scan(struct hostapd_iface *iface)
 {
        struct wpa_scan_results *scan_res;
        int oper40;
+       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 */
@@ -452,7 +442,8 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
                iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
        }
 
-       hostapd_setup_interface_complete(iface, 0);
+       res = ieee80211n_allowed_ht40_channel_pair(iface);
+       hostapd_setup_interface_complete(iface, !res);
 }
 
 
@@ -483,9 +474,6 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
        u16 hw = iface->current_mode->ht_capab;
        u16 conf = iface->conf->ht_capab;
 
-       if (!iface->conf->ieee80211n)
-               return 1;
-
        if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) &&
            !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) {
                wpa_printf(MSG_ERROR, "Driver does not support configured "
@@ -585,13 +573,15 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
 {
 #ifdef CONFIG_IEEE80211N
        int ret;
+       if (!iface->conf->ieee80211n)
+               return 0;
+       if (!ieee80211n_supported_ht_capab(iface))
+               return -1;
        ret = ieee80211n_check_40mhz(iface);
        if (ret)
                return ret;
        if (!ieee80211n_allowed_ht40_channel_pair(iface))
                return -1;
-       if (!ieee80211n_supported_ht_capab(iface))
-               return -1;
 #endif /* CONFIG_IEEE80211N */
 
        return 0;
@@ -601,7 +591,7 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
 /**
  * hostapd_select_hw_mode - Select the hardware mode
  * @iface: Pointer to interface data.
- * Returns: 0 on success, -1 on failure
+ * Returns: 0 on success, < 0 on failure
  *
  * Sets up the hardware mode, channel, rates, and passive scanning
  * based on the configuration.
@@ -628,18 +618,58 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
                hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_WARNING,
                               "Hardware does not support configured mode "
-                              "(%d)", (int) iface->conf->hw_mode);
-               return -1;
+                              "(%d) (hw_mode in hostapd.conf)",
+                              (int) iface->conf->hw_mode);
+               return -2;
        }
 
        ok = 0;
        for (j = 0; j < iface->current_mode->num_channels; j++) {
                struct hostapd_channel_data *chan =
                        &iface->current_mode->channels[j];
-               if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
-                   (chan->chan == iface->conf->channel)) {
-                       ok = 1;
-                       break;
+               if (chan->chan == iface->conf->channel) {
+                       if (chan->flag & HOSTAPD_CHAN_DISABLED) {
+                               wpa_printf(MSG_ERROR,
+                                          "channel [%i] (%i) is disabled for "
+                                          "use in AP mode, flags: 0x%x%s%s%s",
+                                          j, chan->chan, chan->flag,
+                                          chan->flag & HOSTAPD_CHAN_NO_IBSS ?
+                                          " NO-IBSS" : "",
+                                          chan->flag &
+                                          HOSTAPD_CHAN_PASSIVE_SCAN ?
+                                          " PASSIVE-SCAN" : "",
+                                          chan->flag & HOSTAPD_CHAN_RADAR ?
+                                          " RADAR" : "");
+                       } else {
+                               ok = 1;
+                               break;
+                       }
+               }
+       }
+       if (ok && iface->conf->secondary_channel) {
+               int sec_ok = 0;
+               int sec_chan = iface->conf->channel +
+                       iface->conf->secondary_channel * 4;
+               for (j = 0; j < iface->current_mode->num_channels; j++) {
+                       struct hostapd_channel_data *chan =
+                               &iface->current_mode->channels[j];
+                       if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+                           (chan->chan == sec_chan)) {
+                               sec_ok = 1;
+                               break;
+                       }
+               }
+               if (!sec_ok) {
+                       hostapd_logger(iface->bss[0], NULL,
+                                      HOSTAPD_MODULE_IEEE80211,
+                                      HOSTAPD_LEVEL_WARNING,
+                                      "Configured HT40 secondary channel "
+                                      "(%d) not found from the channel list "
+                                      "of current mode (%d) %s",
+                                      sec_chan, iface->current_mode->mode,
+                                      hostapd_hw_mode_txt(
+                                              iface->current_mode->mode));
+                       ok = 0;
                }
        }
        if (iface->conf->channel == 0) {
@@ -647,7 +677,7 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
                 * the channel automatically */
                wpa_printf(MSG_ERROR, "Channel not configured "
                           "(hw_mode/channel in hostapd.conf)");
-               return -1;
+               return -3;
        }
        if (ok == 0 && iface->conf->channel != 0) {
                hostapd_logger(iface->bss[0], NULL,
@@ -665,15 +695,7 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
                hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_WARNING,
                               "Hardware does not support configured channel");
-               return -1;
-       }
-
-       if (hostapd_prepare_rates(iface->bss[0], iface->current_mode)) {
-               wpa_printf(MSG_ERROR, "Failed to prepare rates table.");
-               hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
-                                          HOSTAPD_LEVEL_WARNING,
-                                          "Failed to prepare rates table.");
-               return -1;
+               return -4;
        }
 
        return 0;
index 0295549..abadcd1 100644 (file)
@@ -2,6 +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>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -25,6 +26,8 @@ const char * hostapd_hw_mode_txt(int mode);
 int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
 int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
 int hostapd_check_ht_capab(struct hostapd_iface *iface);
+int hostapd_prepare_rates(struct hostapd_iface *iface,
+                         struct hostapd_hw_modes *mode);
 #else /* NEED_AP_MLME */
 static inline void
 hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
@@ -39,7 +42,7 @@ static inline int hostapd_get_hw_features(struct hostapd_iface *iface)
 
 static inline int hostapd_select_hw_mode(struct hostapd_iface *iface)
 {
-       return -1;
+       return -100;
 }
 
 static inline const char * hostapd_hw_mode_txt(int mode)
@@ -57,6 +60,12 @@ static inline int hostapd_check_ht_capab(struct hostapd_iface *iface)
        return 0;
 }
 
+static inline int hostapd_prepare_rates(struct hostapd_iface *iface,
+                                       struct hostapd_hw_modes *mode)
+{
+       return 0;
+}
+
 #endif /* NEED_AP_MLME */
 
 #endif /* HW_FEATURES_H */
index 3375aa2..a1a7270 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / IEEE 802.11 Management
- * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ * 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
@@ -25,6 +25,7 @@
 #include "common/wpa_ctrl.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
+#include "p2p/p2p.h"
 #include "wps/wps.h"
 #include "hostapd.h"
 #include "beacon.h"
@@ -37,6 +38,8 @@
 #include "accounting.h"
 #include "ap_config.h"
 #include "ap_mlme.h"
+#include "p2p_hostapd.h"
+#include "ap_drv_ops.h"
 #include "ieee802_11.h"
 
 
@@ -50,6 +53,8 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
 
        *pos++ = WLAN_EID_SUPP_RATES;
        num = hapd->iface->num_rates;
+       if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
+               num++;
        if (num > 8) {
                /* rest of the rates are encoded in Extended supported
                 * rates element */
@@ -67,6 +72,10 @@ 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)
+               *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
+
        return pos;
 }
 
@@ -80,6 +89,8 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
                return eid;
 
        num = hapd->iface->num_rates;
+       if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
+               num++;
        if (num <= 8)
                return eid;
        num -= 8;
@@ -98,6 +109,10 @@ 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;
+
        return pos;
 }
 
@@ -148,34 +163,6 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
 }
 
 
-#ifdef CONFIG_IEEE80211W
-static u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
-                                           struct sta_info *sta, u8 *eid)
-{
-       u8 *pos = eid;
-       u32 timeout, tu;
-       struct os_time now, passed;
-
-       *pos++ = WLAN_EID_TIMEOUT_INTERVAL;
-       *pos++ = 5;
-       *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
-       os_get_time(&now);
-       os_time_sub(&now, &sta->sa_query_start, &passed);
-       tu = (passed.sec * 1000000 + passed.usec) / 1024;
-       if (hapd->conf->assoc_sa_query_max_timeout > tu)
-               timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
-       else
-               timeout = 0;
-       if (timeout < hapd->conf->assoc_sa_query_max_timeout)
-               timeout++; /* add some extra time for local timers */
-       WPA_PUT_LE32(pos, timeout);
-       pos += 4;
-
-       return pos;
-}
-#endif /* CONFIG_IEEE80211W */
-
-
 void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len)
 {
        int i;
@@ -204,15 +191,15 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
                if (!sta->challenge) {
                        /* Generate a pseudo-random challenge */
                        u8 key[8];
-                       time_t now;
+                       struct os_time now;
                        int r;
                        sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN);
                        if (sta->challenge == NULL)
                                return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
-                       now = time(NULL);
-                       r = random();
-                       os_memcpy(key, &now, 4);
+                       os_get_time(&now);
+                       r = os_random();
+                       os_memcpy(key, &now.sec, 4);
                        os_memcpy(key + 4, &r, 4);
                        rc4_skip(key, sizeof(key), 0,
                                 sta->challenge, WLAN_AUTH_CHALLENGE_LEN);
@@ -282,7 +269,7 @@ static void send_auth_reply(struct hostapd_data *hapd,
                   " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)",
                   MAC2STR(dst), auth_alg, auth_transaction,
                   resp, (unsigned long) ies_len);
-       if (hapd->drv.send_mgmt_frame(hapd, reply, rlen) < 0)
+       if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
                perror("send_auth_reply: send");
 
        os_free(buf);
@@ -326,6 +313,8 @@ 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;
        u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
        size_t resp_ies_len = 0;
 
@@ -360,9 +349,7 @@ static void handle_auth(struct hostapd_data *hapd,
        if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
               auth_alg == WLAN_AUTH_OPEN) ||
 #ifdef CONFIG_IEEE80211R
-             (hapd->conf->wpa &&
-              (hapd->conf->wpa_key_mgmt &
-               (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) &&
+             (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
               auth_alg == WLAN_AUTH_FT) ||
 #endif /* CONFIG_IEEE80211R */
              ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
@@ -390,7 +377,9 @@ 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);
+                                     &acct_interim_interval, &vlan_id,
+                                     psk, &has_psk);
+
        if (res == HOSTAPD_ACL_REJECT) {
                printf("Station " MACSTR " not allowed to authenticate.\n",
                       MAC2STR(mgmt->sa));
@@ -428,6 +417,16 @@ 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);
+       } else {
+               os_free(sta->psk);
+               sta->psk = NULL;
+       }
+
        sta->flags &= ~WLAN_STA_PREAUTH;
        ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
 
@@ -552,15 +551,22 @@ static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta,
                     const u8 *wmm_ie, size_t wmm_ie_len)
 {
        sta->flags &= ~WLAN_STA_WMM;
+       sta->qosinfo = 0;
        if (wmm_ie && hapd->conf->wmm_enabled) {
-               if (hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len))
+               struct wmm_information_element *wmm;
+
+               if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) {
                        hostapd_logger(hapd, sta->addr,
                                       HOSTAPD_MODULE_WPA,
                                       HOSTAPD_LEVEL_DEBUG,
                                       "invalid WMM element in association "
                                       "request");
-               else
-                       sta->flags |= WLAN_STA_WMM;
+                       return WLAN_STATUS_UNSPECIFIED_FAILURE;
+               }
+
+               sta->flags |= WLAN_STA_WMM;
+               wmm = (struct wmm_information_element *) wmm_ie;
+               sta->qosinfo = wmm->qos_info;
        }
        return WLAN_STATUS_SUCCESS;
 }
@@ -635,10 +641,17 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
        if (resp != WLAN_STATUS_SUCCESS)
                return resp;
 #ifdef CONFIG_IEEE80211N
-       resp = copy_sta_ht_capab(sta, elems.ht_capabilities,
+       resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities,
                                 elems.ht_capabilities_len);
        if (resp != WLAN_STATUS_SUCCESS)
                return resp;
+       if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
+           !(sta->flags & WLAN_STA_HT)) {
+               hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+                              HOSTAPD_LEVEL_INFO, "Station does not support "
+                              "mandatory HT PHY - reject association");
+               return WLAN_STATUS_ASSOC_DENIED_NO_HT;
+       }
 #endif /* CONFIG_IEEE80211N */
 
        if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) {
@@ -654,7 +667,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
        }
 
 #ifdef CONFIG_WPS
-       sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
+       sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
        if (hapd->conf->wps_state && elems.wps_ie) {
                wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
                           "Request - assume WPS is used");
@@ -662,8 +675,17 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                wpabuf_free(sta->wps_ie);
                sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
                                                          WPS_IE_VENDOR_TYPE);
+               if (sta->wps_ie && wps_is_20(sta->wps_ie)) {
+                       wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0");
+                       sta->flags |= WLAN_STA_WPS2;
+               }
                wpa_ie = NULL;
                wpa_ie_len = 0;
+               if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) {
+                       wpa_printf(MSG_DEBUG, "WPS: Invalid WPS IE in "
+                                  "(Re)Association Request - reject");
+                       return WLAN_STATUS_INVALID_IE;
+               }
        } else if (hapd->conf->wps_state && wpa_ie == NULL) {
                wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in "
                           "(Re)Association Request - possible WPS use");
@@ -768,6 +790,20 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
        } else
                wpa_auth_sta_no_wpa(sta->wpa_sm);
 
+#ifdef CONFIG_P2P
+       if (elems.p2p) {
+               wpabuf_free(sta->p2p_ie);
+               sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
+                                                         P2P_IE_VENDOR_TYPE);
+
+       } else {
+               wpabuf_free(sta->p2p_ie);
+               sta->p2p_ie = NULL;
+       }
+
+       p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len);
+#endif /* CONFIG_P2P */
+
        return WLAN_STATUS_SUCCESS;
 }
 
@@ -788,7 +824,7 @@ static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
        send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
        reply.u.deauth.reason_code = host_to_le16(reason_code);
 
-       if (hapd->drv.send_mgmt_frame(hapd, &reply, send_len) < 0)
+       if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0) < 0)
                wpa_printf(MSG_INFO, "Failed to send deauth: %s",
                           strerror(errno));
 }
@@ -845,11 +881,14 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
        p = hostapd_eid_ht_operation(hapd, p);
 #endif /* CONFIG_IEEE80211N */
 
+       p = hostapd_eid_ext_capab(hapd, p);
+
        if (sta->flags & WLAN_STA_WMM)
                p = hostapd_eid_wmm(hapd, p);
 
 #ifdef CONFIG_WPS
-       if (sta->flags & WLAN_STA_WPS) {
+       if ((sta->flags & WLAN_STA_WPS) ||
+           ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa)) {
                struct wpabuf *wps = wps_build_assoc_resp_ie();
                if (wps) {
                        os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
@@ -859,9 +898,39 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
        }
 #endif /* CONFIG_WPS */
 
+#ifdef CONFIG_P2P
+       if (sta->p2p_ie) {
+               struct wpabuf *p2p_resp_ie;
+               enum p2p_status_code status;
+               switch (status_code) {
+               case WLAN_STATUS_SUCCESS:
+                       status = P2P_SC_SUCCESS;
+                       break;
+               case WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
+                       status = P2P_SC_FAIL_LIMIT_REACHED;
+                       break;
+               default:
+                       status = P2P_SC_FAIL_INVALID_PARAMS;
+                       break;
+               }
+               p2p_resp_ie = p2p_group_assoc_resp_ie(hapd->p2p_group, status);
+               if (p2p_resp_ie) {
+                       os_memcpy(p, wpabuf_head(p2p_resp_ie),
+                                 wpabuf_len(p2p_resp_ie));
+                       p += wpabuf_len(p2p_resp_ie);
+                       wpabuf_free(p2p_resp_ie);
+               }
+       }
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_P2P_MANAGER
+       if (hapd->conf->p2p & P2P_MANAGE)
+               p = hostapd_eid_p2p_manage(hapd, p);
+#endif /* CONFIG_P2P_MANAGER */
+
        send_len += p - reply->u.assoc_resp.variable;
 
-       if (hapd->drv.send_mgmt_frame(hapd, reply, send_len) < 0)
+       if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0)
                wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
                           strerror(errno));
 }
@@ -1005,6 +1074,7 @@ static void handle_assoc(struct hostapd_data *hapd,
                       "association OK (aid %d)", sta->aid);
        /* Station will be marked associated, after it acknowledges AssocResp
         */
+       sta->flags |= WLAN_STA_ASSOC_REQ_OK;
 
 #ifdef CONFIG_IEEE80211W
        if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
@@ -1061,9 +1131,8 @@ static void handle_disassoc(struct hostapd_data *hapd,
                return;
        }
 
-       sta->flags &= ~WLAN_STA_ASSOC;
-       wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-               MAC2STR(sta->addr));
+       ap_sta_set_authorized(hapd, sta, 0);
+       sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
        wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
        hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
                       HOSTAPD_LEVEL_INFO, "disassociated");
@@ -1073,7 +1142,7 @@ static void handle_disassoc(struct hostapd_data *hapd,
         * authenticated. */
        accounting_sta_stop(hapd, sta);
        ieee802_1x_free_station(sta);
-       hapd->drv.sta_remove(hapd, sta->addr);
+       hostapd_drv_sta_remove(hapd, sta->addr);
 
        if (sta->timeout_next == STA_NULLFUNC ||
            sta->timeout_next == STA_DISASSOC) {
@@ -1094,26 +1163,26 @@ static void handle_deauth(struct hostapd_data *hapd,
        struct sta_info *sta;
 
        if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) {
-               printf("handle_deauth - too short payload (len=%lu)\n",
-                      (unsigned long) len);
+               wpa_msg(hapd->msg_ctx, MSG_DEBUG, "handle_deauth - too short "
+                       "payload (len=%lu)", (unsigned long) len);
                return;
        }
 
-       wpa_printf(MSG_DEBUG, "deauthentication: STA=" MACSTR
-                  " reason_code=%d",
-                  MAC2STR(mgmt->sa),
-                  le_to_host16(mgmt->u.deauth.reason_code));
+       wpa_msg(hapd->msg_ctx, MSG_DEBUG, "deauthentication: STA=" MACSTR
+               " reason_code=%d",
+               MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code));
 
        sta = ap_get_sta(hapd, mgmt->sa);
        if (sta == NULL) {
-               printf("Station " MACSTR " trying to deauthenticate, but it "
-                      "is not authenticated.\n", MAC2STR(mgmt->sa));
+               wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying "
+                       "to deauthenticate, but it is not authenticated",
+                       MAC2STR(mgmt->sa));
                return;
        }
 
-       sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
-       wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-               MAC2STR(sta->addr));
+       ap_sta_set_authorized(hapd, sta, 0);
+       sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
+                       WLAN_STA_ASSOC_REQ_OK);
        wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
        hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
                       HOSTAPD_LEVEL_DEBUG, "deauthenticated");
@@ -1148,81 +1217,11 @@ static void handle_beacon(struct hostapd_data *hapd,
 
 #ifdef CONFIG_IEEE80211W
 
-/* MLME-SAQuery.request */
-void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
-                                 const u8 *addr, const u8 *trans_id)
-{
-       struct ieee80211_mgmt mgmt;
-       u8 *end;
-
-       wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
-                  MACSTR, MAC2STR(addr));
-       wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
-                   trans_id, WLAN_SA_QUERY_TR_ID_LEN);
-
-       os_memset(&mgmt, 0, sizeof(mgmt));
-       mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-                                         WLAN_FC_STYPE_ACTION);
-       os_memcpy(mgmt.da, addr, ETH_ALEN);
-       os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
-       os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
-       mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
-       mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
-       os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
-                 WLAN_SA_QUERY_TR_ID_LEN);
-       end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
-       if (hapd->drv.send_mgmt_frame(hapd, &mgmt, end - (u8 *) &mgmt) < 0)
-               perror("ieee802_11_send_sa_query_req: send");
-}
-
-
-static void hostapd_sa_query_request(struct hostapd_data *hapd,
-                                    const struct ieee80211_mgmt *mgmt)
-{
-       struct sta_info *sta;
-       struct ieee80211_mgmt resp;
-       u8 *end;
-
-       wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
-                  MACSTR, MAC2STR(mgmt->sa));
-       wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
-                   mgmt->u.action.u.sa_query_resp.trans_id,
-                   WLAN_SA_QUERY_TR_ID_LEN);
-
-       sta = ap_get_sta(hapd, mgmt->sa);
-       if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
-               wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request "
-                          "from unassociated STA " MACSTR, MAC2STR(mgmt->sa));
-               return;
-       }
-
-       wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
-                  MACSTR, MAC2STR(mgmt->sa));
-
-       os_memset(&resp, 0, sizeof(resp));
-       resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-                                         WLAN_FC_STYPE_ACTION);
-       os_memcpy(resp.da, mgmt->sa, ETH_ALEN);
-       os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
-       os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
-       resp.u.action.category = WLAN_ACTION_SA_QUERY;
-       resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
-       os_memcpy(resp.u.action.u.sa_query_req.trans_id,
-                 mgmt->u.action.u.sa_query_req.trans_id,
-                 WLAN_SA_QUERY_TR_ID_LEN);
-       end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
-       if (hapd->drv.send_mgmt_frame(hapd, &resp, end - (u8 *) &resp) < 0)
-               perror("hostapd_sa_query_request: send");
-}
-
-
 static void hostapd_sa_query_action(struct hostapd_data *hapd,
                                    const struct ieee80211_mgmt *mgmt,
                                    size_t len)
 {
-       struct sta_info *sta;
        const u8 *end;
-       int i;
 
        end = mgmt->u.action.u.sa_query_resp.trans_id +
                WLAN_SA_QUERY_TR_ID_LEN;
@@ -1232,50 +1231,9 @@ static void hostapd_sa_query_action(struct hostapd_data *hapd,
                return;
        }
 
-       if (mgmt->u.action.u.sa_query_resp.action == WLAN_SA_QUERY_REQUEST) {
-               hostapd_sa_query_request(hapd, mgmt);
-               return;
-       }
-
-       if (mgmt->u.action.u.sa_query_resp.action != WLAN_SA_QUERY_RESPONSE) {
-               wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query "
-                          "Action %d", mgmt->u.action.u.sa_query_resp.action);
-               return;
-       }
-
-       wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from "
-                  MACSTR, MAC2STR(mgmt->sa));
-       wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
-                   mgmt->u.action.u.sa_query_resp.trans_id,
-                   WLAN_SA_QUERY_TR_ID_LEN);
-
-       /* MLME-SAQuery.confirm */
-
-       sta = ap_get_sta(hapd, mgmt->sa);
-       if (sta == NULL || sta->sa_query_trans_id == NULL) {
-               wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
-                          "pending SA Query request found");
-               return;
-       }
-
-       for (i = 0; i < sta->sa_query_count; i++) {
-               if (os_memcmp(sta->sa_query_trans_id +
-                             i * WLAN_SA_QUERY_TR_ID_LEN,
-                             mgmt->u.action.u.sa_query_resp.trans_id,
-                             WLAN_SA_QUERY_TR_ID_LEN) == 0)
-                       break;
-       }
-
-       if (i >= sta->sa_query_count) {
-               wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query "
-                          "transaction identifier found");
-               return;
-       }
-
-       hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-                      HOSTAPD_LEVEL_DEBUG,
-                      "Reply to pending SA Query received");
-       ap_sta_stop_sa_query(hapd, sta);
+       ieee802_11_sa_query_action(hapd, mgmt->sa,
+                                  mgmt->u.action.u.sa_query_resp.action,
+                                  mgmt->u.action.u.sa_query_resp.trans_id);
 }
 
 
@@ -1290,7 +1248,10 @@ static int robust_action_frame(u8 category)
 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,
@@ -1300,7 +1261,6 @@ static void handle_action(struct hostapd_data *hapd,
                return;
        }
 
-       sta = ap_get_sta(hapd, mgmt->sa);
 #ifdef CONFIG_IEEE80211W
        if (sta && (sta->flags & WLAN_STA_MFP) &&
            !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) &&
@@ -1347,6 +1307,14 @@ static void handle_action(struct hostapd_data *hapd,
                        return;
                }
                break;
+       case WLAN_ACTION_VENDOR_SPECIFIC:
+               if (hapd->vendor_action_cb) {
+                       if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx,
+                                                  (u8 *) mgmt, len,
+                                                  hapd->iface->freq) == 0)
+                               return;
+               }
+               break;
        }
 
        hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -1374,7 +1342,7 @@ static void handle_action(struct hostapd_data *hapd,
                os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
                resp->u.action.category |= 0x80;
 
-               hapd->drv.send_mgmt_frame(hapd, resp, len);
+               hostapd_drv_send_mlme(hapd, resp, len, 0);
                os_free(resp);
        }
 }
@@ -1400,6 +1368,9 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
        int broadcast;
        u16 fc, stype;
 
+       if (len < 24)
+               return;
+
        mgmt = (struct ieee80211_mgmt *) buf;
        fc = le_to_host16(mgmt->frame_control);
        stype = WLAN_FC_GET_STYPE(fc);
@@ -1414,6 +1385,11 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
                mgmt->bssid[4] == 0xff && mgmt->bssid[5] == 0xff;
 
        if (!broadcast &&
+#ifdef CONFIG_P2P
+           /* Invitation responses can be sent with the peer MAC as BSSID */
+           !((hapd->conf->p2p & P2P_GROUP_OWNER) &&
+             stype == WLAN_FC_STYPE_ACTION) &&
+#endif /* CONFIG_P2P */
            os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
                printf("MGMT: BSSID=" MACSTR " not our address\n",
                       MAC2STR(mgmt->bssid));
@@ -1452,7 +1428,7 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
                handle_disassoc(hapd, mgmt, len);
                break;
        case WLAN_FC_STYPE_DEAUTH:
-               wpa_printf(MSG_DEBUG, "mgmt::deauth");
+               wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth");
                handle_deauth(hapd, mgmt, len);
                break;
        case WLAN_FC_STYPE_ACTION:
@@ -1565,9 +1541,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
                 * Open, static WEP, or FT protocol; no separate authorization
                 * step.
                 */
-               sta->flags |= WLAN_STA_AUTHORIZED;
-               wpa_msg(hapd->msg_ctx, MSG_INFO,
-                       AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
+               ap_sta_set_authorized(hapd, sta, 1);
        }
 
        if (reassoc)
@@ -1584,22 +1558,31 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
         * cleared and configuration gets updated in case of reassociation back
         * to the same AP.
         */
-       hapd->drv.sta_remove(hapd, sta->addr);
+       hostapd_drv_sta_remove(hapd, sta->addr);
 
 #ifdef CONFIG_IEEE80211N
        if (sta->flags & WLAN_STA_HT)
                hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
 #endif /* CONFIG_IEEE80211N */
 
-       if (hapd->drv.sta_add(hapd, sta->addr, sta->aid, sta->capability,
-                             sta->supported_rates, sta->supported_rates_len,
-                             sta->listen_interval,
-                             sta->flags & WLAN_STA_HT ? &ht_cap : NULL)) {
+       if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
+                           sta->supported_rates, sta->supported_rates_len,
+                           sta->listen_interval,
+                           sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
+                           sta->flags, sta->qosinfo)) {
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_NOTICE,
                               "Could not add STA to kernel driver");
+
+               ap_sta_disconnect(hapd, sta, sta->addr,
+                                 WLAN_REASON_DISASSOC_AP_BUSY);
+
+               goto fail;
        }
 
+       if (sta->flags & WLAN_STA_WDS)
+               hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 1);
+
        if (sta->eapol_sm == NULL) {
                /*
                 * This STA does not use RADIUS server for EAP authentication,
@@ -1614,7 +1597,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
                        goto fail;
        }
 
-       hapd->drv.set_sta_flags(hapd, sta);
+       hostapd_set_sta_flags(hapd, sta);
 
        if (sta->auth_alg == WLAN_AUTH_FT)
                wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
@@ -1633,6 +1616,54 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
 }
 
 
+static void handle_deauth_cb(struct hostapd_data *hapd,
+                            const struct ieee80211_mgmt *mgmt,
+                            size_t len, int ok)
+{
+       struct sta_info *sta;
+       if (mgmt->da[0] & 0x01)
+               return;
+       sta = ap_get_sta(hapd, mgmt->da);
+       if (!sta) {
+               wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR
+                          " not found", MAC2STR(mgmt->da));
+               return;
+       }
+       if (ok)
+               wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth",
+                          MAC2STR(sta->addr));
+       else
+               wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
+                          "deauth", MAC2STR(sta->addr));
+
+       ap_sta_deauth_cb(hapd, sta);
+}
+
+
+static void handle_disassoc_cb(struct hostapd_data *hapd,
+                              const struct ieee80211_mgmt *mgmt,
+                              size_t len, int ok)
+{
+       struct sta_info *sta;
+       if (mgmt->da[0] & 0x01)
+               return;
+       sta = ap_get_sta(hapd, mgmt->da);
+       if (!sta) {
+               wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR
+                          " not found", MAC2STR(mgmt->da));
+               return;
+       }
+       if (ok)
+               wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc",
+                          MAC2STR(sta->addr));
+       else
+               wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
+                          "disassoc", MAC2STR(sta->addr));
+
+       ap_sta_disassoc_cb(hapd, sta);
+}
+
+
 /**
  * ieee802_11_mgmt_cb - Process management frame TX status callback
  * @hapd: hostapd BSS data structure (the BSS from which the management frame
@@ -1662,10 +1693,15 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
                handle_assoc_cb(hapd, mgmt, len, 1, ok);
                break;
        case WLAN_FC_STYPE_PROBE_RESP:
-               wpa_printf(MSG_DEBUG, "mgmt::proberesp cb");
+               wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb");
                break;
        case WLAN_FC_STYPE_DEAUTH:
-               /* ignore */
+               wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
+               handle_deauth_cb(hapd, mgmt, len, ok);
+               break;
+       case WLAN_FC_STYPE_DISASSOC:
+               wpa_printf(MSG_DEBUG, "mgmt::disassoc cb");
+               handle_disassoc_cb(hapd, mgmt, len, ok);
                break;
        case WLAN_FC_STYPE_ACTION:
                wpa_printf(MSG_DEBUG, "mgmt::action cb");
@@ -1722,6 +1758,55 @@ void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
 }
 
 
+void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
+                            const u8 *data, size_t len, int ack)
+{
+       struct sta_info *sta;
+       struct hostapd_iface *iface = hapd->iface;
+
+       sta = ap_get_sta(hapd, dst);
+       if (sta == NULL && iface->num_bss > 1) {
+               size_t j;
+               for (j = 0; j < iface->num_bss; j++) {
+                       hapd = iface->bss[j];
+                       sta = ap_get_sta(hapd, dst);
+                       if (sta)
+                               break;
+               }
+       }
+       if (sta == NULL)
+               return;
+
+       ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack);
+}
+
+
+void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
+{
+       struct sta_info *sta;
+       struct hostapd_iface *iface = hapd->iface;
+
+       sta = ap_get_sta(hapd, addr);
+       if (sta == NULL && iface->num_bss > 1) {
+               size_t j;
+               for (j = 0; j < iface->num_bss; j++) {
+                       hapd = iface->bss[j];
+                       sta = ap_get_sta(hapd, addr);
+                       if (sta)
+                               break;
+               }
+       }
+       if (sta == NULL)
+               return;
+       if (!(sta->flags & WLAN_STA_PENDING_POLL))
+               return;
+
+       wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending "
+                  "activity poll", MAC2STR(sta->addr));
+       sta->flags &= ~WLAN_STA_PENDING_POLL;
+}
+
+
 void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
                                int wds)
 {
@@ -1734,19 +1819,32 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
                                   "STA " MACSTR " (aid %u)",
                                   MAC2STR(sta->addr), sta->aid);
                        sta->flags |= WLAN_STA_WDS;
-                       hapd->drv.set_wds_sta(hapd, sta->addr, sta->aid, 1);
+                       hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 1);
                }
                return;
        }
 
        wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
                   MACSTR, MAC2STR(src));
+       if (src[0] & 0x01) {
+               /* Broadcast bit set in SA?! Ignore the frame silently. */
+               return;
+       }
+
+       if (sta && (sta->flags & WLAN_STA_ASSOC_REQ_OK)) {
+               wpa_printf(MSG_DEBUG, "Association Response to the STA has "
+                          "already been sent, but no TX status yet known - "
+                          "ignore Class 3 frame issue with " MACSTR,
+                          MAC2STR(src));
+               return;
+       }
+
        if (sta && (sta->flags & WLAN_STA_AUTH))
-               hapd->drv.sta_disassoc(
+               hostapd_drv_sta_disassoc(
                        hapd, src,
                        WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
        else
-               hapd->drv.sta_deauth(
+               hostapd_drv_sta_deauth(
                        hapd, src,
                        WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
 }
index cfc069c..43042a5 100644 (file)
@@ -46,6 +46,7 @@ static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd,
 #endif /* NEED_AP_MLME */
 u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
                           int probe);
+u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
@@ -56,12 +57,26 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
 void hostapd_get_ht_capab(struct hostapd_data *hapd,
                          struct ieee80211_ht_capabilities *ht_cap,
                          struct ieee80211_ht_capabilities *neg_ht_cap);
-u16 copy_sta_ht_capab(struct sta_info *sta, const u8 *ht_capab,
-                     size_t ht_capab_len);
+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);
 void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
                       const u8 *buf, size_t len, int ack);
+void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
+                            const u8 *data, size_t len, int ack);
 void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
                                int wds);
+u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
+                                    struct sta_info *sta, u8 *eid);
+void ieee802_11_sa_query_action(struct hostapd_data *hapd,
+                               const u8 *sa, const u8 action_type,
+                               const u8 *trans_id);
+u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid);
+int hostapd_update_time_adv(struct hostapd_data *hapd);
+void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
 
 #endif /* IEEE802_11_H */
index dec56d1..f3f313d 100644 (file)
 
 #include "utils/common.h"
 #include "utils/eloop.h"
+#include "crypto/sha1.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
 #include "hostapd.h"
 #include "ap_config.h"
+#include "ap_drv_ops.h"
 #include "ieee802_11.h"
 #include "ieee802_11_auth.h"
 
 
 
 struct hostapd_cached_radius_acl {
-       time_t timestamp;
+       os_time_t timestamp;
        macaddr addr;
        int accepted; /* HOSTAPD_ACL_* */
        struct hostapd_cached_radius_acl *next;
        u32 session_timeout;
        u32 acct_interim_interval;
        int vlan_id;
+       int has_psk;
+       u8 psk[PMK_LEN];
 };
 
 
 struct hostapd_acl_query_data {
-       time_t timestamp;
+       os_time_t timestamp;
        u8 radius_id;
        macaddr addr;
        u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
@@ -67,17 +71,18 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
 
 static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
                                 u32 *session_timeout,
-                                u32 *acct_interim_interval, int *vlan_id)
+                                u32 *acct_interim_interval, int *vlan_id,
+                                u8 *psk, int *has_psk)
 {
        struct hostapd_cached_radius_acl *entry;
-       time_t now;
+       struct os_time now;
 
-       time(&now);
+       os_get_time(&now);
        entry = hapd->acl_cache;
 
        while (entry) {
                if (os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
-                       if (now - entry->timestamp > RADIUS_ACL_TIMEOUT)
+                       if (now.sec - entry->timestamp > RADIUS_ACL_TIMEOUT)
                                return -1; /* entry has expired */
                        if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
                                if (session_timeout)
@@ -88,6 +93,10 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
                                        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;
                }
 
@@ -209,11 +218,14 @@ 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
  * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
  */
 int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
                            const u8 *msg, size_t len, u32 *session_timeout,
-                           u32 *acct_interim_interval, int *vlan_id)
+                           u32 *acct_interim_interval, int *vlan_id,
+                           u8 *psk, int *has_psk)
 {
        if (session_timeout)
                *session_timeout = 0;
@@ -221,6 +233,10 @@ 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);
 
        if (hostapd_maclist_found(hapd->conf->accept_mac,
                                  hapd->conf->num_accept_mac, addr, vlan_id))
@@ -240,11 +256,12 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
                return HOSTAPD_ACL_REJECT;
 #else /* CONFIG_NO_RADIUS */
                struct hostapd_acl_query_data *query;
+               struct os_time t;
 
                /* Check whether ACL cache has an entry for this station */
                int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
                                                acct_interim_interval,
-                                               vlan_id);
+                                               vlan_id, psk, has_psk);
                if (res == HOSTAPD_ACL_ACCEPT ||
                    res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
                        return res;
@@ -270,7 +287,8 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
                        wpa_printf(MSG_ERROR, "malloc for query data failed");
                        return HOSTAPD_ACL_REJECT;
                }
-               time(&query->timestamp);
+               os_get_time(&t);
+               query->timestamp = t.sec;
                os_memcpy(query->addr, addr, ETH_ALEN);
                if (hostapd_radius_acl_query(hapd, addr, query)) {
                        wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
@@ -302,7 +320,7 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
 
 
 #ifndef CONFIG_NO_RADIUS
-static void hostapd_acl_expire_cache(struct hostapd_data *hapd, time_t now)
+static void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now)
 {
        struct hostapd_cached_radius_acl *prev, *entry, *tmp;
 
@@ -317,9 +335,7 @@ static void hostapd_acl_expire_cache(struct hostapd_data *hapd, time_t now)
                                prev->next = entry->next;
                        else
                                hapd->acl_cache = entry->next;
-#ifdef CONFIG_DRIVER_RADIUS_ACL
-                       hapd->drv.set_radius_acl_expire(hapd, entry->addr);
-#endif /* CONFIG_DRIVER_RADIUS_ACL */
+                       hostapd_drv_set_radius_acl_expire(hapd, entry->addr);
                        tmp = entry;
                        entry = entry->next;
                        os_free(tmp);
@@ -332,7 +348,8 @@ static void hostapd_acl_expire_cache(struct hostapd_data *hapd, time_t now)
 }
 
 
-static void hostapd_acl_expire_queries(struct hostapd_data *hapd, time_t now)
+static void hostapd_acl_expire_queries(struct hostapd_data *hapd,
+                                      os_time_t now)
 {
        struct hostapd_acl_query_data *prev, *entry, *tmp;
 
@@ -368,11 +385,11 @@ static void hostapd_acl_expire_queries(struct hostapd_data *hapd, time_t now)
 static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
 {
        struct hostapd_data *hapd = eloop_ctx;
-       time_t now;
+       struct os_time now;
 
-       time(&now);
-       hostapd_acl_expire_cache(hapd, now);
-       hostapd_acl_expire_queries(hapd, now);
+       os_get_time(&now);
+       hostapd_acl_expire_cache(hapd, now.sec);
+       hostapd_acl_expire_queries(hapd, now.sec);
 
        eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
 }
@@ -397,6 +414,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
        struct hostapd_acl_query_data *query, *prev;
        struct hostapd_cached_radius_acl *cache;
        struct radius_hdr *hdr = radius_msg_get_hdr(msg);
+       struct os_time t;
 
        query = hapd->acl_queries;
        prev = NULL;
@@ -431,9 +449,13 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
                wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
                goto done;
        }
-       time(&cache->timestamp);
+       os_get_time(&t);
+       cache->timestamp = t.sec;
        os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
        if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
+               int passphraselen;
+               char *passphrase;
+
                if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
                                              &cache->session_timeout) == 0)
                        cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
@@ -452,14 +474,40 @@ 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);
+               }
+
+               if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
+                   cache->psk == NULL)
+                       cache->accepted = HOSTAPD_ACL_REJECT;
        } else
                cache->accepted = HOSTAPD_ACL_REJECT;
        cache->next = hapd->acl_cache;
        hapd->acl_cache = cache;
 
 #ifdef CONFIG_DRIVER_RADIUS_ACL
-       hapd->drv.set_radius_acl_auth(hapd, query->addr, cache->accepted,
-                                     cache->session_timeout);
+       hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted,
+                                       cache->session_timeout);
 #else /* CONFIG_DRIVER_RADIUS_ACL */
 #ifdef NEED_AP_MLME
        /* Re-send original authentication frame for 802.11 processing */
index b2971e5..a90571f 100644 (file)
@@ -24,7 +24,8 @@ 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);
+                           u32 *acct_interim_interval, int *vlan_id,
+                           u8 *psk, int *has_psk);
 int hostapd_acl_init(struct hostapd_data *hapd);
 void hostapd_acl_deinit(struct hostapd_data *hapd);
 
index 7541b83..6c3696f 100644 (file)
@@ -30,7 +30,8 @@ u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
        struct ieee80211_ht_capabilities *cap;
        u8 *pos = eid;
 
-       if (!hapd->iconf->ieee80211n || !hapd->iface->current_mode)
+       if (!hapd->iconf->ieee80211n || !hapd->iface->current_mode ||
+           hapd->conf->disable_11n)
                return eid;
 
        *pos++ = WLAN_EID_HT_CAP;
@@ -58,7 +59,7 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
        struct ieee80211_ht_operation *oper;
        u8 *pos = eid;
 
-       if (!hapd->iconf->ieee80211n)
+       if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
                return eid;
 
        *pos++ = WLAN_EID_HT_OPERATION;
@@ -92,7 +93,6 @@ Set to 1 (HT non-member protection) if there may be non-HT STAs
 Set to 2 if only HT STAs are associated in BSS,
        however and at least one 20 MHz HT STA is associated
 Set to 3 (HT mixed mode) when one or more non-HT STAs are associated
-       (currently non-GF HT station is considered as non-HT STA also)
 */
 int hostapd_ht_operation_update(struct hostapd_iface *iface)
 {
@@ -130,13 +130,8 @@ int hostapd_ht_operation_update(struct hostapd_iface *iface)
                op_mode_changes++;
        }
 
-       /* Note: currently we switch to the MIXED op mode if HT non-greenfield
-        * station is associated. Probably it's a theoretical case, since
-        * it looks like all known HT STAs support greenfield.
-        */
        new_op_mode = 0;
-       if (iface->num_sta_no_ht ||
-           (iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT))
+       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)
@@ -160,11 +155,13 @@ int hostapd_ht_operation_update(struct hostapd_iface *iface)
 }
 
 
-u16 copy_sta_ht_capab(struct sta_info *sta, const u8 *ht_capab,
-                     size_t ht_capab_len)
+u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+                     const u8 *ht_capab, size_t ht_capab_len)
 {
+       /* Disable HT caps for STAs associated to no-HT BSSes. */
        if (!ht_capab ||
-           ht_capab_len < sizeof(struct ieee80211_ht_capabilities)) {
+           ht_capab_len < sizeof(struct ieee80211_ht_capabilities) ||
+           hapd->conf->disable_11n) {
                sta->flags &= ~WLAN_STA_HT;
                os_free(sta->ht_capabilities);
                sta->ht_capabilities = NULL;
@@ -253,8 +250,14 @@ void hostapd_get_ht_capab(struct hostapd_data *hapd,
                return;
        os_memcpy(neg_ht_cap, ht_cap, sizeof(*neg_ht_cap));
        cap = le_to_host16(neg_ht_cap->ht_capabilities_info);
-       cap &= hapd->iconf->ht_capab;
-       cap |= (hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_DISABLED);
+
+       /*
+        * Mask out HT features we don't support, but don't overwrite
+        * non-symmetric features like STBC and SMPS. Just because
+        * we're not in dynamic SMPS mode the STA might still be.
+        */
+       cap &= (hapd->iconf->ht_capab | HT_CAP_INFO_RX_STBC_MASK |
+               HT_CAP_INFO_TX_STBC | HT_CAP_INFO_SMPS_MASK);
 
        /*
         * STBC needs to be handled specially
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
new file mode 100644 (file)
index 0000000..8503fce
--- /dev/null
@@ -0,0 +1,405 @@
+/*
+ * hostapd / IEEE 802.11 Management
+ * 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.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "ieee802_11.h"
+
+
+#ifdef CONFIG_IEEE80211W
+
+u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
+                                    struct sta_info *sta, u8 *eid)
+{
+       u8 *pos = eid;
+       u32 timeout, tu;
+       struct os_time now, passed;
+
+       *pos++ = WLAN_EID_TIMEOUT_INTERVAL;
+       *pos++ = 5;
+       *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
+       os_get_time(&now);
+       os_time_sub(&now, &sta->sa_query_start, &passed);
+       tu = (passed.sec * 1000000 + passed.usec) / 1024;
+       if (hapd->conf->assoc_sa_query_max_timeout > tu)
+               timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
+       else
+               timeout = 0;
+       if (timeout < hapd->conf->assoc_sa_query_max_timeout)
+               timeout++; /* add some extra time for local timers */
+       WPA_PUT_LE32(pos, timeout);
+       pos += 4;
+
+       return pos;
+}
+
+
+/* MLME-SAQuery.request */
+void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
+                                 const u8 *addr, const u8 *trans_id)
+{
+       struct ieee80211_mgmt mgmt;
+       u8 *end;
+
+       wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
+                  MACSTR, MAC2STR(addr));
+       wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+                   trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+       os_memset(&mgmt, 0, sizeof(mgmt));
+       mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+                                         WLAN_FC_STYPE_ACTION);
+       os_memcpy(mgmt.da, addr, ETH_ALEN);
+       os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+       os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+       mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
+       mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
+       os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
+                 WLAN_SA_QUERY_TR_ID_LEN);
+       end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
+       if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0)
+               perror("ieee802_11_send_sa_query_req: send");
+}
+
+
+static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
+                                         const u8 *sa, const u8 *trans_id)
+{
+       struct sta_info *sta;
+       struct ieee80211_mgmt resp;
+       u8 *end;
+
+       wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
+                  MACSTR, MAC2STR(sa));
+       wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+                   trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+       sta = ap_get_sta(hapd, sa);
+       if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
+               wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request "
+                          "from unassociated STA " MACSTR, MAC2STR(sa));
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
+                  MACSTR, MAC2STR(sa));
+
+       os_memset(&resp, 0, sizeof(resp));
+       resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+                                         WLAN_FC_STYPE_ACTION);
+       os_memcpy(resp.da, sa, ETH_ALEN);
+       os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
+       os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
+       resp.u.action.category = WLAN_ACTION_SA_QUERY;
+       resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
+       os_memcpy(resp.u.action.u.sa_query_req.trans_id, trans_id,
+                 WLAN_SA_QUERY_TR_ID_LEN);
+       end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
+       if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0)
+               perror("ieee80211_mgmt_sa_query_request: send");
+}
+
+
+void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
+                               const u8 action_type, const u8 *trans_id)
+{
+       struct sta_info *sta;
+       int i;
+
+       if (action_type == WLAN_SA_QUERY_REQUEST) {
+               ieee802_11_send_sa_query_resp(hapd, sa, trans_id);
+               return;
+       }
+
+       if (action_type != WLAN_SA_QUERY_RESPONSE) {
+               wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query "
+                          "Action %d", action_type);
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from "
+                  MACSTR, MAC2STR(sa));
+       wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+                   trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+       /* MLME-SAQuery.confirm */
+
+       sta = ap_get_sta(hapd, sa);
+       if (sta == NULL || sta->sa_query_trans_id == NULL) {
+               wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
+                          "pending SA Query request found");
+               return;
+       }
+
+       for (i = 0; i < sta->sa_query_count; i++) {
+               if (os_memcmp(sta->sa_query_trans_id +
+                             i * WLAN_SA_QUERY_TR_ID_LEN,
+                             trans_id, WLAN_SA_QUERY_TR_ID_LEN) == 0)
+                       break;
+       }
+
+       if (i >= sta->sa_query_count) {
+               wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query "
+                          "transaction identifier found");
+               return;
+       }
+
+       hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+                      HOSTAPD_LEVEL_DEBUG,
+                      "Reply to pending SA Query received");
+       ap_sta_stop_sa_query(hapd, sta);
+}
+
+#endif /* CONFIG_IEEE80211W */
+
+
+u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
+{
+       u8 *pos = eid;
+       u8 len = 0;
+
+       if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
+               len = 5;
+       if (len < 4 && hapd->conf->interworking)
+               len = 4;
+       if (len == 0)
+               return eid;
+
+       *pos++ = WLAN_EID_EXT_CAPAB;
+       *pos++ = len;
+       *pos++ = 0x00;
+       *pos++ = 0x00;
+       *pos++ = 0x00;
+
+       *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 (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++;
+
+       return pos;
+}
+
+
+u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid)
+{
+       u8 *pos = eid;
+#ifdef CONFIG_INTERWORKING
+       u8 *len;
+
+       if (!hapd->conf->interworking)
+               return eid;
+
+       *pos++ = WLAN_EID_INTERWORKING;
+       len = pos++;
+
+       *pos = hapd->conf->access_network_type;
+       if (hapd->conf->internet)
+               *pos |= INTERWORKING_ANO_INTERNET;
+       if (hapd->conf->asra)
+               *pos |= INTERWORKING_ANO_ASRA;
+       if (hapd->conf->esr)
+               *pos |= INTERWORKING_ANO_ESR;
+       if (hapd->conf->uesa)
+               *pos |= INTERWORKING_ANO_UESA;
+       pos++;
+
+       if (hapd->conf->venue_info_set) {
+               *pos++ = hapd->conf->venue_group;
+               *pos++ = hapd->conf->venue_type;
+       }
+
+       if (!is_zero_ether_addr(hapd->conf->hessid)) {
+               os_memcpy(pos, hapd->conf->hessid, ETH_ALEN);
+               pos += ETH_ALEN;
+       }
+
+       *len = pos - len - 1;
+#endif /* CONFIG_INTERWORKING */
+
+       return pos;
+}
+
+
+u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid)
+{
+       u8 *pos = eid;
+#ifdef CONFIG_INTERWORKING
+
+       /* TODO: Separate configuration for ANQP? */
+       if (!hapd->conf->interworking)
+               return eid;
+
+       *pos++ = WLAN_EID_ADV_PROTO;
+       *pos++ = 2;
+       *pos++ = 0x7F; /* Query Response Length Limit | PAME-BI */
+       *pos++ = ACCESS_NETWORK_QUERY_PROTOCOL;
+#endif /* CONFIG_INTERWORKING */
+
+       return pos;
+}
+
+
+u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid)
+{
+       u8 *pos = eid;
+#ifdef CONFIG_INTERWORKING
+       u8 *len;
+       unsigned int i, count;
+
+       if (!hapd->conf->interworking ||
+           hapd->conf->roaming_consortium == NULL ||
+           hapd->conf->roaming_consortium_count == 0)
+               return eid;
+
+       *pos++ = WLAN_EID_ROAMING_CONSORTIUM;
+       len = pos++;
+
+       /* Number of ANQP OIs (in addition to the max 3 listed here) */
+       if (hapd->conf->roaming_consortium_count > 3 + 255)
+               *pos++ = 255;
+       else if (hapd->conf->roaming_consortium_count > 3)
+               *pos++ = hapd->conf->roaming_consortium_count - 3;
+       else
+               *pos++ = 0;
+
+       /* OU #1 and #2 Lengths */
+       *pos = hapd->conf->roaming_consortium[0].len;
+       if (hapd->conf->roaming_consortium_count > 1)
+               *pos |= hapd->conf->roaming_consortium[1].len << 4;
+       pos++;
+
+       if (hapd->conf->roaming_consortium_count > 3)
+               count = 3;
+       else
+               count = hapd->conf->roaming_consortium_count;
+
+       for (i = 0; i < count; i++) {
+               os_memcpy(pos, hapd->conf->roaming_consortium[i].oi,
+                         hapd->conf->roaming_consortium[i].len);
+               pos += hapd->conf->roaming_consortium[i].len;
+       }
+
+       *len = pos - len - 1;
+#endif /* CONFIG_INTERWORKING */
+
+       return pos;
+}
+
+
+u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid)
+{
+       if (hapd->conf->time_advertisement != 2)
+               return eid;
+
+       if (hapd->time_adv == NULL &&
+           hostapd_update_time_adv(hapd) < 0)
+               return eid;
+
+       if (hapd->time_adv == NULL)
+               return eid;
+
+       os_memcpy(eid, wpabuf_head(hapd->time_adv),
+                 wpabuf_len(hapd->time_adv));
+       eid += wpabuf_len(hapd->time_adv);
+
+       return eid;
+}
+
+
+u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid)
+{
+       size_t len;
+
+       if (hapd->conf->time_advertisement != 2)
+               return eid;
+
+       len = os_strlen(hapd->conf->time_zone);
+
+       *eid++ = WLAN_EID_TIME_ZONE;
+       *eid++ = len;
+       os_memcpy(eid, hapd->conf->time_zone, len);
+       eid += len;
+
+       return eid;
+}
+
+
+int hostapd_update_time_adv(struct hostapd_data *hapd)
+{
+       const int elen = 2 + 1 + 10 + 5 + 1;
+       struct os_time t;
+       struct os_tm tm;
+       u8 *pos;
+
+       if (hapd->conf->time_advertisement != 2)
+               return 0;
+
+       if (os_get_time(&t) < 0 || os_gmtime(t.sec, &tm) < 0)
+               return -1;
+
+       if (!hapd->time_adv) {
+               hapd->time_adv = wpabuf_alloc(elen);
+               if (hapd->time_adv == NULL)
+                       return -1;
+               pos = wpabuf_put(hapd->time_adv, elen);
+       } else
+               pos = wpabuf_mhead_u8(hapd->time_adv);
+
+       *pos++ = WLAN_EID_TIME_ADVERTISEMENT;
+       *pos++ = 1 + 10 + 5 + 1;
+
+       *pos++ = 2; /* UTC time at which the TSF timer is 0 */
+
+       /* Time Value at TSF 0 */
+       /* FIX: need to calculate this based on the current TSF value */
+       WPA_PUT_LE16(pos, tm.year); /* Year */
+       pos += 2;
+       *pos++ = tm.month; /* Month */
+       *pos++ = tm.day; /* Day of month */
+       *pos++ = tm.hour; /* Hours */
+       *pos++ = tm.min; /* Minutes */
+       *pos++ = tm.sec; /* Seconds */
+       WPA_PUT_LE16(pos, 0); /* Milliseconds (not used) */
+       pos += 2;
+       *pos++ = 0; /* Reserved */
+
+       /* Time Error */
+       /* TODO: fill in an estimate on the error */
+       *pos++ = 0;
+       *pos++ = 0;
+       *pos++ = 0;
+       *pos++ = 0;
+       *pos++ = 0;
+
+       *pos++ = hapd->time_update_counter++;
+
+       return 0;
+}
index eb160f8..153b271 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / IEEE 802.1X-2004 Authenticator
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * 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
 #include "utils/eloop.h"
 #include "crypto/md5.h"
 #include "crypto/crypto.h"
+#include "crypto/random.h"
 #include "common/ieee802_11_defs.h"
-#include "common/wpa_ctrl.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
 #include "eap_server/eap.h"
 #include "eap_common/eap_wsc_common.h"
 #include "eapol_auth/eapol_auth_sm.h"
 #include "eapol_auth/eapol_auth_sm_i.h"
+#include "p2p/p2p.h"
 #include "hostapd.h"
 #include "accounting.h"
 #include "sta_info.h"
@@ -33,6 +34,7 @@
 #include "preauth_auth.h"
 #include "pmksa_cache_auth.h"
 #include "ap_config.h"
+#include "ap_drv_ops.h"
 #include "ieee802_1x.h"
 
 
@@ -70,7 +72,8 @@ 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 {
-               hapd->drv.send_eapol(hapd, sta->addr, buf, len, encrypt);
+               hostapd_drv_hapd_send_eapol(hapd, sta->addr, buf, len,
+                                           encrypt, sta->flags);
        }
 
        os_free(buf);
@@ -86,21 +89,13 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
                return;
 
        if (authorized) {
-               if (!(sta->flags & WLAN_STA_AUTHORIZED))
-                       wpa_msg(hapd->msg_ctx, MSG_INFO,
-                               AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
-               sta->flags |= WLAN_STA_AUTHORIZED;
-               res = hapd->drv.set_authorized(hapd, sta, 1);
+               ap_sta_set_authorized(hapd, sta, 1);
+               res = hostapd_set_authorized(hapd, sta, 1);
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
                               HOSTAPD_LEVEL_DEBUG, "authorizing port");
        } else {
-               if ((sta->flags & (WLAN_STA_AUTHORIZED | WLAN_STA_ASSOC)) ==
-                   (WLAN_STA_AUTHORIZED | WLAN_STA_ASSOC))
-                       wpa_msg(hapd->msg_ctx, MSG_INFO,
-                               AP_STA_DISCONNECTED MACSTR,
-                               MAC2STR(sta->addr));
-               sta->flags &= ~WLAN_STA_AUTHORIZED;
-               res = hapd->drv.set_authorized(hapd, sta, 0);
+               ap_sta_set_authorized(hapd, sta, 0);
+               res = hostapd_set_authorized(hapd, sta, 0);
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
                               HOSTAPD_LEVEL_DEBUG, "unauthorizing port");
        }
@@ -140,7 +135,7 @@ static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
        key->key_length = htons(key_len);
        wpa_get_ntp_timestamp(key->replay_counter);
 
-       if (os_get_random(key->key_iv, sizeof(key->key_iv))) {
+       if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) {
                wpa_printf(MSG_ERROR, "Could not get random numbers");
                os_free(buf);
                return;
@@ -215,7 +210,7 @@ ieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname)
        if (!key->key[key->idx])
                key->key[key->idx] = os_malloc(key->default_len);
        if (key->key[key->idx] == NULL ||
-           os_get_random(key->key[key->idx], key->default_len)) {
+           random_get_bytes(key->key[key->idx], key->default_len)) {
                printf("Could not generate random WEP key (dynamic VLAN).\n");
                os_free(key->key[key->idx]);
                key->key[key->idx] = NULL;
@@ -229,11 +224,13 @@ ieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname)
        wpa_hexdump_key(MSG_DEBUG, "Default WEP key (dynamic VLAN)",
                        key->key[key->idx], key->len[key->idx]);
 
-       if (hapd->drv.set_key(ifname, hapd, WPA_ALG_WEP, NULL, key->idx, 1,
-                             NULL, 0, key->key[key->idx], key->len[key->idx]))
+       if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_WEP,
+                               broadcast_ether_addr, key->idx, 1,
+                               NULL, 0, key->key[key->idx],
+                               key->len[key->idx]))
                printf("Could not set dynamic VLAN WEP encryption key.\n");
 
-       hapd->drv.set_drv_ieee8021x(hapd, ifname, 1);
+       hostapd_set_drv_ieee8021x(hapd, ifname, 1);
 
        return key;
 }
@@ -330,7 +327,8 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
                u8 *ikey;
                ikey = os_malloc(hapd->conf->individual_wep_key_len);
                if (ikey == NULL ||
-                   os_get_random(ikey, hapd->conf->individual_wep_key_len)) {
+                   random_get_bytes(ikey, hapd->conf->individual_wep_key_len))
+               {
                        wpa_printf(MSG_ERROR, "Could not generate random "
                                   "individual WEP key.");
                        os_free(ikey);
@@ -345,9 +343,9 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
 
                /* TODO: set encryption in TX callback, i.e., only after STA
                 * has ACKed EAPOL-Key frame */
-               if (hapd->drv.set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
-                                     sta->addr, 0, 1, NULL, 0, ikey,
-                                     hapd->conf->individual_wep_key_len)) {
+               if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
+                                       sta->addr, 0, 1, NULL, 0, ikey,
+                                       hapd->conf->individual_wep_key_len)) {
                        wpa_printf(MSG_ERROR, "Could not set individual WEP "
                                   "encryption.");
                }
@@ -549,7 +547,9 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
                }
        }
 
-       radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr);
+       if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0)
+               goto fail;
+
        return;
 
  fail:
@@ -652,7 +652,7 @@ 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);
+                               sta->wps_ie, sta->p2p_ie, sta);
 }
 
 
@@ -673,6 +673,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
        struct ieee802_1x_eapol_key *key;
        u16 datalen;
        struct rsn_pmksa_cache_entry *pmksa;
+       int key_mgmt;
 
        if (!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
            !hapd->conf->wps_state)
@@ -681,9 +682,10 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
        wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR,
                   (unsigned long) len, MAC2STR(sa));
        sta = ap_get_sta(hapd, sa);
-       if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
+       if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) &&
+                    !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
                wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
-                          "associated STA");
+                          "associated/Pre-authenticating STA");
                return;
        }
 
@@ -724,10 +726,19 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
                return;
        }
 
-       if ((!hapd->conf->ieee802_1x &&
-            !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) ||
-           wpa_key_mgmt_wpa_psk(wpa_auth_sta_key_mgmt(sta->wpa_sm)))
+       if (!hapd->conf->ieee802_1x &&
+           !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
+               wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
+                          "802.1X not enabled and WPS not used");
+               return;
+       }
+
+       key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
+       if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) {
+               wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
+                          "STA is using PSK");
                return;
+       }
 
        if (!sta->eapol_sm) {
                sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
@@ -735,14 +746,24 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
                        return;
 
 #ifdef CONFIG_WPS
-               if (!hapd->conf->ieee802_1x &&
-                   ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) ==
-                    WLAN_STA_MAYBE_WPS)) {
-                       /*
-                        * Delay EAPOL frame transmission until a possible WPS
-                        * STA initiates the handshake with EAPOL-Start.
-                        */
-                       sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
+               if (!hapd->conf->ieee802_1x) {
+                       u32 wflags = sta->flags & (WLAN_STA_WPS |
+                                                  WLAN_STA_WPS2 |
+                                                  WLAN_STA_MAYBE_WPS);
+                       if (wflags == WLAN_STA_MAYBE_WPS ||
+                           wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) {
+                               /*
+                                * Delay EAPOL frame transmission until a
+                                * possible WPS STA initiates the handshake
+                                * with EAPOL-Start. Only allow the wait to be
+                                * skipped if the STA is known to support WPS
+                                * 2.0.
+                                */
+                               wpa_printf(MSG_DEBUG, "WPS: Do not start "
+                                          "EAPOL until EAPOL-Start is "
+                                          "received");
+                               sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
+                       }
                }
 #endif /* CONFIG_WPS */
 
@@ -776,6 +797,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
                }
                sta->eapol_sm->eapolStart = TRUE;
                sta->eapol_sm->dot1xAuthEapolStartFramesRx++;
+               eap_server_clear_identity(sta->eapol_sm->eap);
                wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
                break;
 
@@ -788,11 +810,12 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
                accounting_sta_stop(hapd, sta);
                sta->eapol_sm->eapolLogoff = TRUE;
                sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++;
+               eap_server_clear_identity(sta->eapol_sm->eap);
                break;
 
        case IEEE802_1X_TYPE_EAPOL_KEY:
                wpa_printf(MSG_DEBUG, "   EAPOL-Key");
-               if (!(sta->flags & WLAN_STA_AUTHORIZED)) {
+               if (!ap_sta_is_authorized(sta)) {
                        wpa_printf(MSG_DEBUG, "   Dropped key data from "
                                   "unauthorized Supplicant");
                        break;
@@ -827,6 +850,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
        struct rsn_pmksa_cache_entry *pmksa;
        int reassoc = 1;
        int force_1x = 0;
+       int key_mgmt;
 
 #ifdef CONFIG_WPS
        if (hapd->conf->wps_state && hapd->conf->wpa &&
@@ -840,9 +864,17 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
        }
 #endif /* CONFIG_WPS */
 
-       if ((!force_1x && !hapd->conf->ieee802_1x) ||
-           wpa_key_mgmt_wpa_psk(wpa_auth_sta_key_mgmt(sta->wpa_sm)))
+       if (!force_1x && !hapd->conf->ieee802_1x) {
+               wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - "
+                          "802.1X not enabled or forced for WPS");
+               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");
                return;
+       }
 
        if (sta->eapol_sm == NULL) {
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
@@ -860,17 +892,39 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
 
 #ifdef CONFIG_WPS
        sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
-       if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS)) {
+       if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS2)) {
                /*
-                * Delay EAPOL frame transmission until a possible WPS
-                * initiates the handshake with EAPOL-Start.
+                * Delay EAPOL frame transmission until a possible WPS STA
+                * initiates the handshake with EAPOL-Start. Only allow the
+                * wait to be skipped if the STA is known to support WPS 2.0.
                 */
+               wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until "
+                          "EAPOL-Start is received");
                sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
        }
 #endif /* CONFIG_WPS */
 
        sta->eapol_sm->eap_if->portEnabled = TRUE;
 
+#ifdef CONFIG_IEEE80211R
+       if (sta->auth_alg == WLAN_AUTH_FT) {
+               hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+                              HOSTAPD_LEVEL_DEBUG,
+                              "PMK from FT - skip IEEE 802.1X/EAP");
+               /* Setup EAPOL state machines to already authenticated state
+                * because of existing FT information from R0KH. */
+               sta->eapol_sm->keyRun = TRUE;
+               sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+               sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
+               sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
+               sta->eapol_sm->authSuccess = TRUE;
+               if (sta->eapol_sm->eap)
+                       eap_sm_notify_cached(sta->eapol_sm->eap);
+               /* TODO: get vlan_id from R0KH using RRB message */
+               return;
+       }
+#endif /* CONFIG_IEEE80211R */
+
        pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
        if (pmksa) {
                int old_vlanid;
@@ -1363,6 +1417,9 @@ void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
                 * request and we cannot continue EAP processing (EAP-Failure
                 * could only be sent if the EAP peer actually replied).
                 */
+               wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR,
+                       MAC2STR(sta->addr));
+
                sm->eap_if->portEnabled = FALSE;
                ap_sta_disconnect(hapd, sta, sta->addr,
                                  WLAN_REASON_PREV_AUTH_NOT_VALID);
@@ -1380,8 +1437,8 @@ static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
        os_free(eapol->default_wep_key);
        eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len);
        if (eapol->default_wep_key == NULL ||
-           os_get_random(eapol->default_wep_key,
-                         hapd->conf->default_wep_key_len)) {
+           random_get_bytes(eapol->default_wep_key,
+                            hapd->conf->default_wep_key_len)) {
                printf("Could not generate random WEP key.\n");
                os_free(eapol->default_wep_key);
                eapol->default_wep_key = NULL;
@@ -1432,10 +1489,11 @@ static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
 
        /* TODO: Could setup key for RX here, but change default TX keyid only
         * after new broadcast key has been sent to all stations. */
-       if (hapd->drv.set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, NULL,
-                             eapol->default_wep_key_idx, 1, NULL, 0,
-                             eapol->default_wep_key,
-                             hapd->conf->default_wep_key_len)) {
+       if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
+                               broadcast_ether_addr,
+                               eapol->default_wep_key_idx, 1, NULL, 0,
+                               eapol->default_wep_key,
+                               hapd->conf->default_wep_key_len)) {
                hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
                               HOSTAPD_LEVEL_WARNING, "failed to configure a "
                               "new broadcast key");
@@ -1514,7 +1572,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
 {
        struct hostapd_data *hapd = ctx;
        const struct hostapd_eap_user *eap_user;
-       int i, count;
+       int i;
 
        eap_user = hostapd_get_eap_user(hapd->conf, identity,
                                        identity_len, phase2);
@@ -1523,10 +1581,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
 
        os_memset(user, 0, sizeof(*user));
        user->phase2 = phase2;
-       count = EAP_USER_MAX_METHODS;
-       if (count > EAP_MAX_METHODS)
-               count = EAP_MAX_METHODS;
-       for (i = 0; i < count; i++) {
+       for (i = 0; i < EAP_MAX_METHODS; i++) {
                user->methods[i].vendor = eap_user->methods[i].vendor;
                user->methods[i].method = eap_user->methods[i].method;
        }
@@ -1538,6 +1593,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
                os_memcpy(user->password, eap_user->password,
                          eap_user->password_len);
                user->password_len = eap_user->password_len;
+               user->password_hash = eap_user->password_hash;
        }
        user->force_version = eap_user->force_version;
        user->ttls_auth = eap_user->ttls_auth;
@@ -1651,6 +1707,9 @@ int ieee802_1x_init(struct hostapd_data *hapd)
        conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
        conf.tnc = hapd->conf->tnc;
        conf.wps = hapd->wps;
+       conf.fragment_size = hapd->conf->fragment_size;
+       conf.pwd_group = hapd->conf->pwd_group;
+       conf.pbc_in_m1 = hapd->conf->pbc_in_m1;
 
        os_memset(&cb, 0, sizeof(cb));
        cb.eapol_send = ieee802_1x_eapol_send;
@@ -1669,7 +1728,7 @@ int ieee802_1x_init(struct hostapd_data *hapd)
                return -1;
 
        if ((hapd->conf->ieee802_1x || hapd->conf->wpa) &&
-           hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 1))
+           hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1))
                return -1;
 
 #ifndef CONFIG_NO_RADIUS
@@ -1680,9 +1739,9 @@ int ieee802_1x_init(struct hostapd_data *hapd)
 
        if (hapd->conf->default_wep_key_len) {
                for (i = 0; i < 4; i++)
-                       hapd->drv.set_key(hapd->conf->iface, hapd,
-                                         WPA_ALG_NONE, NULL, i, 0, NULL, 0,
-                                         NULL, 0);
+                       hostapd_drv_set_key(hapd->conf->iface, hapd,
+                                           WPA_ALG_NONE, NULL, i, 0, NULL, 0,
+                                           NULL, 0);
 
                ieee802_1x_rekey(hapd, NULL);
 
@@ -1700,7 +1759,7 @@ void ieee802_1x_deinit(struct hostapd_data *hapd)
 
        if (hapd->driver != NULL &&
            (hapd->conf->ieee802_1x || hapd->conf->wpa))
-               hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
+               hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
 
        eapol_auth_deinit(hapd->eapol_auth);
        hapd->eapol_auth = NULL;
@@ -1711,15 +1770,13 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
                         const u8 *buf, size_t len, int ack)
 {
        struct ieee80211_hdr *hdr;
-       struct ieee802_1x_hdr *xhdr;
-       struct ieee802_1x_eapol_key *key;
        u8 *pos;
        const unsigned char rfc1042_hdr[ETH_ALEN] =
                { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
 
        if (sta == NULL)
                return -1;
-       if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2 + sizeof(*xhdr))
+       if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2)
                return 0;
 
        hdr = (struct ieee80211_hdr *) buf;
@@ -1731,21 +1788,44 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
                return 0;
        pos += 2;
 
-       xhdr = (struct ieee802_1x_hdr *) pos;
-       pos += sizeof(*xhdr);
+       return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos,
+                                         ack);
+}
+
 
+int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+                              const u8 *buf, int len, int ack)
+{
+       const struct ieee802_1x_hdr *xhdr =
+               (const struct ieee802_1x_hdr *) buf;
+       const u8 *pos = buf + sizeof(*xhdr);
+       struct ieee802_1x_eapol_key *key;
+
+       if (len < (int) sizeof(*xhdr))
+               return 0;
        wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d "
                   "type=%d length=%d - ack=%d",
                   MAC2STR(sta->addr), xhdr->version, xhdr->type,
                   be_to_host16(xhdr->length), ack);
 
+       if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY)
+               return 0;
+
+       if (pos + sizeof(struct wpa_eapol_key) <= buf + len) {
+               const struct wpa_eapol_key *wpa;
+               wpa = (const struct wpa_eapol_key *) pos;
+               if (wpa->type == EAPOL_KEY_TYPE_RSN ||
+                   wpa->type == EAPOL_KEY_TYPE_WPA)
+                       wpa_auth_eapol_key_tx_status(hapd->wpa_auth,
+                                                    sta->wpa_sm, ack);
+       }
+
        /* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant
         * or Authenticator state machines, but EAPOL-Key packets are not
-        * retransmitted in case of failure. Try to re-sent failed EAPOL-Key
+        * retransmitted in case of failure. Try to re-send failed EAPOL-Key
         * packets couple of times because otherwise STA keys become
         * unsynchronized with AP. */
-       if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY && !ack &&
-           pos + sizeof(*key) <= buf + len) {
+       if (!ack && pos + sizeof(*key) <= buf + len) {
                key = (struct ieee802_1x_eapol_key *) pos;
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
                               HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key "
@@ -1791,6 +1871,7 @@ u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
 
 const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
 {
+       *len = 0;
        if (sm == NULL)
                return NULL;
 
@@ -1848,6 +1929,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
 {
        int len = 0, ret;
        struct eapol_state_machine *sm = sta->eapol_sm;
+       struct os_time t;
 
        if (sm == NULL)
                return 0;
@@ -1962,6 +2044,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
        len += ret;
 
        /* dot1xAuthSessionStatsTable */
+       os_get_time(&t);
        ret = os_snprintf(buf + len, buflen - len,
                          /* TODO: dot1xAuthSessionOctetsRx */
                          /* TODO: dot1xAuthSessionOctetsTx */
@@ -1976,8 +2059,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
                          (wpa_key_mgmt_wpa_ieee8021x(
                                   wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
                          1 : 2,
-                         (unsigned int) (time(NULL) -
-                                         sta->acct_session_start),
+                         (unsigned int) (t.sec - sta->acct_session_start),
                          sm->identity);
        if (ret < 0 || (size_t) ret >= buflen - len)
                return len;
@@ -2004,22 +2086,25 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
                               "Added PMKSA cache entry (IEEE 802.1X)");
        }
 
-#ifdef CONFIG_WPS
-       if (!success && (sta->flags & WLAN_STA_WPS)) {
+       if (!success) {
                /*
                 * Many devices require deauthentication after WPS provisioning
                 * and some may not be be able to do that themselves, so
-                * disconnect the client here.
+                * disconnect the client here. In addition, this may also
+                * benefit IEEE 802.1X/EAPOL authentication cases, too since
+                * the EAPOL PAE state machine would remain in HELD state for
+                * considerable amount of time and some EAP methods, like
+                * EAP-FAST with anonymous provisioning, may require another
+                * EAPOL authentication to be started to complete connection.
                 */
-               wpa_printf(MSG_DEBUG, "WPS: Force disconnection after "
-                          "EAP-Failure");
+               wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force "
+                       "disconnection after EAP-Failure");
                /* Add a small sleep to increase likelihood of previously
                 * requested EAP-Failure TX getting out before this should the
                 * driver reorder operations.
                 */
                os_sleep(0, 10000);
                ap_sta_disconnect(hapd, sta, sta->addr,
-                                 WLAN_REASON_PREV_AUTH_NOT_VALID);
+                                 WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
        }
-#endif /* CONFIG_WPS */
 }
index 1a4d2eb..267e22a 100644 (file)
@@ -68,6 +68,8 @@ int ieee802_1x_init(struct hostapd_data *hapd);
 void ieee802_1x_deinit(struct hostapd_data *hapd);
 int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
                         const u8 *buf, size_t len, int ack);
+int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+                              const u8 *data, int len, int ack);
 u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
 u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
                                 int idx);
diff --git a/src/ap/p2p_hostapd.c b/src/ap/p2p_hostapd.c
new file mode 100644 (file)
index 0000000..6f8b778
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "p2p/p2p.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "sta_info.h"
+#include "p2p_hostapd.h"
+
+
+#ifdef CONFIG_P2P
+
+int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
+                           char *buf, size_t buflen)
+{
+       if (sta->p2p_ie == NULL)
+               return 0;
+
+       return p2p_ie_text(sta->p2p_ie, buf, buf + buflen);
+}
+
+
+int hostapd_p2p_set_noa(struct hostapd_data *hapd, u8 count, int start,
+                       int duration)
+{
+       wpa_printf(MSG_DEBUG, "P2P: Set NoA parameters: count=%u start=%d "
+                  "duration=%d", count, start, duration);
+
+       if (count == 0) {
+               hapd->noa_enabled = 0;
+               hapd->noa_start = 0;
+               hapd->noa_duration = 0;
+       }
+
+       if (count != 255) {
+               wpa_printf(MSG_DEBUG, "P2P: Non-periodic NoA - set "
+                          "NoA parameters");
+               return hostapd_driver_set_noa(hapd, count, start, duration);
+       }
+
+       hapd->noa_enabled = 1;
+       hapd->noa_start = start;
+       hapd->noa_duration = duration;
+
+       if (hapd->num_sta_no_p2p == 0) {
+               wpa_printf(MSG_DEBUG, "P2P: No legacy STAs connected - update "
+                          "periodic NoA parameters");
+               return hostapd_driver_set_noa(hapd, count, start, duration);
+       }
+
+       wpa_printf(MSG_DEBUG, "P2P: Legacy STA(s) connected - do not enable "
+                  "periodic NoA");
+
+       return 0;
+}
+
+
+void hostapd_p2p_non_p2p_sta_connected(struct hostapd_data *hapd)
+{
+       wpa_printf(MSG_DEBUG, "P2P: First non-P2P device connected");
+
+       if (hapd->noa_enabled) {
+               wpa_printf(MSG_DEBUG, "P2P: Disable periodic NoA");
+               hostapd_driver_set_noa(hapd, 0, 0, 0);
+       }
+}
+
+
+void hostapd_p2p_non_p2p_sta_disconnected(struct hostapd_data *hapd)
+{
+       wpa_printf(MSG_DEBUG, "P2P: Last non-P2P device disconnected");
+
+       if (hapd->noa_enabled) {
+               wpa_printf(MSG_DEBUG, "P2P: Enable periodic NoA");
+               hostapd_driver_set_noa(hapd, 255, hapd->noa_start,
+                                      hapd->noa_duration);
+       }
+}
+
+#endif /* CONFIG_P2P */
+
+
+#ifdef CONFIG_P2P_MANAGER
+u8 * hostapd_eid_p2p_manage(struct hostapd_data *hapd, u8 *eid)
+{
+       u8 bitmap;
+       *eid++ = WLAN_EID_VENDOR_SPECIFIC;
+       *eid++ = 4 + 3 + 1;
+       WPA_PUT_BE24(eid, OUI_WFA);
+       eid += 3;
+       *eid++ = P2P_OUI_TYPE;
+
+       *eid++ = P2P_ATTR_MANAGEABILITY;
+       WPA_PUT_LE16(eid, 1);
+       eid += 2;
+       bitmap = P2P_MAN_DEVICE_MANAGEMENT;
+       if (hapd->conf->p2p & P2P_ALLOW_CROSS_CONNECTION)
+               bitmap |= P2P_MAN_CROSS_CONNECTION_PERMITTED;
+       bitmap |= P2P_MAN_COEXISTENCE_OPTIONAL;
+       *eid++ = bitmap;
+
+       return eid;
+}
+#endif /* CONFIG_P2P_MANAGER */
diff --git a/src/ap/p2p_hostapd.h b/src/ap/p2p_hostapd.h
new file mode 100644 (file)
index 0000000..95b31d9
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#ifndef P2P_HOSTAPD_H
+#define P2P_HOSTAPD_H
+
+#ifdef CONFIG_P2P
+
+int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
+                           char *buf, size_t buflen);
+int hostapd_p2p_set_noa(struct hostapd_data *hapd, u8 count, int start,
+                       int duration);
+void hostapd_p2p_non_p2p_sta_connected(struct hostapd_data *hapd);
+void hostapd_p2p_non_p2p_sta_disconnected(struct hostapd_data *hapd);
+
+
+#else /* CONFIG_P2P */
+
+static inline int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd,
+                                         struct sta_info *sta,
+                                         char *buf, size_t buflen)
+{
+       return 0;
+}
+
+#endif /* CONFIG_P2P */
+
+u8 * hostapd_eid_p2p_manage(struct hostapd_data *hapd, u8 *eid);
+
+#endif /* P2P_HOSTAPD_H */
index f68c479..b8fa5a9 100644 (file)
@@ -18,6 +18,7 @@
 #include "utils/eloop.h"
 #include "crypto/sha1.h"
 #include "crypto/sha256.h"
+#include "crypto/random.h"
 #include "wpa_auth.h"
 #include "wpa_auth_i.h"
 #include "wpa_auth_ie.h"
@@ -294,7 +295,7 @@ void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
                return;
        }
 
-       if (os_get_random(smk, PMK_LEN)) {
+       if (random_get_bytes(smk, PMK_LEN)) {
                wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
                return;
        }
index 335c9a5..d9c348e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / Station table
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * 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
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
 #include "drivers/driver.h"
+#include "p2p/p2p.h"
 #include "hostapd.h"
 #include "accounting.h"
 #include "ieee802_1x.h"
 #include "beacon.h"
 #include "ap_mlme.h"
 #include "vlan_init.h"
+#include "p2p_hostapd.h"
+#include "ap_drv_ops.h"
 #include "sta_info.h"
 
 static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
                                       struct sta_info *sta);
 static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
+static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
+static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
 #ifdef CONFIG_IEEE80211W
 static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
 #endif /* CONFIG_IEEE80211W */
+static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
 
 int ap_for_each_sta(struct hostapd_data *hapd,
                    int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
@@ -121,11 +128,14 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
 
        accounting_sta_stop(hapd, sta);
 
+       /* just in case */
+       ap_sta_set_authorized(hapd, sta, 0);
+
        if (sta->flags & WLAN_STA_WDS)
-               hapd->drv.set_wds_sta(hapd, sta->addr, sta->aid, 0);
+               hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 0);
 
        if (!(sta->flags & WLAN_STA_PREAUTH))
-               hapd->drv.sta_remove(hapd, sta->addr);
+               hostapd_drv_sta_remove(hapd, sta->addr);
 
        ap_sta_hash_del(hapd, sta);
        ap_sta_list_del(hapd, sta);
@@ -173,6 +183,15 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
                hapd->iface->num_sta_ht_20mhz--;
        }
 
+#ifdef CONFIG_P2P
+       if (sta->no_p2p_set) {
+               sta->no_p2p_set = 0;
+               hapd->num_sta_no_p2p--;
+               if (hapd->num_sta_no_p2p == 0)
+                       hostapd_p2p_non_p2p_sta_disconnected(hapd);
+       }
+#endif /* CONFIG_P2P */
+
 #if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N)
        if (hostapd_ht_operation_update(hapd->iface) > 0)
                set_beacon++;
@@ -183,6 +202,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
 
        eloop_cancel_timeout(ap_handle_timer, hapd, sta);
        eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
+       eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+       eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
 
        ieee802_1x_free_station(sta);
        wpa_auth_sta_deinit(sta->wpa_sm);
@@ -199,9 +220,15 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
        eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
 #endif /* CONFIG_IEEE80211W */
 
+#ifdef CONFIG_P2P
+       p2p_group_notif_disassoc(hapd->p2p_group, sta->addr);
+#endif /* CONFIG_P2P */
+
        wpabuf_free(sta->wps_ie);
+       wpabuf_free(sta->p2p_ie);
 
        os_free(sta->ht_capabilities);
+       os_free(sta->psk);
 
        os_free(sta);
 }
@@ -253,27 +280,35 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
            (sta->timeout_next == STA_NULLFUNC ||
             sta->timeout_next == STA_DISASSOC)) {
                int inactive_sec;
-               wpa_printf(MSG_DEBUG, "Checking STA " MACSTR " inactivity:",
-                          MAC2STR(sta->addr));
-               inactive_sec = hapd->drv.get_inact_sec(hapd, sta->addr);
+               inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr);
                if (inactive_sec == -1) {
-                       wpa_printf(MSG_DEBUG, "Could not get station info "
-                                  "from kernel driver for " MACSTR ".",
-                                  MAC2STR(sta->addr));
+                       wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+                               "Check inactivity: Could not "
+                               "get station info rom kernel driver for "
+                               MACSTR, MAC2STR(sta->addr));
                } else if (inactive_sec < hapd->conf->ap_max_inactivity &&
                           sta->flags & WLAN_STA_ASSOC) {
                        /* station activity detected; reset timeout state */
-                       wpa_printf(MSG_DEBUG, "  Station has been active");
+                       wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+                               "Station " MACSTR " has been active %is ago",
+                               MAC2STR(sta->addr), inactive_sec);
                        sta->timeout_next = STA_NULLFUNC;
                        next_time = hapd->conf->ap_max_inactivity -
                                inactive_sec;
+               } else {
+                       wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+                               "Station " MACSTR " has been "
+                               "inactive too long: %d sec, max allowed: %d",
+                               MAC2STR(sta->addr), inactive_sec,
+                               hapd->conf->ap_max_inactivity);
                }
        }
 
        if ((sta->flags & WLAN_STA_ASSOC) &&
            sta->timeout_next == STA_DISASSOC &&
            !(sta->flags & WLAN_STA_PENDING_POLL)) {
-               wpa_printf(MSG_DEBUG, "  Station has ACKed data poll");
+               wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
+                       " has ACKed data poll", MAC2STR(sta->addr));
                /* data nullfunc frame poll did not produce TX errors; assume
                 * station ACKed it */
                sta->timeout_next = STA_NULLFUNC;
@@ -288,52 +323,24 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
 
        if (sta->timeout_next == STA_NULLFUNC &&
            (sta->flags & WLAN_STA_ASSOC)) {
-#ifndef CONFIG_NATIVE_WINDOWS
-               /* send data frame to poll STA and check whether this frame
-                * is ACKed */
-               struct ieee80211_hdr hdr;
-
-               wpa_printf(MSG_DEBUG, "  Polling STA with data frame");
+               wpa_printf(MSG_DEBUG, "  Polling STA");
                sta->flags |= WLAN_STA_PENDING_POLL;
-
-               os_memset(&hdr, 0, sizeof(hdr));
-               if (hapd->driver &&
-                   os_strcmp(hapd->driver->name, "hostap") == 0) {
-                       /*
-                        * WLAN_FC_STYPE_NULLFUNC would be more appropriate,
-                        * but it is apparently not retried so TX Exc events
-                        * are not received for it.
-                        */
-                       hdr.frame_control =
-                               IEEE80211_FC(WLAN_FC_TYPE_DATA,
-                                            WLAN_FC_STYPE_DATA);
-               } else {
-                       hdr.frame_control =
-                               IEEE80211_FC(WLAN_FC_TYPE_DATA,
-                                            WLAN_FC_STYPE_NULLFUNC);
-               }
-
-               hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
-               os_memcpy(hdr.IEEE80211_DA_FROMDS, sta->addr, ETH_ALEN);
-               os_memcpy(hdr.IEEE80211_BSSID_FROMDS, hapd->own_addr,
-                         ETH_ALEN);
-               os_memcpy(hdr.IEEE80211_SA_FROMDS, hapd->own_addr, ETH_ALEN);
-
-               if (hapd->drv.send_mgmt_frame(hapd, &hdr, sizeof(hdr)) < 0)
-                       perror("ap_handle_timer: send");
-#endif /* CONFIG_NATIVE_WINDOWS */
+               hostapd_drv_poll_client(hapd, hapd->own_addr, sta->addr,
+                                       sta->flags & WLAN_STA_WMM);
        } else if (sta->timeout_next != STA_REMOVE) {
                int deauth = sta->timeout_next == STA_DEAUTH;
 
-               wpa_printf(MSG_DEBUG, "Sending %s info to STA " MACSTR,
-                          deauth ? "deauthentication" : "disassociation",
-                          MAC2STR(sta->addr));
+               wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+                       "Timeout, sending %s info to STA " MACSTR,
+                       deauth ? "deauthentication" : "disassociation",
+                       MAC2STR(sta->addr));
 
                if (deauth) {
-                       hapd->drv.sta_deauth(hapd, sta->addr,
-                                            WLAN_REASON_PREV_AUTH_NOT_VALID);
+                       hostapd_drv_sta_deauth(
+                               hapd, sta->addr,
+                               WLAN_REASON_PREV_AUTH_NOT_VALID);
                } else {
-                       hapd->drv.sta_disassoc(
+                       hostapd_drv_sta_disassoc(
                                hapd, sta->addr,
                                WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
                }
@@ -346,6 +353,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
                                       hapd, sta);
                break;
        case STA_DISASSOC:
+               ap_sta_set_authorized(hapd, sta, 0);
                sta->flags &= ~WLAN_STA_ASSOC;
                ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
                if (!sta->acct_terminate_cause)
@@ -366,7 +374,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
        case STA_REMOVE:
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_INFO, "deauthenticated due to "
-                              "inactivity");
+                              "inactivity (timer DEAUTH/REMOVE)");
                if (!sta->acct_terminate_cause)
                        sta->acct_terminate_cause =
                                RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
@@ -397,7 +405,7 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
                RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT;
        os_memcpy(addr, sta->addr, ETH_ALEN);
        ap_free_sta(hapd, sta);
-       hapd->drv.sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+       hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
 }
 
 
@@ -463,7 +471,7 @@ static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
 
        wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver",
                   MAC2STR(sta->addr));
-       if (hapd->drv.sta_remove(hapd, sta->addr) &&
+       if (hostapd_drv_sta_remove(hapd, sta->addr) &&
            sta->flags & WLAN_STA_ASSOC) {
                wpa_printf(MSG_DEBUG, "Could not remove station " MACSTR
                           " from kernel driver.", MAC2STR(sta->addr));
@@ -498,13 +506,23 @@ static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
 }
 
 
+static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct hostapd_data *hapd = eloop_ctx;
+       struct sta_info *sta = timeout_ctx;
+
+       ap_sta_remove(hapd, sta);
+       mlme_disassociate_indication(hapd, sta, sta->disassoc_reason);
+}
+
+
 void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
                         u16 reason)
 {
        wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
                   hapd->conf->iface, MAC2STR(sta->addr));
        sta->flags &= ~WLAN_STA_ASSOC;
-       ap_sta_remove(hapd, sta);
+       ap_sta_set_authorized(hapd, sta, 0);
        sta->timeout_next = STA_DEAUTH;
        eloop_cancel_timeout(ap_handle_timer, hapd, sta);
        eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
@@ -512,7 +530,22 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
        accounting_sta_stop(hapd, sta);
        ieee802_1x_free_station(sta);
 
-       mlme_disassociate_indication(hapd, sta, reason);
+       sta->disassoc_reason = reason;
+       sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
+       eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+       eloop_register_timeout(hapd->iface->drv_flags &
+                              WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
+                              ap_sta_disassoc_cb_timeout, hapd, sta);
+}
+
+
+static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct hostapd_data *hapd = eloop_ctx;
+       struct sta_info *sta = timeout_ctx;
+
+       ap_sta_remove(hapd, sta);
+       mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason);
 }
 
 
@@ -522,7 +555,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
        wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
                   hapd->conf->iface, MAC2STR(sta->addr));
        sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
-       ap_sta_remove(hapd, sta);
+       ap_sta_set_authorized(hapd, sta, 0);
        sta->timeout_next = STA_REMOVE;
        eloop_cancel_timeout(ap_handle_timer, hapd, sta);
        eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
@@ -530,7 +563,12 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
        accounting_sta_stop(hapd, sta);
        ieee802_1x_free_station(sta);
 
-       mlme_deauthenticate_indication(hapd, sta, reason);
+       sta->deauth_reason = reason;
+       sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
+       eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+       eloop_register_timeout(hapd->iface->drv_flags &
+                              WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
+                              ap_sta_deauth_cb_timeout, hapd, sta);
 }
 
 
@@ -636,7 +674,7 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
        if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0)
                wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
 
-       ret = hapd->drv.set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
+       ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
        if (ret < 0) {
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
@@ -732,6 +770,64 @@ void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
 #endif /* CONFIG_IEEE80211W */
 
 
+void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
+                          int authorized)
+{
+       const u8 *dev_addr = NULL;
+       if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
+               return;
+
+#ifdef CONFIG_P2P
+       dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
+#endif /* CONFIG_P2P */
+
+       if (authorized) {
+               if (dev_addr)
+                       wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
+                               MACSTR " p2p_dev_addr=" MACSTR,
+                               MAC2STR(sta->addr), MAC2STR(dev_addr));
+               else
+                       wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
+                               MACSTR, MAC2STR(sta->addr));
+               if (hapd->msg_ctx_parent &&
+                   hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
+                       wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+                               AP_STA_CONNECTED MACSTR " p2p_dev_addr="
+                               MACSTR,
+                               MAC2STR(sta->addr), MAC2STR(dev_addr));
+               else if (hapd->msg_ctx_parent &&
+                        hapd->msg_ctx_parent != hapd->msg_ctx)
+                       wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+                               AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
+
+               sta->flags |= WLAN_STA_AUTHORIZED;
+       } else {
+               if (dev_addr)
+                       wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
+                               MACSTR " p2p_dev_addr=" MACSTR,
+                               MAC2STR(sta->addr), MAC2STR(dev_addr));
+               else
+                       wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
+                               MACSTR, MAC2STR(sta->addr));
+               if (hapd->msg_ctx_parent &&
+                   hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
+                       wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+                               AP_STA_DISCONNECTED MACSTR " p2p_dev_addr="
+                               MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr));
+               else if (hapd->msg_ctx_parent &&
+                        hapd->msg_ctx_parent != hapd->msg_ctx)
+                       wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+                               AP_STA_DISCONNECTED MACSTR,
+                               MAC2STR(sta->addr));
+               sta->flags &= ~WLAN_STA_AUTHORIZED;
+       }
+
+       if (hapd->sta_authorized_cb)
+               hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
+                                       sta->addr, authorized);
+}
+
+
 void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
                       const u8 *addr, u16 reason)
 {
@@ -740,12 +836,45 @@ void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
                sta = ap_get_sta(hapd, addr);
 
        if (addr)
-               hapd->drv.sta_deauth(hapd, addr, reason);
+               hostapd_drv_sta_deauth(hapd, addr, reason);
 
        if (sta == NULL)
                return;
-       sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_AUTHORIZED);
+       ap_sta_set_authorized(hapd, sta, 0);
+       sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
        eloop_cancel_timeout(ap_handle_timer, hapd, sta);
-       eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta);
+       eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
+                              ap_handle_timer, hapd, sta);
        sta->timeout_next = STA_REMOVE;
+
+       sta->deauth_reason = reason;
+       sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
+       eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+       eloop_register_timeout(hapd->iface->drv_flags &
+                              WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
+                              ap_sta_deauth_cb_timeout, hapd, sta);
+}
+
+
+void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta)
+{
+       if (!(sta->flags & WLAN_STA_PENDING_DEAUTH_CB)) {
+               wpa_printf(MSG_DEBUG, "Ignore deauth cb for test frame");
+               return;
+       }
+       sta->flags &= ~WLAN_STA_PENDING_DEAUTH_CB;
+       eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+       ap_sta_deauth_cb_timeout(hapd, sta);
+}
+
+
+void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta)
+{
+       if (!(sta->flags & WLAN_STA_PENDING_DISASSOC_CB)) {
+               wpa_printf(MSG_DEBUG, "Ignore disassoc cb for test frame");
+               return;
+       }
+       sta->flags &= ~WLAN_STA_PENDING_DISASSOC_CB;
+       eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+       ap_sta_disassoc_cb_timeout(hapd, sta);
 }
index 55faa5a..daa96bf 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / Station table
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * 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
 #define WLAN_STA_WPS BIT(12)
 #define WLAN_STA_MAYBE_WPS BIT(13)
 #define WLAN_STA_WDS BIT(14)
+#define WLAN_STA_ASSOC_REQ_OK BIT(15)
+#define WLAN_STA_WPS2 BIT(16)
+#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
+#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
 #define WLAN_STA_NONERP BIT(31)
 
 /* Maximum number of supported rates (from both Supported Rates and Extended
@@ -48,6 +52,7 @@ struct sta_info {
        u16 listen_interval; /* or beacon_int for APs */
        u8 supported_rates[WLAN_SUPP_RATES_MAX];
        int supported_rates_len;
+       u8 qosinfo; /* Valid when WLAN_STA_WMM is set */
 
        unsigned int nonerp_set:1;
        unsigned int no_short_slot_time_set:1;
@@ -55,6 +60,7 @@ struct sta_info {
        unsigned int no_ht_gf_set:1;
        unsigned int no_ht_set:1;
        unsigned int ht_20mhz_set:1;
+       unsigned int no_p2p_set:1;
 
        u16 auth_alg;
        u8 previous_ap[6];
@@ -63,6 +69,9 @@ struct sta_info {
                STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
        } timeout_next;
 
+       u16 deauth_reason;
+       u16 disassoc_reason;
+
        /* IEEE 802.1X related data */
        struct eapol_state_machine *eapol_sm;
 
@@ -90,6 +99,7 @@ struct sta_info {
        struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
 
        int vlan_id;
+       u8 *psk; /* PSK from RADIUS authentication server */
 
        struct ieee80211_ht_capabilities *ht_capabilities;
 
@@ -104,6 +114,7 @@ struct sta_info {
 #endif /* CONFIG_IEEE80211W */
 
        struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
+       struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
 };
 
 
@@ -111,7 +122,7 @@ struct sta_info {
  * passed since last received frame from the station, a nullfunc data frame is
  * sent to the station. If this frame is not acknowledged and no other frames
  * have been received, the station will be disassociated after
- * AP_DISASSOC_DELAY seconds. Similarily, the station will be deauthenticated
+ * AP_DISASSOC_DELAY seconds. Similarly, the station will be deauthenticated
  * after AP_DEAUTH_DELAY seconds has passed after disassociation. */
 #define AP_MAX_INACTIVITY (5 * 60)
 #define AP_DISASSOC_DELAY (1)
@@ -152,4 +163,14 @@ int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
 void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
                       const u8 *addr, u16 reason);
 
+void ap_sta_set_authorized(struct hostapd_data *hapd,
+                          struct sta_info *sta, int authorized);
+static inline int ap_sta_is_authorized(struct sta_info *sta)
+{
+       return sta->flags & WLAN_STA_AUTHORIZED;
+}
+
+void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta);
+
 #endif /* STA_INFO_H */
index 9690348..fac7f4b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / TKIP countermeasures
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * 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
@@ -21,6 +21,7 @@
 #include "sta_info.h"
 #include "ap_mlme.h"
 #include "wpa_auth.h"
+#include "ap_drv_ops.h"
 #include "tkip_countermeasures.h"
 
 
@@ -29,7 +30,7 @@ static void ieee80211_tkip_countermeasures_stop(void *eloop_ctx,
 {
        struct hostapd_data *hapd = eloop_ctx;
        hapd->tkip_countermeasures = 0;
-       hapd->drv.set_countermeasures(hapd, 0);
+       hostapd_drv_set_countermeasures(hapd, 0);
        hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
                       HOSTAPD_LEVEL_INFO, "TKIP countermeasures ended");
 }
@@ -44,24 +45,30 @@ static void ieee80211_tkip_countermeasures_start(struct hostapd_data *hapd)
 
        wpa_auth_countermeasures_start(hapd->wpa_auth);
        hapd->tkip_countermeasures = 1;
-       hapd->drv.set_countermeasures(hapd, 1);
+       hostapd_drv_set_countermeasures(hapd, 1);
        wpa_gtk_rekey(hapd->wpa_auth);
        eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
        eloop_register_timeout(60, 0, ieee80211_tkip_countermeasures_stop,
                               hapd, NULL);
        for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
-               hapd->drv.sta_deauth(hapd, sta->addr,
-                                    WLAN_REASON_MICHAEL_MIC_FAILURE);
-               sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
-                               WLAN_STA_AUTHORIZED);
-               hapd->drv.sta_remove(hapd, sta->addr);
+               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);
        }
 }
 
 
+void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd)
+{
+       eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
+}
+
+
 void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
 {
-       time_t now;
+       struct os_time now;
 
        if (addr && local) {
                struct sta_info *sta = ap_get_sta(hapd, addr);
@@ -81,13 +88,13 @@ void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
                }
        }
 
-       time(&now);
-       if (now > hapd->michael_mic_failure + 60) {
+       os_get_time(&now);
+       if (now.sec > hapd->michael_mic_failure + 60) {
                hapd->michael_mic_failures = 1;
        } else {
                hapd->michael_mic_failures++;
                if (hapd->michael_mic_failures > 1)
                        ieee80211_tkip_countermeasures_start(hapd);
        }
-       hapd->michael_mic_failure = now;
+       hapd->michael_mic_failure = now.sec;
 }
index 5a1afce..a8ffd16 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / TKIP countermeasures
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * 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
@@ -16,5 +16,6 @@
 #define TKIP_COUNTERMEASURES_H
 
 void 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 0ff48ae..09bc32f 100644 (file)
@@ -22,6 +22,7 @@
 
 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),
                                 void *ctx)
 {
index c9d166a..f2f766f 100644 (file)
@@ -19,6 +19,7 @@
 #include "utils/common.h"
 #include "hostapd.h"
 #include "ap_config.h"
+#include "ap_drv_ops.h"
 #include "vlan_init.h"
 
 
@@ -737,9 +738,10 @@ int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
         * functions for setting up dynamic broadcast keys. */
        for (i = 0; i < 4; i++) {
                if (mssid->wep.key[i] &&
-                   hapd->drv.set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
-                                     i == mssid->wep.idx, NULL, 0,
-                                     mssid->wep.key[i], mssid->wep.len[i])) {
+                   hostapd_drv_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
+                                       i == mssid->wep.idx, NULL, 0,
+                                       mssid->wep.key[i], mssid->wep.len[i]))
+               {
                        wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
                                   "encryption for dynamic VLAN");
                        return -1;
@@ -755,7 +757,7 @@ static int vlan_dynamic_add(struct hostapd_data *hapd,
 {
        while (vlan) {
                if (vlan->vlan_id != VLAN_ID_WILDCARD) {
-                       if (hapd->drv.vlan_if_add(hapd, vlan->ifname)) {
+                       if (hostapd_vlan_if_add(hapd, vlan->ifname)) {
                                if (errno != EEXIST) {
                                        wpa_printf(MSG_ERROR, "VLAN: Could "
                                                   "not add VLAN %s: %s",
@@ -785,7 +787,7 @@ static void vlan_dynamic_remove(struct hostapd_data *hapd,
                next = vlan->next;
 
                if (vlan->vlan_id != VLAN_ID_WILDCARD &&
-                   hapd->drv.vlan_if_remove(hapd, vlan->ifname)) {
+                   hostapd_vlan_if_remove(hapd, vlan->ifname)) {
                        wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
                                   "iface: %s: %s",
                                   vlan->ifname, strerror(errno));
@@ -859,7 +861,7 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
                    pos);
        os_free(ifname);
 
-       if (hapd->drv.vlan_if_add(hapd, n->ifname)) {
+       if (hostapd_vlan_if_add(hapd, n->ifname)) {
                os_free(n);
                return NULL;
        }
@@ -897,7 +899,7 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
                return 1;
 
        if (vlan->dynamic_vlan == 0)
-               hapd->drv.vlan_if_remove(hapd, vlan->ifname);
+               hostapd_vlan_if_remove(hapd, vlan->ifname);
 
        return 0;
 }
index 3668130..d21c82f 100644 (file)
@@ -23,6 +23,7 @@
 #include "ieee802_11.h"
 #include "sta_info.h"
 #include "ap_config.h"
+#include "ap_drv_ops.h"
 #include "wmm.h"
 
 
@@ -71,9 +72,12 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid)
        wmm->version = WMM_VERSION;
        wmm->qos_info = hapd->parameter_set_count & 0xf;
 
-       if (hapd->conf->wmm_uapsd)
+       if (hapd->conf->wmm_uapsd &&
+           (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
                wmm->qos_info |= 0x80;
 
+       wmm->reserved = 0;
+
        /* fill in a parameter set record for each AC */
        for (e = 0; e < 4; e++) {
                struct wmm_ac_parameter *ac = &wmm->ac[e];
@@ -94,9 +98,11 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid)
 }
 
 
-/* This function is called when a station sends an association request with
- * WMM info element. The function returns zero on success or non-zero on any
- * error in WMM element. eid does not include Element ID and Length octets. */
+/*
+ * This function is called when a station sends an association request with
+ * WMM info element. The function returns 1 on success or 0 on any error in WMM
+ * element. eid does not include Element ID and Length octets.
+ */
 int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len)
 {
        struct wmm_information_element *wmm;
@@ -106,7 +112,7 @@ int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len)
        if (len < sizeof(struct wmm_information_element)) {
                wpa_printf(MSG_DEBUG, "Too short WMM IE (len=%lu)",
                           (unsigned long) len);
-               return -1;
+               return 0;
        }
 
        wmm = (struct wmm_information_element *) eid;
@@ -117,10 +123,10 @@ int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len)
        if (wmm->oui_subtype != WMM_OUI_SUBTYPE_INFORMATION_ELEMENT ||
            wmm->version != WMM_VERSION) {
                wpa_printf(MSG_DEBUG, "Unsupported WMM IE Subtype/Version");
-               return -1;
+               return 0;
        }
 
-       return 0;
+       return 1;
 }
 
 
@@ -150,7 +156,7 @@ static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr,
        os_memcpy(t, tspec, sizeof(struct wmm_tspec_element));
        len = ((u8 *) (t + 1)) - buf;
 
-       if (hapd->drv.send_mgmt_frame(hapd, m, len) < 0)
+       if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0)
                perror("wmm_send_action: send");
 }
 
index 36cb0f4..1b5a5a2 100644 (file)
@@ -22,6 +22,7 @@
 #include "crypto/crypto.h"
 #include "crypto/sha1.h"
 #include "crypto/sha256.h"
+#include "crypto/random.h"
 #include "eapol_auth/eapol_auth_sm.h"
 #include "ap_config.h"
 #include "ieee802_11.h"
@@ -44,6 +45,8 @@ static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
 static void wpa_request_new_ptk(struct wpa_state_machine *sm);
 static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
                          struct wpa_group *group);
+static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
+                                      struct wpa_group *group);
 
 static const u32 dot11RSNAConfigGroupUpdateCount = 4;
 static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
@@ -191,6 +194,7 @@ static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
 {
        if (wpa_auth->cb.disconnect == NULL)
                return;
+       wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR, MAC2STR(addr));
        wpa_auth->cb.disconnect(wpa_auth->cb.ctx, addr,
                                WLAN_REASON_PREV_AUTH_NOT_VALID);
 }
@@ -215,11 +219,13 @@ static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
 {
        struct wpa_authenticator *wpa_auth = eloop_ctx;
 
-       if (os_get_random(wpa_auth->group->GMK, WPA_GMK_LEN)) {
+       if (random_get_bytes(wpa_auth->group->GMK, WPA_GMK_LEN)) {
                wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
                           "initialization.");
        } else {
                wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "GMK rekeyd");
+               wpa_hexdump_key(MSG_DEBUG, "GMK",
+                               wpa_auth->group->GMK, WPA_GMK_LEN);
        }
 
        if (wpa_auth->conf.wpa_gmk_rekey) {
@@ -296,13 +302,41 @@ static void wpa_group_set_key_len(struct wpa_group *group, int cipher)
 }
 
 
-static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
-                                        int vlan_id)
+static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
+                                         struct wpa_group *group)
 {
-       struct wpa_group *group;
        u8 buf[ETH_ALEN + 8 + sizeof(group)];
        u8 rkey[32];
 
+       if (random_get_bytes(group->GMK, WPA_GMK_LEN) < 0)
+               return -1;
+       wpa_hexdump_key(MSG_DEBUG, "GMK", group->GMK, WPA_GMK_LEN);
+
+       /*
+        * Counter = PRF-256(Random number, "Init Counter",
+        *                   Local MAC Address || Time)
+        */
+       os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
+       wpa_get_ntp_timestamp(buf + ETH_ALEN);
+       os_memcpy(buf + ETH_ALEN + 8, &group, sizeof(group));
+       if (random_get_bytes(rkey, sizeof(rkey)) < 0)
+               return -1;
+
+       if (sha1_prf(rkey, sizeof(rkey), "Init Counter", buf, sizeof(buf),
+                    group->Counter, WPA_NONCE_LEN) < 0)
+               return -1;
+       wpa_hexdump_key(MSG_DEBUG, "Key Counter",
+                       group->Counter, WPA_NONCE_LEN);
+
+       return 0;
+}
+
+
+static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
+                                        int vlan_id, int delay_init)
+{
+       struct wpa_group *group;
+
        group = os_zalloc(sizeof(struct wpa_group));
        if (group == NULL)
                return NULL;
@@ -312,27 +346,35 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
 
        wpa_group_set_key_len(group, wpa_auth->conf.wpa_group);
 
-       /* Counter = PRF-256(Random number, "Init Counter",
-        *                   Local MAC Address || Time)
+       if (random_pool_ready() != 1) {
+               wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
+                          "for secure operations - update keys later when "
+                          "the first station connects");
+       }
+
+       /*
+        * Set initial GMK/Counter value here. The actual values that will be
+        * used in negotiations will be set once the first station tries to
+        * connect. This allows more time for collecting additional randomness
+        * on embedded devices.
         */
-       os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
-       wpa_get_ntp_timestamp(buf + ETH_ALEN);
-       os_memcpy(buf + ETH_ALEN + 8, &group, sizeof(group));
-       if (os_get_random(rkey, sizeof(rkey)) ||
-           os_get_random(group->GMK, WPA_GMK_LEN)) {
+       if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0) {
                wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
                           "initialization.");
                os_free(group);
                return NULL;
        }
 
-       sha1_prf(rkey, sizeof(rkey), "Init Counter", buf, sizeof(buf),
-                group->Counter, WPA_NONCE_LEN);
-
        group->GInit = TRUE;
-       wpa_group_sm_step(wpa_auth, group);
-       group->GInit = FALSE;
-       wpa_group_sm_step(wpa_auth, group);
+       if (delay_init) {
+               wpa_printf(MSG_DEBUG, "WPA: Delay group state machine start "
+                          "until Beacon frames have been configured");
+               /* Initialization is completed in wpa_init_keys(). */
+       } else {
+               wpa_group_sm_step(wpa_auth, group);
+               group->GInit = FALSE;
+               wpa_group_sm_step(wpa_auth, group);
+       }
 
        return group;
 }
@@ -364,7 +406,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
                return NULL;
        }
 
-       wpa_auth->group = wpa_group_init(wpa_auth, 0);
+       wpa_auth->group = wpa_group_init(wpa_auth, 0, 1);
        if (wpa_auth->group == NULL) {
                os_free(wpa_auth->wpa_ie);
                os_free(wpa_auth);
@@ -405,6 +447,19 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
 }
 
 
+int wpa_init_keys(struct wpa_authenticator *wpa_auth)
+{
+       struct wpa_group *group = wpa_auth->group;
+
+       wpa_printf(MSG_DEBUG, "WPA: Start group state machine to set initial "
+                  "keys");
+       wpa_group_sm_step(wpa_auth, group);
+       group->GInit = FALSE;
+       wpa_group_sm_step(wpa_auth, group);
+       return 0;
+}
+
+
 /**
  * wpa_deinit - Deinitialize WPA authenticator
  * @wpa_auth: Pointer to WPA authenticator data from wpa_init()
@@ -539,6 +594,10 @@ void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm)
 
 static void wpa_free_sta_sm(struct wpa_state_machine *sm)
 {
+       if (sm->GUpdateStationKeys) {
+               sm->group->GKeyDoneStations--;
+               sm->GUpdateStationKeys = FALSE;
+       }
 #ifdef CONFIG_IEEE80211R
        os_free(sm->assoc_resp_ftie);
 #endif /* CONFIG_IEEE80211R */
@@ -563,6 +622,7 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
        }
 
        eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
+       sm->pending_1_of_4_timeout = 0;
        eloop_cancel_timeout(wpa_sm_call_step, sm, NULL);
        eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
        if (sm->in_step_loop) {
@@ -651,6 +711,37 @@ 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)
+{
+       /* Supplicant reported a Michael MIC error */
+       wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+                        "received EAPOL-Key Error Request "
+                        "(STA detected Michael MIC failure (group=%d))",
+                        group);
+
+       if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) {
+               wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+                               "ignore Michael MIC failure report since "
+                               "group cipher is not TKIP");
+       } else if (!group && sm->pairwise != WPA_CIPHER_TKIP) {
+               wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+                               "ignore Michael MIC failure report since "
+                               "pairwise cipher is not TKIP");
+       } else {
+               wpa_auth_mic_failure_report(wpa_auth, sm->addr);
+               sm->dot11RSNAStatsTKIPRemoteMICFailures++;
+               wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
+       }
+
+       /*
+        * Error report is not a request for a new key handshake, but since
+        * Authenticator may do it, let's change the keys now anyway.
+        */
+       wpa_request_new_ptk(sm);
+}
+
+
 void wpa_receive(struct wpa_authenticator *wpa_auth,
                 struct wpa_state_machine *sm,
                 u8 *data, size_t data_len)
@@ -676,6 +767,9 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
        key = (struct wpa_eapol_key *) (hdr + 1);
        key_info = WPA_GET_BE16(key->key_info);
        key_data_length = WPA_GET_BE16(key->key_data_length);
+       wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
+                  " key_info=0x%x type=%u key_data_length=%u",
+                  MAC2STR(sm->addr), key_info, key->type, key_data_length);
        if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) {
                wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
                           "key_data overflow (%d > %lu)",
@@ -701,6 +795,11 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
                }
        }
 
+       wpa_hexdump(MSG_DEBUG, "WPA: Received Key Nonce", key->key_nonce,
+                   WPA_NONCE_LEN);
+       wpa_hexdump(MSG_DEBUG, "WPA: Received Replay Counter",
+                   key->replay_counter, WPA_REPLAY_COUNTER_LEN);
+
        /* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys
         * are set */
 
@@ -795,6 +894,26 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
                                         sm->wpa_ptk_state);
                        return;
                }
+               random_add_randomness(key->key_nonce, WPA_NONCE_LEN);
+               if (sm->group->reject_4way_hs_for_entropy) {
+                       /*
+                        * The system did not have enough entropy to generate
+                        * strong random numbers. Reject the first 4-way
+                        * handshake(s) and collect some entropy based on the
+                        * information from it. Once enough entropy is
+                        * available, the next atempt will trigger GMK/Key
+                        * Counter update and the station will be allowed to
+                        * continue.
+                        */
+                       wpa_printf(MSG_DEBUG, "WPA: Reject 4-way handshake to "
+                                  "collect more entropy for random number "
+                                  "generation");
+                       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;
+               }
                if (wpa_parse_kde_ies((u8 *) (key + 1), key_data_length,
                                      &kde) < 0) {
                        wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -905,6 +1024,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
                }
                sm->MICVerified = TRUE;
                eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
+               sm->pending_1_of_4_timeout = 0;
        }
 
        if (key_info & WPA_KEY_INFO_REQUEST) {
@@ -930,17 +1050,9 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
 #endif /* CONFIG_PEERKEY */
                        return;
                } else if (key_info & WPA_KEY_INFO_ERROR) {
-                       /* Supplicant reported a Michael MIC error */
-                       wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
-                                       "received EAPOL-Key Error Request "
-                                       "(STA detected Michael MIC failure)");
-                       wpa_auth_mic_failure_report(wpa_auth, sm->addr);
-                       sm->dot11RSNAStatsTKIPRemoteMICFailures++;
-                       wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
-                       /* Error report is not a request for a new key
-                        * handshake, but since Authenticator may do it, let's
-                        * change the keys now anyway. */
-                       wpa_request_new_ptk(sm);
+                       wpa_receive_error_report(
+                               wpa_auth, sm,
+                               !(key_info & WPA_KEY_INFO_KEY_TYPE));
                } else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
                        wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
                                        "received EAPOL-Key Request for new "
@@ -987,6 +1099,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
        os_memcpy(sm->last_rx_eapol_key, data, data_len);
        sm->last_rx_eapol_key_len = data_len;
 
+       sm->rx_eapol_key_secure = !!(key_info & WPA_KEY_INFO_SECURE);
        sm->EAPOLKeyReceived = TRUE;
        sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
        sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST);
@@ -995,25 +1108,37 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
 }
 
 
-static void wpa_gmk_to_gtk(const u8 *gmk, const u8 *addr, const u8 *gnonce,
-                          u8 *gtk, size_t gtk_len)
+static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr,
+                         const u8 *gnonce, u8 *gtk, size_t gtk_len)
 {
-       u8 data[ETH_ALEN + WPA_NONCE_LEN];
+       u8 data[ETH_ALEN + WPA_NONCE_LEN + 8 + 16];
+       u8 *pos;
+       int ret = 0;
 
-       /* GTK = PRF-X(GMK, "Group key expansion", AA || GNonce) */
+       /* GTK = PRF-X(GMK, "Group key expansion",
+        *      AA || GNonce || Time || random data)
+        * The example described in the IEEE 802.11 standard uses only AA and
+        * GNonce as inputs here. Add some more entropy since this derivation
+        * is done only at the Authenticator and as such, does not need to be
+        * exactly same.
+        */
        os_memcpy(data, addr, ETH_ALEN);
        os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN);
+       pos = data + ETH_ALEN + WPA_NONCE_LEN;
+       wpa_get_ntp_timestamp(pos);
+       pos += 8;
+       if (random_get_bytes(pos, 16) < 0)
+               ret = -1;
 
 #ifdef CONFIG_IEEE80211W
-       sha256_prf(gmk, WPA_GMK_LEN, "Group key expansion",
-                  data, sizeof(data), gtk, gtk_len);
+       sha256_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len);
 #else /* CONFIG_IEEE80211W */
-       sha1_prf(gmk, WPA_GMK_LEN, "Group key expansion",
-                data, sizeof(data), gtk, gtk_len);
+       if (sha1_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len)
+           < 0)
+               ret = -1;
 #endif /* CONFIG_IEEE80211W */
 
-       wpa_hexdump_key(MSG_DEBUG, "GMK", gmk, WPA_GMK_LEN);
-       wpa_hexdump_key(MSG_DEBUG, "GTK", gtk, gtk_len);
+       return ret;
 }
 
 
@@ -1022,6 +1147,7 @@ static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx)
        struct wpa_authenticator *wpa_auth = eloop_ctx;
        struct wpa_state_machine *sm = timeout_ctx;
 
+       sm->pending_1_of_4_timeout = 0;
        wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout");
        sm->TimeoutEvt = TRUE;
        wpa_sm_step(sm);
@@ -1209,10 +1335,14 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
                         keyidx, encr, 0);
 
        ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr;
-       if (ctr == 1)
+       if (ctr == 1 && wpa_auth->conf.tx_status)
                timeout_ms = eapol_key_timeout_first;
        else
                timeout_ms = eapol_key_timeout_subseq;
+       if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
+               sm->pending_1_of_4_timeout = 1;
+       wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
+                  "counter %d)", timeout_ms, ctr);
        eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
                               wpa_send_eapol_timeout, wpa_auth, sm);
 }
@@ -1247,8 +1377,7 @@ void wpa_remove_ptk(struct wpa_state_machine *sm)
 {
        sm->PTK_valid = FALSE;
        os_memset(&sm->PTK, 0, sizeof(sm->PTK));
-       wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, (u8 *) "",
-                        0);
+       wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL, 0);
        sm->pairwise_set = FALSE;
        eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
 }
@@ -1411,10 +1540,41 @@ SM_STATE(WPA_PTK, AUTHENTICATION)
 }
 
 
+static void wpa_group_first_station(struct wpa_authenticator *wpa_auth,
+                                   struct wpa_group *group)
+{
+       /*
+        * System has run bit further than at the time hostapd was started
+        * potentially very early during boot up. This provides better chances
+        * of collecting more randomness on embedded systems. Re-initialize the
+        * GMK and Counter here to improve their strength if there was not
+        * enough entropy available immediately after system startup.
+        */
+       wpa_printf(MSG_DEBUG, "WPA: Re-initialize GMK/Counter on first "
+                  "station");
+       if (random_pool_ready() != 1) {
+               wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
+                          "to proceed - reject first 4-way handshake");
+               group->reject_4way_hs_for_entropy = TRUE;
+       }
+       wpa_group_init_gmk_and_counter(wpa_auth, group);
+       wpa_gtk_update(wpa_auth, group);
+       wpa_group_config_group_keys(wpa_auth, group);
+}
+
+
 SM_STATE(WPA_PTK, AUTHENTICATION2)
 {
        SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk);
+
+       if (!sm->group->first_sta_seen) {
+               wpa_group_first_station(sm->wpa_auth, sm->group);
+               sm->group->first_sta_seen = TRUE;
+       }
+
        os_memcpy(sm->ANonce, sm->group->Counter, WPA_NONCE_LEN);
+       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
@@ -1605,6 +1765,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
        }
 #endif /* CONFIG_IEEE80211R */
 
+       sm->pending_1_of_4_timeout = 0;
        eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
 
        if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
@@ -1726,6 +1887,20 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
                gtk_len = 0;
                keyidx = 0;
                _rsc = NULL;
+               if (sm->rx_eapol_key_secure) {
+                       /*
+                        * It looks like Windows 7 supplicant tries to use
+                        * Secure bit in msg 2/4 after having reported Michael
+                        * MIC failure and it then rejects the 4-way handshake
+                        * if msg 3/4 does not set Secure bit. Work around this
+                        * by setting the Secure bit here even in the case of
+                        * WPA if the supplicant used it first.
+                        */
+                       wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+                                       "STA used Secure bit in WPA msg 2/4 - "
+                                       "set Secure for 3/4 as workaround");
+                       secure = 1;
+               }
        }
 
        kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
@@ -1876,8 +2051,11 @@ SM_STEP(WPA_PTK)
        if (sm->Init)
                SM_ENTER(WPA_PTK, INITIALIZE);
        else if (sm->Disconnect
-                /* || FIX: dot11RSNAConfigSALifetime timeout */)
+                /* || FIX: dot11RSNAConfigSALifetime timeout */) {
+               wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+                               "WPA_PTK: sm->Disconnect");
                SM_ENTER(WPA_PTK, DISCONNECT);
+       }
        else if (sm->DeauthenticationRequest)
                SM_ENTER(WPA_PTK, DISCONNECTED);
        else if (sm->AuthenticationRequest)
@@ -1913,6 +2091,8 @@ SM_STEP(WPA_PTK)
                        SM_ENTER(WPA_PTK, PTKSTART);
                else {
                        wpa_auth->dot11RSNA4WayHandshakeFailures++;
+                       wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+                                       "INITPMK - keyAvailable = false");
                        SM_ENTER(WPA_PTK, DISCONNECT);
                }
                break;
@@ -1933,6 +2113,9 @@ SM_STEP(WPA_PTK)
                else if (sm->TimeoutCtr >
                         (int) dot11RSNAConfigPairwiseUpdateCount) {
                        wpa_auth->dot11RSNA4WayHandshakeFailures++;
+                       wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+                                        "PTKSTART: Retry limit %d reached",
+                                        dot11RSNAConfigPairwiseUpdateCount);
                        SM_ENTER(WPA_PTK, DISCONNECT);
                } else if (sm->TimeoutEvt)
                        SM_ENTER(WPA_PTK, PTKSTART);
@@ -1956,6 +2139,10 @@ SM_STEP(WPA_PTK)
                else if (sm->TimeoutCtr >
                         (int) dot11RSNAConfigPairwiseUpdateCount) {
                        wpa_auth->dot11RSNA4WayHandshakeFailures++;
+                       wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+                                        "PTKINITNEGOTIATING: Retry limit %d "
+                                        "reached",
+                                        dot11RSNAConfigPairwiseUpdateCount);
                        SM_ENTER(WPA_PTK, DISCONNECT);
                } else if (sm->TimeoutEvt)
                        SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
@@ -2094,20 +2281,24 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
 {
        int ret = 0;
 
-       /* FIX: is this the correct way of getting GNonce? */
        os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
        inc_byte_array(group->Counter, WPA_NONCE_LEN);
-       wpa_gmk_to_gtk(group->GMK, wpa_auth->addr, group->GNonce,
-                      group->GTK[group->GN - 1], group->GTK_len);
+       if (wpa_gmk_to_gtk(group->GMK, "Group key expansion",
+                          wpa_auth->addr, group->GNonce,
+                          group->GTK[group->GN - 1], group->GTK_len) < 0)
+               ret = -1;
+       wpa_hexdump_key(MSG_DEBUG, "GTK",
+                       group->GTK[group->GN - 1], group->GTK_len);
 
 #ifdef CONFIG_IEEE80211W
        if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
-               if (os_get_random(group->IGTK[group->GN_igtk - 4],
-                                 WPA_IGTK_LEN) < 0) {
-                       wpa_printf(MSG_INFO, "RSN: Failed to get new random "
-                                  "IGTK");
+               os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
+               inc_byte_array(group->Counter, WPA_NONCE_LEN);
+               if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion",
+                                  wpa_auth->addr, group->GNonce,
+                                  group->IGTK[group->GN_igtk - 4],
+                                  WPA_IGTK_LEN) < 0)
                        ret = -1;
-               }
                wpa_hexdump_key(MSG_DEBUG, "IGTK",
                                group->IGTK[group->GN_igtk - 4], WPA_IGTK_LEN);
        }
@@ -2143,20 +2334,23 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
        if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) {
                wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
                                "Not in PTKINITDONE; skip Group Key update");
+               sm->GUpdateStationKeys = FALSE;
                return 0;
        }
        if (sm->GUpdateStationKeys) {
                /*
-                * This should not really happen, but just in case, make sure
-                * we do not count the same STA twice in GKeyDoneStations.
+                * This should not really happen, so add a debug log entry.
+                * Since we clear the GKeyDoneStations before the loop, the
+                * station needs to be counted here anyway.
                 */
                wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-                               "GUpdateStationKeys already set - do not "
-                               "increment GKeyDoneStations");
-       } else {
-               sm->group->GKeyDoneStations++;
-               sm->GUpdateStationKeys = TRUE;
+                               "GUpdateStationKeys was already set when "
+                               "marking station for GTK rekeying");
        }
+
+       sm->group->GKeyDoneStations++;
+       sm->GUpdateStationKeys = TRUE;
+
        wpa_sm_step(sm);
        return 0;
 }
@@ -2185,32 +2379,54 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
         * including all STAs that could be in not-yet-completed state. */
        wpa_gtk_update(wpa_auth, group);
 
+       if (group->GKeyDoneStations) {
+               wpa_printf(MSG_DEBUG, "wpa_group_setkeys: Unexpected "
+                          "GKeyDoneStations=%d when starting new GTK rekey",
+                          group->GKeyDoneStations);
+               group->GKeyDoneStations = 0;
+       }
        wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, NULL);
        wpa_printf(MSG_DEBUG, "wpa_group_setkeys: GKeyDoneStations=%d",
                   group->GKeyDoneStations);
 }
 
 
-static void wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
-                                 struct wpa_group *group)
+static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
+                                      struct wpa_group *group)
+{
+       int ret = 0;
+
+       if (wpa_auth_set_key(wpa_auth, group->vlan_id,
+                            wpa_alg_enum(wpa_auth->conf.wpa_group),
+                            broadcast_ether_addr, group->GN,
+                            group->GTK[group->GN - 1], group->GTK_len) < 0)
+               ret = -1;
+
+#ifdef CONFIG_IEEE80211W
+       if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION &&
+           wpa_auth_set_key(wpa_auth, group->vlan_id, WPA_ALG_IGTK,
+                            broadcast_ether_addr, group->GN_igtk,
+                            group->IGTK[group->GN_igtk - 4],
+                            WPA_IGTK_LEN) < 0)
+               ret = -1;
+#endif /* CONFIG_IEEE80211W */
+
+       return ret;
+}
+
+
+static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
+                                struct wpa_group *group)
 {
        wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
                   "SETKEYSDONE (VLAN-ID %d)", group->vlan_id);
        group->changed = TRUE;
        group->wpa_group_state = WPA_GROUP_SETKEYSDONE;
-       wpa_auth_set_key(wpa_auth, group->vlan_id,
-                        wpa_alg_enum(wpa_auth->conf.wpa_group),
-                        NULL, group->GN, group->GTK[group->GN - 1],
-                        group->GTK_len);
 
-#ifdef CONFIG_IEEE80211W
-       if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
-               wpa_auth_set_key(wpa_auth, group->vlan_id, WPA_ALG_IGTK,
-                                NULL, group->GN_igtk,
-                                group->IGTK[group->GN_igtk - 4],
-                                WPA_IGTK_LEN);
-       }
-#endif /* CONFIG_IEEE80211W */
+       if (wpa_group_config_group_keys(wpa_auth, group) < 0)
+               return -1;
+
+       return 0;
 }
 
 
@@ -2310,6 +2526,7 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
                group->GN_igtk = tmp;
 #endif /* CONFIG_IEEE80211W */
                wpa_gtk_update(wpa_auth, group);
+               wpa_group_config_group_keys(wpa_auth, group);
        }
 }
 
@@ -2345,19 +2562,21 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
 {
        int len = 0, ret;
        char pmkid_txt[PMKID_LEN * 2 + 1];
+#ifdef CONFIG_RSN_PREAUTH
+       const int preauth = 1;
+#else /* CONFIG_RSN_PREAUTH */
+       const int preauth = 0;
+#endif /* CONFIG_RSN_PREAUTH */
 
        if (wpa_auth == NULL)
                return len;
 
        ret = os_snprintf(buf + len, buflen - len,
                          "dot11RSNAOptionImplemented=TRUE\n"
-#ifdef CONFIG_RSN_PREAUTH
-                         "dot11RSNAPreauthenticationImplemented=TRUE\n"
-#else /* CONFIG_RSN_PREAUTH */
-                         "dot11RSNAPreauthenticationImplemented=FALSE\n"
-#endif /* CONFIG_RSN_PREAUTH */
+                         "dot11RSNAPreauthenticationImplemented=%s\n"
                          "dot11RSNAEnabled=%s\n"
                          "dot11RSNAPreauthenticationEnabled=%s\n",
+                         wpa_bool_txt(preauth),
                          wpa_bool_txt(wpa_auth->conf.wpa & WPA_PROTO_RSN),
                          wpa_bool_txt(wpa_auth->conf.rsn_preauth));
        if (ret < 0 || (size_t) ret >= buflen - len)
@@ -2473,7 +2692,7 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
                "dot11RSNAStatsSelectedPairwiseCipher=" RSN_SUITE "\n"
                /* TODO: dot11RSNAStatsTKIPICVErrors */
                "dot11RSNAStatsTKIPLocalMICFailures=%u\n"
-               "dot11RSNAStatsTKIPRemoveMICFailures=%u\n"
+               "dot11RSNAStatsTKIPRemoteMICFailures=%u\n"
                /* TODO: dot11RSNAStatsCCMPReplays */
                /* TODO: dot11RSNAStatsCCMPDecryptErrors */
                /* TODO: dot11RSNAStatsTKIPReplays */,
@@ -2570,7 +2789,8 @@ const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len)
 int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
                       int session_timeout, struct eapol_state_machine *eapol)
 {
-       if (sm == NULL || sm->wpa != WPA_VERSION_WPA2)
+       if (sm == NULL || sm->wpa != WPA_VERSION_WPA2 ||
+           sm->wpa_auth->conf.disable_pmksa_caching)
                return -1;
 
        if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
@@ -2609,7 +2829,7 @@ wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
 
        wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d",
                   vlan_id);
-       group = wpa_group_init(wpa_auth, vlan_id);
+       group = wpa_group_init(wpa_auth, vlan_id, 0);
        if (group == NULL)
                return NULL;
 
@@ -2649,3 +2869,33 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
        sm->group = group;
        return 0;
 }
+
+
+void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
+                                 struct wpa_state_machine *sm, int ack)
+{
+       if (wpa_auth == NULL || sm == NULL)
+               return;
+       wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key TX status for STA " MACSTR
+                  " ack=%d", MAC2STR(sm->addr), ack);
+       if (sm->pending_1_of_4_timeout && ack) {
+               /*
+                * Some deployed supplicant implementations update their SNonce
+                * for each EAPOL-Key 2/4 message even within the same 4-way
+                * handshake and then fail to use the first SNonce when
+                * deriving the PTK. This results in unsuccessful 4-way
+                * handshake whenever the relatively short initial timeout is
+                * reached and EAPOL-Key 1/4 is retransmitted. Try to work
+                * around this by increasing the timeout now that we know that
+                * the station has received the frame.
+                */
+               int timeout_ms = eapol_key_timeout_subseq;
+               wpa_printf(MSG_DEBUG, "WPA: Increase initial EAPOL-Key 1/4 "
+                          "timeout by %u ms because of acknowledged frame",
+                          timeout_ms);
+               eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
+               eloop_register_timeout(timeout_ms / 1000,
+                                      (timeout_ms % 1000) * 1000,
+                                      wpa_send_eapol_timeout, wpa_auth, sm);
+       }
+}
index d0136c7..ce2751e 100644 (file)
@@ -143,7 +143,9 @@ struct wpa_auth_config {
        int peerkey;
        int wmm_enabled;
        int wmm_uapsd;
+       int disable_pmksa_caching;
        int okc;
+       int tx_status;
 #ifdef CONFIG_IEEE80211W
        enum mfp_options ieee80211w;
 #endif /* CONFIG_IEEE80211W */
@@ -160,6 +162,7 @@ struct wpa_auth_config {
        struct ft_remote_r0kh *r0kh_list;
        struct ft_remote_r1kh *r1kh_list;
        int pmk_r1_push;
+       int ft_over_ds;
 #endif /* CONFIG_IEEE80211R */
 };
 
@@ -205,6 +208,7 @@ struct wpa_auth_callbacks {
 struct wpa_authenticator * wpa_init(const u8 *addr,
                                    struct wpa_auth_config *conf,
                                    struct wpa_auth_callbacks *cb);
+int wpa_init_keys(struct wpa_authenticator *wpa_auth);
 void wpa_deinit(struct wpa_authenticator *wpa_auth);
 int wpa_reconfig(struct wpa_authenticator *wpa_auth,
                 struct wpa_auth_config *conf);
@@ -259,6 +263,8 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
                               int session_timeout,
                               struct eapol_state_machine *eapol);
 int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
+void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
+                                 struct wpa_state_machine *sm, int ack);
 
 #ifdef CONFIG_IEEE80211R
 u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
index c9871d9..2d1bbe4 100644 (file)
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "crypto/aes_wrap.h"
+#include "crypto/random.h"
 #include "ap_config.h"
 #include "ieee802_11.h"
 #include "wmm.h"
 #include "wpa_auth.h"
 #include "wpa_auth_i.h"
-#include "wpa_auth_ie.h"
 
 
 #ifdef CONFIG_IEEE80211R
 
-struct wpa_ft_ies {
-       const u8 *mdie;
-       size_t mdie_len;
-       const u8 *ftie;
-       size_t ftie_len;
-       const u8 *r1kh_id;
-       const u8 *gtk;
-       size_t gtk_len;
-       const u8 *r0kh_id;
-       size_t r0kh_id_len;
-       const u8 *rsn;
-       size_t rsn_len;
-       const u8 *rsn_pmkid;
-       const u8 *ric;
-       size_t ric_len;
-};
-
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
-                           struct wpa_ft_ies *parse);
-
-
 static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
                           const u8 *data, size_t data_len)
 {
@@ -91,7 +69,9 @@ int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
        *pos++ = MOBILITY_DOMAIN_ID_LEN + 1;
        os_memcpy(pos, conf->mobility_domain, MOBILITY_DOMAIN_ID_LEN);
        pos += MOBILITY_DOMAIN_ID_LEN;
-       capab = RSN_FT_CAPAB_FT_OVER_DS;
+       capab = 0;
+       if (conf->ft_over_ds)
+               capab |= RSN_FT_CAPAB_FT_OVER_DS;
        *pos++ = capab;
 
        return pos - buf;
@@ -334,7 +314,7 @@ static int wpa_ft_pull_pmk_r1(struct wpa_authenticator *wpa_auth,
 
        /* aes_wrap() does not support inplace encryption, so use a temporary
         * buffer for the data. */
-       if (os_get_random(f.nonce, sizeof(f.nonce))) {
+       if (random_get_bytes(f.nonce, sizeof(f.nonce))) {
                wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
                           "nonce");
                return -1;
@@ -725,143 +705,6 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
 }
 
 
-static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
-                            struct wpa_ft_ies *parse)
-{
-       const u8 *end, *pos;
-
-       parse->ftie = ie;
-       parse->ftie_len = ie_len;
-
-       pos = ie + sizeof(struct rsn_ftie);
-       end = ie + ie_len;
-
-       while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
-               switch (pos[0]) {
-               case FTIE_SUBELEM_R1KH_ID:
-                       if (pos[1] != FT_R1KH_ID_LEN) {
-                               wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
-                                          "length in FTIE: %d", pos[1]);
-                               return -1;
-                       }
-                       parse->r1kh_id = pos + 2;
-                       break;
-               case FTIE_SUBELEM_GTK:
-                       parse->gtk = pos + 2;
-                       parse->gtk_len = pos[1];
-                       break;
-               case FTIE_SUBELEM_R0KH_ID:
-                       if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
-                               wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
-                                          "length in FTIE: %d", pos[1]);
-                               return -1;
-                       }
-                       parse->r0kh_id = pos + 2;
-                       parse->r0kh_id_len = pos[1];
-                       break;
-               }
-
-               pos += 2 + pos[1];
-       }
-
-       return 0;
-}
-
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
-                           struct wpa_ft_ies *parse)
-{
-       const u8 *end, *pos;
-       struct wpa_ie_data data;
-       int ret;
-       const struct rsn_ftie *ftie;
-       int prot_ie_count = 0;
-
-       os_memset(parse, 0, sizeof(*parse));
-       if (ies == NULL)
-               return 0;
-
-       pos = ies;
-       end = ies + ies_len;
-       while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
-               switch (pos[0]) {
-               case WLAN_EID_RSN:
-                       parse->rsn = pos + 2;
-                       parse->rsn_len = pos[1];
-                       ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
-                                                  parse->rsn_len + 2,
-                                                  &data);
-                       if (ret < 0) {
-                               wpa_printf(MSG_DEBUG, "FT: Failed to parse "
-                                          "RSN IE: %d", ret);
-                               return -1;
-                       }
-                       if (data.num_pmkid == 1 && data.pmkid)
-                               parse->rsn_pmkid = data.pmkid;
-                       break;
-               case WLAN_EID_MOBILITY_DOMAIN:
-                       parse->mdie = pos + 2;
-                       parse->mdie_len = pos[1];
-                       break;
-               case WLAN_EID_FAST_BSS_TRANSITION:
-                       if (pos[1] < sizeof(*ftie))
-                               return -1;
-                       ftie = (const struct rsn_ftie *) (pos + 2);
-                       prot_ie_count = ftie->mic_control[1];
-                       if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
-                               return -1;
-                       break;
-               case WLAN_EID_RIC_DATA:
-                       if (parse->ric == NULL)
-                               parse->ric = pos;
-               }
-
-               pos += 2 + pos[1];
-       }
-
-       if (prot_ie_count == 0)
-               return 0; /* no MIC */
-
-       /*
-        * Check that the protected IE count matches with IEs included in the
-        * frame.
-        */
-       if (parse->rsn)
-               prot_ie_count--;
-       if (parse->mdie)
-               prot_ie_count--;
-       if (parse->ftie)
-               prot_ie_count--;
-       if (prot_ie_count < 0) {
-               wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
-                          "the protected IE count");
-               return -1;
-       }
-
-       if (prot_ie_count == 0 && parse->ric) {
-               wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
-                          "included in protected IE count");
-               return -1;
-       }
-
-       /* Determine the end of the RIC IE(s) */
-       pos = parse->ric;
-       while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
-              prot_ie_count) {
-               prot_ie_count--;
-               pos += 2 + pos[1];
-       }
-       parse->ric_len = pos - parse->ric;
-       if (prot_ie_count) {
-               wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
-                          "frame", (int) prot_ie_count);
-               return -1;
-       }
-
-       return 0;
-}
-
-
 static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
                                   int vlan_id,
                                   enum wpa_alg alg, const u8 *addr, int idx,
@@ -997,7 +840,7 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
        sm->pmk_r1_name_valid = 1;
        os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
 
-       if (os_get_random(sm->ANonce, WPA_NONCE_LEN)) {
+       if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
                wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
                           "ANonce");
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -1204,7 +1047,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
 
        count = 3;
        if (parse.ric)
-               count++;
+               count += ieee802_11_ie_count(parse.ric, parse.ric_len);
        if (ftie->mic_control[1] != count) {
                wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
                           "Control: received %u expected %u",
index afa13a6..56bab23 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / WPA authenticator glue code
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * 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
 #include "ap_drv_ops.h"
 #include "ap_config.h"
 #include "wpa_auth.h"
-
-
-#ifdef CONFIG_IEEE80211R
-static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
-                               size_t len);
-#endif /* CONFIG_IEEE80211R */
+#include "wpa_auth_glue.h"
 
 
 static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
                                  struct wpa_auth_config *wconf)
 {
+       os_memset(wconf, 0, sizeof(*wconf));
        wconf->wpa = conf->wpa;
        wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
        wconf->wpa_pairwise = conf->wpa_pairwise;
@@ -54,6 +50,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
        wconf->peerkey = conf->peerkey;
        wconf->wmm_enabled = conf->wmm_enabled;
        wconf->wmm_uapsd = conf->wmm_uapsd;
+       wconf->disable_pmksa_caching = conf->disable_pmksa_caching;
        wconf->okc = conf->okc;
 #ifdef CONFIG_IEEE80211W
        wconf->ieee80211w = conf->ieee80211w;
@@ -77,6 +74,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
        wconf->r0kh_list = conf->r0kh_list;
        wconf->r1kh_list = conf->r1kh_list;
        wconf->pmk_r1_push = conf->pmk_r1_push;
+       wconf->ft_over_ds = conf->ft_over_ds;
 #endif /* CONFIG_IEEE80211R */
 }
 
@@ -188,6 +186,9 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
                                           const u8 *prev_psk)
 {
        struct hostapd_data *hapd = ctx;
+       struct sta_info *sta = ap_get_sta(hapd, addr);
+       if (sta && sta->psk)
+               return sta->psk;
        return hostapd_get_psk(hapd->conf, addr, prev_psk);
 }
 
@@ -230,8 +231,8 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
                        return -1;
        }
 
-       return hapd->drv.set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
-                                key, key_len);
+       return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
+                                  key, key_len);
 }
 
 
@@ -248,7 +249,15 @@ static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr,
                                       int encrypt)
 {
        struct hostapd_data *hapd = ctx;
-       return hapd->drv.send_eapol(hapd, addr, data, data_len, encrypt);
+       struct sta_info *sta;
+       u32 flags = 0;
+
+       sta = ap_get_sta(hapd, addr);
+       if (sta)
+               flags = hostapd_sta_flags_to_drv(sta->flags);
+
+       return hostapd_drv_hapd_send_eapol(hapd, addr, data, data_len,
+                                          encrypt, flags);
 }
 
 
@@ -327,8 +336,9 @@ static int hostapd_wpa_auth_ft_iter(struct hostapd_iface *iface, void *ctx)
                                   MAC2STR(idata->src_hapd->own_addr),
                                   idata->src_hapd->conf->iface,
                                   MAC2STR(hapd->own_addr), hapd->conf->iface);
-                       hostapd_rrb_receive(hapd, idata->src_hapd->own_addr,
-                                           idata->data, idata->data_len);
+                       wpa_ft_rrb_rx(hapd->wpa_auth,
+                                     idata->src_hapd->own_addr,
+                                     idata->data, idata->data_len);
                        return 1;
                }
        }
@@ -343,6 +353,8 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
                                       const u8 *data, size_t data_len)
 {
        struct hostapd_data *hapd = ctx;
+       struct l2_ethhdr *buf;
+       int ret;
 
 #ifdef CONFIG_IEEE80211R
        if (proto == ETH_P_RRB && hapd->iface->for_each_interface) {
@@ -366,7 +378,18 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
                                                data, data_len);
        if (hapd->l2 == NULL)
                return -1;
-       return l2_packet_send(hapd->l2, dst, proto, data, data_len);
+
+       buf = os_malloc(sizeof(*buf) + data_len);
+       if (buf == NULL)
+               return -1;
+       os_memcpy(buf->h_dest, dst, ETH_ALEN);
+       os_memcpy(buf->h_source, hapd->own_addr, ETH_ALEN);
+       buf->h_proto = host_to_be16(proto);
+       os_memcpy(buf + 1, data, data_len);
+       ret = l2_packet_send(hapd->l2, dst, proto, (u8 *) buf,
+                            sizeof(*buf) + data_len);
+       os_free(buf);
+       return ret;
 }
 
 
@@ -396,7 +419,7 @@ static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
        os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
        os_memcpy(&m->u, data, data_len);
 
-       res = hapd->drv.send_mgmt_frame(hapd, (u8 *) m, mlen);
+       res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0);
        os_free(m);
        return res;
 }
@@ -431,7 +454,14 @@ static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
                                size_t len)
 {
        struct hostapd_data *hapd = ctx;
-       wpa_ft_rrb_rx(hapd->wpa_auth, src_addr, buf, len);
+       struct l2_ethhdr *ethhdr;
+       if (len < sizeof(*ethhdr))
+               return;
+       ethhdr = (struct l2_ethhdr *) buf;
+       wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> "
+                  MACSTR, MAC2STR(ethhdr->h_source), MAC2STR(ethhdr->h_dest));
+       wpa_ft_rrb_rx(hapd->wpa_auth, ethhdr->h_source, buf + sizeof(*ethhdr),
+                     len - sizeof(*ethhdr));
 }
 
 #endif /* CONFIG_IEEE80211R */
@@ -445,6 +475,8 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
        size_t wpa_ie_len;
 
        hostapd_wpa_auth_conf(hapd->conf, &_conf);
+       if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
+               _conf.tx_status = 1;
        os_memset(&cb, 0, sizeof(cb));
        cb.ctx = hapd;
        cb.logger = hostapd_wpa_auth_logger;
@@ -494,7 +526,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
                hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ?
                                          hapd->conf->bridge :
                                          hapd->conf->iface, NULL, ETH_P_RRB,
-                                         hostapd_rrb_receive, hapd, 0);
+                                         hostapd_rrb_receive, hapd, 1);
                if (hapd->l2 == NULL &&
                    (hapd->driver == NULL ||
                     hapd->driver->send_ether == NULL)) {
@@ -520,6 +552,7 @@ void hostapd_reconfig_wpa(struct hostapd_data *hapd)
 
 void hostapd_deinit_wpa(struct hostapd_data *hapd)
 {
+       ieee80211_tkip_countermeasures_deinit(hapd);
        rsn_preauth_iface_deinit(hapd);
        if (hapd->wpa_auth) {
                wpa_deinit(hapd->wpa_auth);
index b69129f..d82192a 100644 (file)
@@ -86,6 +86,7 @@ struct wpa_state_machine {
        unsigned int pending_deinit:1;
        unsigned int started:1;
        unsigned int mgmt_frame_prot:1;
+       unsigned int rx_eapol_key_secure:1;
 #ifdef CONFIG_IEEE80211R
        unsigned int ft_completed:1;
        unsigned int pmk_r1_name_valid:1;
@@ -120,6 +121,8 @@ struct wpa_state_machine {
                                               * message 2/4 */
        u8 *assoc_resp_ftie;
 #endif /* CONFIG_IEEE80211R */
+
+       int pending_1_of_4_timeout;
 };
 
 
@@ -145,6 +148,8 @@ struct wpa_group {
        u8 GTK[2][WPA_GTK_MAX_LEN];
        u8 GNonce[WPA_NONCE_LEN];
        Boolean changed;
+       Boolean first_sta_seen;
+       Boolean reject_4way_hs_for_entropy;
 #ifdef CONFIG_IEEE80211W
        u8 IGTK[2][WPA_IGTK_LEN];
        int GN_igtk, GM_igtk;
index f8a1804..4db04bb 100644 (file)
 #include "wpa_auth_i.h"
 
 
+#ifdef CONFIG_RSN_TESTING
+int rsn_testing = 0;
+#endif /* CONFIG_RSN_TESTING */
+
+
 static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
 {
        struct wpa_ie_hdr *hdr;
@@ -141,6 +146,14 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
        count = pos;
        pos += 2;
 
+#ifdef CONFIG_RSN_TESTING
+       if (rsn_testing) {
+               RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1));
+               pos += RSN_SELECTOR_LEN;
+               num_suites++;
+       }
+#endif /* CONFIG_RSN_TESTING */
+
        if (conf->rsn_pairwise & WPA_CIPHER_CCMP) {
                RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
                pos += RSN_SELECTOR_LEN;
@@ -157,6 +170,14 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
                num_suites++;
        }
 
+#ifdef CONFIG_RSN_TESTING
+       if (rsn_testing) {
+               RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2));
+               pos += RSN_SELECTOR_LEN;
+               num_suites++;
+       }
+#endif /* CONFIG_RSN_TESTING */
+
        if (num_suites == 0) {
                wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
                           conf->rsn_pairwise);
@@ -168,6 +189,14 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
        count = pos;
        pos += 2;
 
+#ifdef CONFIG_RSN_TESTING
+       if (rsn_testing) {
+               RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1));
+               pos += RSN_SELECTOR_LEN;
+               num_suites++;
+       }
+#endif /* CONFIG_RSN_TESTING */
+
        if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
                RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
                pos += RSN_SELECTOR_LEN;
@@ -203,6 +232,14 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
        }
 #endif /* CONFIG_IEEE80211W */
 
+#ifdef CONFIG_RSN_TESTING
+       if (rsn_testing) {
+               RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2));
+               pos += RSN_SELECTOR_LEN;
+               num_suites++;
+       }
+#endif /* CONFIG_RSN_TESTING */
+
        if (num_suites == 0) {
                wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
                           conf->wpa_key_mgmt);
@@ -227,6 +264,10 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
                        capab |= WPA_CAPABILITY_MFPR;
        }
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_RSN_TESTING
+       if (rsn_testing)
+               capab |= BIT(8) | BIT(14) | BIT(15);
+#endif /* CONFIG_RSN_TESTING */
        WPA_PUT_LE16(pos, capab);
        pos += 2;
 
@@ -256,6 +297,29 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
        }
 #endif /* CONFIG_IEEE80211W */
 
+#ifdef CONFIG_RSN_TESTING
+       if (rsn_testing) {
+               /*
+                * Fill in any defined fields and add extra data to the end of
+                * the element.
+                */
+               int pmkid_count_set = pmkid != NULL;
+               if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
+                       pmkid_count_set = 1;
+               /* PMKID Count */
+               WPA_PUT_LE16(pos, 0);
+               pos += 2;
+               if (conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
+                       /* Management Group Cipher Suite */
+                       RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+                       pos += RSN_SELECTOR_LEN;
+               }
+
+               os_memset(pos, 0x12, 17);
+               pos += 17;
+       }
+#endif /* CONFIG_RSN_TESTING */
+
        hdr->len = (pos - buf) - 2;
 
        return pos - buf;
@@ -277,8 +341,7 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
                pos += res;
        }
 #ifdef CONFIG_IEEE80211R
-       if (wpa_auth->conf.wpa_key_mgmt &
-           (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) {
+       if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
                res = wpa_write_mdie(&wpa_auth->conf, pos,
                                     buf + sizeof(buf) - pos);
                if (res < 0)
@@ -322,114 +385,6 @@ u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
 }
 
 
-static int wpa_selector_to_bitfield(const u8 *s)
-{
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
-               return WPA_CIPHER_NONE;
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
-               return WPA_CIPHER_WEP40;
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
-               return WPA_CIPHER_TKIP;
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
-               return WPA_CIPHER_CCMP;
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
-               return WPA_CIPHER_WEP104;
-       return 0;
-}
-
-
-static int wpa_key_mgmt_to_bitfield(const u8 *s)
-{
-       if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
-               return WPA_KEY_MGMT_IEEE8021X;
-       if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
-               return WPA_KEY_MGMT_PSK;
-       if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
-               return WPA_KEY_MGMT_WPA_NONE;
-       return 0;
-}
-
-
-static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
-                               struct wpa_ie_data *data)
-{
-       const struct wpa_ie_hdr *hdr;
-       const u8 *pos;
-       int left;
-       int i, count;
-
-       os_memset(data, 0, sizeof(*data));
-       data->pairwise_cipher = WPA_CIPHER_TKIP;
-       data->group_cipher = WPA_CIPHER_TKIP;
-       data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
-       data->mgmt_group_cipher = 0;
-
-       if (wpa_ie_len < sizeof(struct wpa_ie_hdr))
-               return -1;
-
-       hdr = (const struct wpa_ie_hdr *) wpa_ie;
-
-       if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
-           hdr->len != wpa_ie_len - 2 ||
-           RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
-           WPA_GET_LE16(hdr->version) != WPA_VERSION) {
-               return -2;
-       }
-
-       pos = (const u8 *) (hdr + 1);
-       left = wpa_ie_len - sizeof(*hdr);
-
-       if (left >= WPA_SELECTOR_LEN) {
-               data->group_cipher = wpa_selector_to_bitfield(pos);
-               pos += WPA_SELECTOR_LEN;
-               left -= WPA_SELECTOR_LEN;
-       } else if (left > 0)
-                 return -3;
-
-       if (left >= 2) {
-               data->pairwise_cipher = 0;
-               count = WPA_GET_LE16(pos);
-               pos += 2;
-               left -= 2;
-               if (count == 0 || left < count * WPA_SELECTOR_LEN)
-                       return -4;
-               for (i = 0; i < count; i++) {
-                       data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
-                       pos += WPA_SELECTOR_LEN;
-                       left -= WPA_SELECTOR_LEN;
-               }
-       } else if (left == 1)
-               return -5;
-
-       if (left >= 2) {
-               data->key_mgmt = 0;
-               count = WPA_GET_LE16(pos);
-               pos += 2;
-               left -= 2;
-               if (count == 0 || left < count * WPA_SELECTOR_LEN)
-                       return -6;
-               for (i = 0; i < count; i++) {
-                       data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
-                       pos += WPA_SELECTOR_LEN;
-                       left -= WPA_SELECTOR_LEN;
-               }
-       } else if (left == 1)
-               return -7;
-
-       if (left >= 2) {
-               data->capabilities = WPA_GET_LE16(pos);
-               pos += 2;
-               left -= 2;
-       }
-
-       if (left > 0) {
-               return -8;
-       }
-
-       return 0;
-}
-
-
 struct wpa_auth_okc_iter_data {
        struct rsn_pmksa_cache_entry *pmksa;
        const u8 *aa;
index a6ffd4d..817012e 100644 (file)
@@ -28,6 +28,7 @@
 #include "wps/wps_dev_attr.h"
 #include "hostapd.h"
 #include "ap_config.h"
+#include "ap_drv_ops.h"
 #include "beacon.h"
 #include "sta_info.h"
 #include "wps_hostapd.h"
@@ -40,11 +41,51 @@ static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
 static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd);
 #endif /* CONFIG_WPS_UPNP */
 
-static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr,
+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);
 static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
 
 
+struct wps_for_each_data {
+       int (*func)(struct hostapd_data *h, void *ctx);
+       void *ctx;
+};
+
+
+static int wps_for_each(struct hostapd_iface *iface, void *ctx)
+{
+       struct wps_for_each_data *data = ctx;
+       size_t j;
+
+       if (iface == NULL)
+               return 0;
+       for (j = 0; j < iface->num_bss; j++) {
+               struct hostapd_data *hapd = iface->bss[j];
+               int ret = data->func(hapd, data->ctx);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+
+static int hostapd_wps_for_each(struct hostapd_data *hapd,
+                               int (*func)(struct hostapd_data *h, void *ctx),
+                               void *ctx)
+{
+       struct hostapd_iface *iface = hapd->iface;
+       struct wps_for_each_data data;
+       data.func = func;
+       data.ctx = ctx;
+       if (iface->for_each_interface == NULL)
+               return wps_for_each(iface, &data);
+       return iface->for_each_interface(iface->interfaces, wps_for_each,
+                                        &data);
+}
+
+
 static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
                                  size_t psk_len)
 {
@@ -100,8 +141,9 @@ static int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie,
        hapd->wps_beacon_ie = beacon_ie;
        wpabuf_free(hapd->wps_probe_resp_ie);
        hapd->wps_probe_resp_ie = probe_resp_ie;
-       ieee802_11_set_beacon(hapd);
-       return hapd->drv.set_ap_wps_ie(hapd);
+       if (hapd->beacon_set_done)
+               ieee802_11_set_beacon(hapd);
+       return hostapd_set_ap_wps_ie(hapd);
 }
 
 
@@ -144,11 +186,26 @@ 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;
+};
+
+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);
+       return 0;
+}
+
+
 static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
                                       const u8 *uuid_e)
 {
        struct hostapd_data *hapd = ctx;
        char uuid[40];
+       struct wps_stop_reg_data data;
        if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
                return;
        wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s",
@@ -156,6 +213,9 @@ static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
        if (hapd->wps_reg_success_cb)
                hapd->wps_reg_success_cb(hapd->wps_reg_success_cb_ctx,
                                         mac_addr, uuid_e);
+       data.current_hapd = hapd;
+       data.uuid_e = uuid_e;
+       hostapd_wps_for_each(hapd, wps_stop_registrar, &data);
 }
 
 
@@ -200,9 +260,23 @@ static void wps_reload_config(void *eloop_data, void *user_ctx)
 }
 
 
-static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
+static void hapd_new_ap_event(struct hostapd_data *hapd, const u8 *attr,
+                             size_t attr_len)
 {
-       struct hostapd_data *hapd = ctx;
+       size_t blen = attr_len * 2 + 1;
+       char *buf = os_malloc(blen);
+       if (buf) {
+               wpa_snprintf_hex(buf, blen, attr, attr_len);
+               wpa_msg(hapd->msg_ctx, MSG_INFO,
+                       WPS_EVENT_NEW_AP_SETTINGS "%s", buf);
+               os_free(buf);
+       }
+}
+
+
+static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
+{
+       const struct wps_credential *cred = ctx;
        FILE *oconf, *nconf;
        size_t len, i;
        char *tmp_fname;
@@ -210,6 +284,9 @@ static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
        int multi_bss;
        int wpa;
 
+       if (hapd->wps == NULL)
+               return 0;
+
        wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
                        cred->cred_attr, cred->cred_attr_len);
 
@@ -226,15 +303,15 @@ static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
 
        if ((hapd->conf->wps_cred_processing == 1 ||
             hapd->conf->wps_cred_processing == 2) && cred->cred_attr) {
-               size_t blen = cred->cred_attr_len * 2 + 1;
-               char *_buf = os_malloc(blen);
-               if (_buf) {
-                       wpa_snprintf_hex(_buf, blen,
-                                        cred->cred_attr, cred->cred_attr_len);
-                       wpa_msg(hapd->msg_ctx, MSG_INFO, "%s%s",
-                               WPS_EVENT_NEW_AP_SETTINGS, _buf);
-                       os_free(_buf);
-               }
+               hapd_new_ap_event(hapd, cred->cred_attr, cred->cred_attr_len);
+       } else if (hapd->conf->wps_cred_processing == 1 ||
+                  hapd->conf->wps_cred_processing == 2) {
+               struct wpabuf *attr;
+               attr = wpabuf_alloc(200);
+               if (attr && wps_build_credential_wrap(attr, cred) == 0)
+                       hapd_new_ap_event(hapd, wpabuf_head_u8(attr),
+                                         wpabuf_len(attr));
+               wpabuf_free(attr);
        } else
                wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS);
 
@@ -384,6 +461,8 @@ static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
                if (!multi_bss &&
                    (str_starts(buf, "ssid=") ||
                     str_starts(buf, "auth_algs=") ||
+                    str_starts(buf, "wep_default_key=") ||
+                    str_starts(buf, "wep_key") ||
                     str_starts(buf, "wps_state=") ||
                     str_starts(buf, "wpa=") ||
                     str_starts(buf, "wpa_psk=") ||
@@ -414,14 +493,19 @@ static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
        eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface,
                               NULL);
 
-       /* TODO: dualband AP may need to update multiple configuration files */
-
        wpa_printf(MSG_DEBUG, "WPS: AP configuration updated");
 
        return 0;
 }
 
 
+static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
+{
+       struct hostapd_data *hapd = ctx;
+       return hostapd_wps_for_each(hapd, hapd_wps_cred_cb, (void *) cred);
+}
+
+
 static void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx)
 {
        struct hostapd_data *hapd = eloop_data;
@@ -436,11 +520,12 @@ static void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx)
 }
 
 
-static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
-                                 struct wps_event_pwd_auth_fail *data)
+static int wps_pwd_auth_fail(struct hostapd_data *hapd, void *ctx)
 {
-       if (!data->enrollee || hapd->conf->ap_pin == NULL)
-               return;
+       struct wps_event_pwd_auth_fail *data = ctx;
+
+       if (!data->enrollee || hapd->conf->ap_pin == NULL || hapd->wps == NULL)
+               return 0;
 
        /*
         * Registrar failed to prove its knowledge of the AP PIN. Lock AP setup
@@ -451,7 +536,7 @@ static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
        wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u",
                   hapd->ap_pin_failures);
        if (hapd->ap_pin_failures < 3)
-               return;
+               return 0;
 
        wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED);
        hapd->wps->ap_setup_locked = 1;
@@ -473,7 +558,37 @@ static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
                                       NULL);
        }
 
-       /* TODO: dualband AP may need to update other interfaces */
+       return 0;
+}
+
+
+static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
+                                 struct wps_event_pwd_auth_fail *data)
+{
+       hostapd_wps_for_each(hapd, wps_pwd_auth_fail, data);
+}
+
+
+static const char * wps_event_fail_reason[NUM_WPS_EI_VALUES] = {
+       "No Error", /* WPS_EI_NO_ERROR */
+       "TKIP Only Prohibited", /* WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED */
+       "WEP Prohibited" /* WPS_EI_SECURITY_WEP_PROHIBITED */
+};
+
+static void hostapd_wps_event_fail(struct hostapd_data *hapd,
+                                  struct wps_event_fail *fail)
+{
+       if (fail->error_indication > 0 &&
+           fail->error_indication < NUM_WPS_EI_VALUES) {
+               wpa_msg(hapd->msg_ctx, MSG_INFO,
+                       WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)",
+                       fail->msg, fail->config_error, fail->error_indication,
+                       wps_event_fail_reason[fail->error_indication]);
+       } else {
+               wpa_msg(hapd->msg_ctx, MSG_INFO,
+                       WPS_EVENT_FAIL "msg=%d config_error=%d",
+                       fail->msg, fail->config_error);
+       }
 }
 
 
@@ -482,8 +597,40 @@ static void hostapd_wps_event_cb(void *ctx, enum wps_event event,
 {
        struct hostapd_data *hapd = ctx;
 
-       if (event == WPS_EV_PWD_AUTH_FAIL)
+       switch (event) {
+       case WPS_EV_M2D:
+               wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_M2D);
+               break;
+       case WPS_EV_FAIL:
+               hostapd_wps_event_fail(hapd, &data->fail);
+               break;
+       case WPS_EV_SUCCESS:
+               wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_SUCCESS);
+               break;
+       case WPS_EV_PWD_AUTH_FAIL:
                hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail);
+               break;
+       case WPS_EV_PBC_OVERLAP:
+               wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_OVERLAP);
+               break;
+       case WPS_EV_PBC_TIMEOUT:
+               wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_TIMEOUT);
+               break;
+       case WPS_EV_ER_AP_ADD:
+               break;
+       case WPS_EV_ER_AP_REMOVE:
+               break;
+       case WPS_EV_ER_ENROLLEE_ADD:
+               break;
+       case WPS_EV_ER_ENROLLEE_REMOVE:
+               break;
+       case WPS_EV_ER_AP_SETTINGS:
+               break;
+       case WPS_EV_ER_SET_SELECTED_REGISTRAR:
+               break;
+       }
+       if (hapd->wps_event_cb)
+               hapd->wps_event_cb(hapd->wps_event_cb_ctx, event, data);
 }
 
 
@@ -495,7 +642,81 @@ static void hostapd_wps_clear_ies(struct hostapd_data *hapd)
        wpabuf_free(hapd->wps_probe_resp_ie);
        hapd->wps_probe_resp_ie = NULL;
 
-       hapd->drv.set_ap_wps_ie(hapd);
+       hostapd_set_ap_wps_ie(hapd);
+}
+
+
+static int get_uuid_cb(struct hostapd_iface *iface, void *ctx)
+{
+       const u8 **uuid = ctx;
+       size_t j;
+
+       if (iface == NULL)
+               return 0;
+       for (j = 0; j < iface->num_bss; j++) {
+               struct hostapd_data *hapd = iface->bss[j];
+               if (hapd->wps && !is_nil_uuid(hapd->wps->uuid)) {
+                       *uuid = hapd->wps->uuid;
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+
+static const u8 * get_own_uuid(struct hostapd_iface *iface)
+{
+       const u8 *uuid;
+       if (iface->for_each_interface == NULL)
+               return NULL;
+       uuid = NULL;
+       iface->for_each_interface(iface->interfaces, get_uuid_cb, &uuid);
+       return uuid;
+}
+
+
+static int count_interface_cb(struct hostapd_iface *iface, void *ctx)
+{
+       int *count= ctx;
+       (*count)++;
+       return 0;
+}
+
+
+static int interface_count(struct hostapd_iface *iface)
+{
+       int count = 0;
+       if (iface->for_each_interface == NULL)
+               return 0;
+       iface->for_each_interface(iface->interfaces, count_interface_cb,
+                                 &count);
+       return count;
+}
+
+
+static int hostapd_wps_set_vendor_ext(struct hostapd_data *hapd,
+                                     struct wps_context *wps)
+{
+       int i;
+
+       for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+               wpabuf_free(wps->dev.vendor_ext[i]);
+               wps->dev.vendor_ext[i] = NULL;
+
+               if (hapd->conf->wps_vendor_ext[i] == NULL)
+                       continue;
+
+               wps->dev.vendor_ext[i] =
+                       wpabuf_dup(hapd->conf->wps_vendor_ext[i]);
+               if (wps->dev.vendor_ext[i] == NULL) {
+                       while (--i >= 0)
+                               wpabuf_free(wps->dev.vendor_ext[i]);
+                       return -1;
+               }
+       }
+
+       return 0;
 }
 
 
@@ -522,11 +743,22 @@ int hostapd_init_wps(struct hostapd_data *hapd,
        wps->wps_state = hapd->conf->wps_state;
        wps->ap_setup_locked = hapd->conf->ap_setup_locked;
        if (is_nil_uuid(hapd->conf->uuid)) {
-               uuid_gen_mac_addr(hapd->own_addr, wps->uuid);
-               wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC address",
-                           wps->uuid, UUID_LEN);
-       } else
+               const u8 *uuid;
+               uuid = get_own_uuid(hapd->iface);
+               if (uuid) {
+                       os_memcpy(wps->uuid, uuid, UUID_LEN);
+                       wpa_hexdump(MSG_DEBUG, "WPS: Clone UUID from another "
+                                   "interface", wps->uuid, UUID_LEN);
+               } else {
+                       uuid_gen_mac_addr(hapd->own_addr, wps->uuid);
+                       wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC "
+                                   "address", wps->uuid, UUID_LEN);
+               }
+       } else {
                os_memcpy(wps->uuid, hapd->conf->uuid, UUID_LEN);
+               wpa_hexdump(MSG_DEBUG, "WPS: Use configured UUID",
+                           wps->uuid, UUID_LEN);
+       }
        wps->ssid_len = hapd->conf->ssid.ssid_len;
        os_memcpy(wps->ssid, hapd->conf->ssid.ssid, wps->ssid_len);
        wps->ap = 1;
@@ -543,16 +775,39 @@ int hostapd_init_wps(struct hostapd_data *hapd,
                os_strdup(hapd->conf->serial_number) : NULL;
        wps->config_methods =
                wps_config_methods_str2bin(hapd->conf->config_methods);
-       if (hapd->conf->device_type &&
-           wps_dev_type_str2bin(hapd->conf->device_type,
-                                wps->dev.pri_dev_type) < 0) {
-               wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
+#ifdef CONFIG_WPS2
+       if ((wps->config_methods &
+            (WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY |
+             WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) {
+               wpa_printf(MSG_INFO, "WPS: Converting display to "
+                          "virtual_display for WPS 2.0 compliance");
+               wps->config_methods |= WPS_CONFIG_VIRT_DISPLAY;
+       }
+       if ((wps->config_methods &
+            (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON |
+             WPS_CONFIG_PHY_PUSHBUTTON)) == WPS_CONFIG_PUSHBUTTON) {
+               wpa_printf(MSG_INFO, "WPS: Converting push_button to "
+                          "virtual_push_button for WPS 2.0 compliance");
+               wps->config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
+       }
+#endif /* CONFIG_WPS2 */
+       os_memcpy(wps->dev.pri_dev_type, hapd->conf->device_type,
+                 WPS_DEV_TYPE_LEN);
+
+       if (hostapd_wps_set_vendor_ext(hapd, wps) < 0) {
                os_free(wps);
                return -1;
        }
+
        wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
-       wps->dev.rf_bands = hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
-               WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
+
+       if (conf->wps_rf_bands) {
+               wps->dev.rf_bands = conf->wps_rf_bands;
+       } else {
+               wps->dev.rf_bands =
+                       hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
+                       WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
+       }
 
        if (conf->wpa & WPA_PROTO_RSN) {
                if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
@@ -647,10 +902,13 @@ int hostapd_init_wps(struct hostapd_data *hapd,
                conf->skip_cred_build;
        if (conf->ssid.security_policy == SECURITY_STATIC_WEP)
                cfg.static_wep_only = 1;
+       cfg.dualband = interface_count(hapd->iface) > 1;
+       if (cfg.dualband)
+               wpa_printf(MSG_DEBUG, "WPS: Dualband AP");
 
        wps->registrar = wps_registrar_init(wps, &cfg);
        if (wps->registrar == NULL) {
-               printf("Failed to initialize WPS Registrar\n");
+               wpa_printf(MSG_ERROR, "Failed to initialize WPS Registrar");
                os_free(wps->network_key);
                os_free(wps);
                return -1;
@@ -662,20 +920,34 @@ int hostapd_init_wps(struct hostapd_data *hapd,
        wps->model_description = hapd->conf->model_description;
        wps->model_url = hapd->conf->model_url;
        wps->upc = hapd->conf->upc;
+#endif /* CONFIG_WPS_UPNP */
+
+       hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd);
+
+       hapd->wps = wps;
+
+       return 0;
+}
 
+
+int hostapd_init_wps_complete(struct hostapd_data *hapd)
+{
+       struct wps_context *wps = hapd->wps;
+
+       if (wps == NULL)
+               return 0;
+
+#ifdef CONFIG_WPS_UPNP
        if (hostapd_wps_upnp_init(hapd, wps) < 0) {
                wpa_printf(MSG_ERROR, "Failed to initialize WPS UPnP");
                wps_registrar_deinit(wps->registrar);
                os_free(wps->network_key);
                os_free(wps);
+               hapd->wps = NULL;
                return -1;
        }
 #endif /* CONFIG_WPS_UPNP */
 
-       hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd);
-
-       hapd->wps = wps;
-
        return 0;
 }
 
@@ -707,6 +979,17 @@ void hostapd_update_wps(struct hostapd_data *hapd)
 {
        if (hapd->wps == NULL)
                return;
+
+#ifdef CONFIG_WPS_UPNP
+       hapd->wps->friendly_name = hapd->conf->friendly_name;
+       hapd->wps->manufacturer_url = hapd->conf->manufacturer_url;
+       hapd->wps->model_description = hapd->conf->model_description;
+       hapd->wps->model_url = hapd->conf->model_url;
+       hapd->wps->upc = hapd->conf->upc;
+#endif /* CONFIG_WPS_UPNP */
+
+       hostapd_wps_set_vendor_ext(hapd, hapd->wps);
+
        if (hapd->conf->wps_state)
                wps_registrar_update_ie(hapd->wps->registrar);
        else
@@ -714,29 +997,72 @@ void hostapd_update_wps(struct hostapd_data *hapd)
 }
 
 
-int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
-                       const char *pin, int timeout)
+struct wps_add_pin_data {
+       const u8 *addr;
+       const u8 *uuid;
+       const u8 *pin;
+       size_t pin_len;
+       int timeout;
+       int added;
+};
+
+
+static int wps_add_pin(struct hostapd_data *hapd, void *ctx)
 {
-       u8 u[UUID_LEN];
-       int any = 0;
+       struct wps_add_pin_data *data = ctx;
+       int ret;
 
        if (hapd->wps == NULL)
-               return -1;
+               return 0;
+       ret = wps_registrar_add_pin(hapd->wps->registrar, data->addr,
+                                   data->uuid, data->pin, data->pin_len,
+                                   data->timeout);
+       if (ret == 0)
+               data->added++;
+       return ret;
+}
+
+
+int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
+                       const char *uuid, const char *pin, int timeout)
+{
+       u8 u[UUID_LEN];
+       struct wps_add_pin_data data;
+
+       data.addr = addr;
+       data.uuid = u;
+       data.pin = (const u8 *) pin;
+       data.pin_len = os_strlen(pin);
+       data.timeout = timeout;
+       data.added = 0;
+
        if (os_strcmp(uuid, "any") == 0)
-               any = 1;
-       else if (uuid_str2bin(uuid, u))
+               data.uuid = NULL;
+       else {
+               if (uuid_str2bin(uuid, u))
+                       return -1;
+               data.uuid = u;
+       }
+       if (hostapd_wps_for_each(hapd, wps_add_pin, &data) < 0)
                return -1;
-       return wps_registrar_add_pin(hapd->wps->registrar, any ? NULL : u,
-                                    (const u8 *) pin, os_strlen(pin),
-                                    timeout);
+       return data.added ? 0 : -1;
 }
 
 
-int hostapd_wps_button_pushed(struct hostapd_data *hapd)
+static int wps_button_pushed(struct hostapd_data *hapd, void *ctx)
 {
+       const u8 *p2p_dev_addr = ctx;
        if (hapd->wps == NULL)
-               return -1;
-       return wps_registrar_button_pushed(hapd->wps->registrar);
+               return 0;
+       return wps_registrar_button_pushed(hapd->wps->registrar, p2p_dev_addr);
+}
+
+
+int hostapd_wps_button_pushed(struct hostapd_data *hapd,
+                             const u8 *p2p_dev_addr)
+{
+       return hostapd_wps_for_each(hapd, wps_button_pushed,
+                                   (void *) p2p_dev_addr);
 }
 
 
@@ -777,7 +1103,7 @@ int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
 
        if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ||
             wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) &&
-           hostapd_wps_add_pin(hapd, "any",
+           hostapd_wps_add_pin(hapd, NULL, "any",
                                wpabuf_head(wps->oob_conf.dev_password), 0) <
            0)
                goto error;
@@ -794,7 +1120,8 @@ error:
 #endif /* CONFIG_WPS_OOB */
 
 
-static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr,
+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)
 {
        struct hostapd_data *hapd = ctx;
@@ -819,15 +1146,28 @@ static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr,
        wps_ie = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
        if (wps_ie == NULL)
                return 0;
+       if (wps_validate_probe_req(wps_ie, addr) < 0) {
+               wpabuf_free(wps_ie);
+               return 0;
+       }
 
        if (wpabuf_len(wps_ie) > 0) {
-               wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie);
+               int p2p_wildcard = 0;
+#ifdef CONFIG_P2P
+               if (elems.ssid && elems.ssid_len == P2P_WILDCARD_SSID_LEN &&
+                   os_memcmp(elems.ssid, P2P_WILDCARD_SSID,
+                             P2P_WILDCARD_SSID_LEN) == 0)
+                       p2p_wildcard = 1;
+#endif /* CONFIG_P2P */
+               wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie,
+                                          p2p_wildcard);
 #ifdef CONFIG_WPS_UPNP
                /* FIX: what exactly should be included in the WLANEvent?
                 * WPS attributes? Full ProbeReq frame? */
-               upnp_wps_device_send_wlan_event(hapd->wps_upnp, addr,
-                                               UPNP_WPS_WLANEVENT_TYPE_PROBE,
-                                               wps_ie);
+               if (!p2p_wildcard)
+                       upnp_wps_device_send_wlan_event(
+                               hapd->wps_upnp, addr,
+                               UPNP_WPS_WLANEVENT_TYPE_PROBE, wps_ie);
 #endif /* CONFIG_WPS_UPNP */
        }
 
@@ -864,6 +1204,7 @@ static int hostapd_rx_req_put_wlan_response(
         */
 
        sta = ap_get_sta(hapd, mac_addr);
+#ifndef CONFIG_WPS_STRICT
        if (!sta) {
                /*
                 * Workaround - Intel wsccmd uses bogus NewWLANEventMAC:
@@ -877,8 +1218,9 @@ static int hostapd_rx_req_put_wlan_response(
                                break;
                }
        }
+#endif /* CONFIG_WPS_STRICT */
 
-       if (!sta) {
+       if (!sta || !(sta->flags & WLAN_STA_WPS)) {
                wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found");
                return 0;
        }
@@ -911,26 +1253,19 @@ static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
        if (hapd->conf->ap_pin)
                ctx->ap_pin = os_strdup(hapd->conf->ap_pin);
 
-       hapd->wps_upnp = upnp_wps_device_init(ctx, wps, hapd);
-       if (hapd->wps_upnp == NULL) {
-               os_free(ctx);
+       hapd->wps_upnp = upnp_wps_device_init(ctx, wps, hapd,
+                                             hapd->conf->upnp_iface);
+       if (hapd->wps_upnp == NULL)
                return -1;
-       }
        wps->wps_upnp = hapd->wps_upnp;
 
-       if (upnp_wps_device_start(hapd->wps_upnp, hapd->conf->upnp_iface)) {
-               upnp_wps_device_deinit(hapd->wps_upnp);
-               hapd->wps_upnp = NULL;
-               return -1;
-       }
-
        return 0;
 }
 
 
 static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd)
 {
-       upnp_wps_device_deinit(hapd->wps_upnp);
+       upnp_wps_device_deinit(hapd->wps_upnp, hapd);
 }
 
 #endif /* CONFIG_WPS_UPNP */
@@ -950,6 +1285,7 @@ static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx)
        struct hostapd_data *hapd = eloop_data;
        wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out");
        hostapd_wps_ap_pin_disable(hapd);
+       wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_PIN_DISABLED);
 }
 
 
@@ -970,31 +1306,53 @@ static void hostapd_wps_ap_pin_enable(struct hostapd_data *hapd, int timeout)
 }
 
 
-void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd)
+static int wps_ap_pin_disable(struct hostapd_data *hapd, void *ctx)
 {
-       wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN");
        os_free(hapd->conf->ap_pin);
        hapd->conf->ap_pin = NULL;
 #ifdef CONFIG_WPS_UPNP
        upnp_wps_set_ap_pin(hapd->wps_upnp, NULL);
 #endif /* CONFIG_WPS_UPNP */
        eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
+       return 0;
 }
 
 
-const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout)
+void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd)
 {
-       unsigned int pin;
+       wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN");
+       hostapd_wps_for_each(hapd, wps_ap_pin_disable, NULL);
+}
+
+
+struct wps_ap_pin_data {
        char pin_txt[9];
+       int timeout;
+};
 
-       pin = wps_generate_pin();
-       os_snprintf(pin_txt, sizeof(pin_txt), "%u", pin);
+
+static int wps_ap_pin_set(struct hostapd_data *hapd, void *ctx)
+{
+       struct wps_ap_pin_data *data = ctx;
        os_free(hapd->conf->ap_pin);
-       hapd->conf->ap_pin = os_strdup(pin_txt);
+       hapd->conf->ap_pin = os_strdup(data->pin_txt);
 #ifdef CONFIG_WPS_UPNP
-       upnp_wps_set_ap_pin(hapd->wps_upnp, pin_txt);
+       upnp_wps_set_ap_pin(hapd->wps_upnp, data->pin_txt);
 #endif /* CONFIG_WPS_UPNP */
-       hostapd_wps_ap_pin_enable(hapd, timeout);
+       hostapd_wps_ap_pin_enable(hapd, data->timeout);
+       return 0;
+}
+
+
+const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout)
+{
+       unsigned int pin;
+       struct wps_ap_pin_data data;
+
+       pin = wps_generate_pin();
+       os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%08u", pin);
+       data.timeout = timeout;
+       hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
        return hapd->conf->ap_pin;
 }
 
@@ -1008,13 +1366,75 @@ const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd)
 int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
                           int timeout)
 {
-       os_free(hapd->conf->ap_pin);
-       hapd->conf->ap_pin = os_strdup(pin);
-       if (hapd->conf->ap_pin == NULL)
+       struct wps_ap_pin_data data;
+       int ret;
+
+       ret = os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%s", pin);
+       if (ret < 0 || ret >= (int) sizeof(data.pin_txt))
                return -1;
-#ifdef CONFIG_WPS_UPNP
-       upnp_wps_set_ap_pin(hapd->wps_upnp, hapd->conf->ap_pin);
-#endif /* CONFIG_WPS_UPNP */
-       hostapd_wps_ap_pin_enable(hapd, timeout);
+       data.timeout = timeout;
+       return hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
+}
+
+
+static int wps_update_ie(struct hostapd_data *hapd, void *ctx)
+{
+       if (hapd->wps)
+               wps_registrar_update_ie(hapd->wps->registrar);
        return 0;
 }
+
+
+void hostapd_wps_update_ie(struct hostapd_data *hapd)
+{
+       hostapd_wps_for_each(hapd, wps_update_ie, NULL);
+}
+
+
+int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
+                         const char *auth, const char *encr, const char *key)
+{
+       struct wps_credential cred;
+       size_t len;
+
+       os_memset(&cred, 0, sizeof(cred));
+
+       len = os_strlen(ssid);
+       if ((len & 1) || len > 2 * sizeof(cred.ssid) ||
+           hexstr2bin(ssid, cred.ssid, len / 2))
+               return -1;
+       cred.ssid_len = len / 2;
+
+       if (os_strncmp(auth, "OPEN", 4) == 0)
+               cred.auth_type = WPS_AUTH_OPEN;
+       else if (os_strncmp(auth, "WPAPSK", 6) == 0)
+               cred.auth_type = WPS_AUTH_WPAPSK;
+       else if (os_strncmp(auth, "WPA2PSK", 7) == 0)
+               cred.auth_type = WPS_AUTH_WPA2PSK;
+       else
+               return -1;
+
+       if (encr) {
+               if (os_strncmp(encr, "NONE", 4) == 0)
+                       cred.encr_type = WPS_ENCR_NONE;
+               else if (os_strncmp(encr, "WEP", 3) == 0)
+                       cred.encr_type = WPS_ENCR_WEP;
+               else if (os_strncmp(encr, "TKIP", 4) == 0)
+                       cred.encr_type = WPS_ENCR_TKIP;
+               else if (os_strncmp(encr, "CCMP", 4) == 0)
+                       cred.encr_type = WPS_ENCR_AES;
+               else
+                       return -1;
+       } else
+               cred.encr_type = WPS_ENCR_NONE;
+
+       if (key) {
+               len = os_strlen(key);
+               if ((len & 1) || len > 2 * sizeof(cred.key) ||
+                   hexstr2bin(key, cred.key, len / 2))
+                       return -1;
+               cred.key_len = len / 2;
+       }
+
+       return wps_registrar_config_ap(hapd->wps->registrar, &cred);
+}
index e978a1c..6b28c13 100644 (file)
 
 int hostapd_init_wps(struct hostapd_data *hapd,
                     struct hostapd_bss_config *conf);
+int hostapd_init_wps_complete(struct hostapd_data *hapd);
 void hostapd_deinit_wps(struct hostapd_data *hapd);
 void hostapd_update_wps(struct hostapd_data *hapd);
-int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
-                       const char *pin, int timeout);
-int hostapd_wps_button_pushed(struct hostapd_data *hapd);
+int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
+                       const char *uuid, const char *pin, int timeout);
+int hostapd_wps_button_pushed(struct hostapd_data *hapd,
+                             const u8 *p2p_dev_addr);
 int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
                          char *path, char *method, char *name);
 int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
@@ -33,6 +35,9 @@ const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout);
 const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd);
 int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
                           int timeout);
+void hostapd_wps_update_ie(struct hostapd_data *hapd);
+int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
+                         const char *auth, const char *encr, const char *key);
 
 #else /* CONFIG_WPS */
 
@@ -46,6 +51,11 @@ static inline void hostapd_deinit_wps(struct hostapd_data *hapd)
 {
 }
 
+static inline int hostapd_init_wps_complete(struct hostapd_data *hapd)
+{
+    return 0;
+}
+
 static inline void hostapd_update_wps(struct hostapd_data *hapd)
 {
 }
@@ -57,7 +67,8 @@ static inline int hostapd_wps_get_mib_sta(struct hostapd_data *hapd,
        return 0;
 }
 
-static inline int hostapd_wps_button_pushed(struct hostapd_data *hapd)
+static inline int hostapd_wps_button_pushed(struct hostapd_data *hapd,
+                                           const u8 *p2p_dev_addr)
 {
        return 0;
 }
index 173bbd1..6082053 100644 (file)
@@ -46,28 +46,39 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
 
 static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
 {
-       return akm == WPA_KEY_MGMT_IEEE8021X ||
-               akm == WPA_KEY_MGMT_FT_IEEE8021X ||
-               akm == WPA_KEY_MGMT_IEEE8021X_SHA256;
+       return !!(akm & (WPA_KEY_MGMT_IEEE8021X |
+                        WPA_KEY_MGMT_FT_IEEE8021X |
+                        WPA_KEY_MGMT_IEEE8021X_SHA256));
 }
 
 static inline int wpa_key_mgmt_wpa_psk(int akm)
 {
-       return akm == WPA_KEY_MGMT_PSK ||
-               akm == WPA_KEY_MGMT_FT_PSK ||
-               akm == WPA_KEY_MGMT_PSK_SHA256;
+       return !!(akm & (WPA_KEY_MGMT_PSK |
+                        WPA_KEY_MGMT_FT_PSK |
+                        WPA_KEY_MGMT_PSK_SHA256));
 }
 
 static inline int wpa_key_mgmt_ft(int akm)
 {
-       return akm == WPA_KEY_MGMT_FT_PSK ||
-               akm == WPA_KEY_MGMT_FT_IEEE8021X;
+       return !!(akm & (WPA_KEY_MGMT_FT_PSK |
+                        WPA_KEY_MGMT_FT_IEEE8021X));
 }
 
 static inline int wpa_key_mgmt_sha256(int akm)
 {
-       return akm == WPA_KEY_MGMT_PSK_SHA256 ||
-               akm == WPA_KEY_MGMT_IEEE8021X_SHA256;
+       return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 |
+                        WPA_KEY_MGMT_IEEE8021X_SHA256));
+}
+
+static inline int wpa_key_mgmt_wpa(int akm)
+{
+       return wpa_key_mgmt_wpa_ieee8021x(akm) ||
+               wpa_key_mgmt_wpa_psk(akm);
+}
+
+static inline int wpa_key_mgmt_wpa_any(int akm)
+{
+       return wpa_key_mgmt_wpa(akm) || (akm & WPA_KEY_MGMT_WPA_NONE);
 }
 
 
@@ -137,6 +148,15 @@ enum wpa_states {
        WPA_DISCONNECTED,
 
        /**
+        * WPA_INTERFACE_DISABLED - Interface disabled
+        *
+        * This stat eis entered if the network interface is disabled, e.g.,
+        * due to rfkill. wpa_supplicant refuses any new operations that would
+        * use the radio until the interface has been enabled.
+        */
+       WPA_INTERFACE_DISABLED,
+
+       /**
         * WPA_INACTIVE - Inactive state (wpa_supplicant disabled)
         *
         * This state is entered if there are no enabled networks in the
@@ -252,4 +272,21 @@ enum hostapd_hw_mode {
        NUM_HOSTAPD_MODES
 };
 
+/**
+ * enum wpa_ctrl_req_type - Control interface request types
+ */
+enum wpa_ctrl_req_type {
+       WPA_CTRL_REQ_UNKNOWN,
+       WPA_CTRL_REQ_EAP_IDENTITY,
+       WPA_CTRL_REQ_EAP_PASSWORD,
+       WPA_CTRL_REQ_EAP_NEW_PASSWORD,
+       WPA_CTRL_REQ_EAP_PIN,
+       WPA_CTRL_REQ_EAP_OTP,
+       WPA_CTRL_REQ_EAP_PASSPHRASE,
+       NUM_WPA_CTRL_REQS
+};
+
+/* Maximum number of EAP methods to store for EAP server user information */
+#define EAP_MAX_METHODS 8
+
 #endif /* DEFS_H */
diff --git a/src/common/gas.c b/src/common/gas.c
new file mode 100644 (file)
index 0000000..babdaa3
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Generic advertisement service (GAS) (IEEE 802.11u)
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "ieee802_11_defs.h"
+#include "gas.h"
+
+
+static struct wpabuf *
+gas_build_req(u8 action, u8 dialog_token, size_t size)
+{
+       struct wpabuf *buf;
+
+       buf = wpabuf_alloc(100 + size);
+       if (buf == NULL)
+               return NULL;
+
+       wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+       wpabuf_put_u8(buf, action);
+       wpabuf_put_u8(buf, dialog_token);
+
+       return buf;
+}
+
+
+static struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size)
+{
+       return gas_build_req(WLAN_PA_GAS_INITIAL_REQ, dialog_token,
+                            size);
+}
+
+
+struct wpabuf * gas_build_comeback_req(u8 dialog_token)
+{
+       return gas_build_req(WLAN_PA_GAS_COMEBACK_REQ, dialog_token, 0);
+}
+
+
+static struct wpabuf *
+gas_build_resp(u8 action, u8 dialog_token, u16 status_code, u8 frag_id,
+              u8 more, u16 comeback_delay, size_t size)
+{
+       struct wpabuf *buf;
+
+       buf = wpabuf_alloc(100 + size);
+       if (buf == NULL)
+               return NULL;
+
+       wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+       wpabuf_put_u8(buf, action);
+       wpabuf_put_u8(buf, dialog_token);
+       wpabuf_put_le16(buf, status_code);
+       if (action == WLAN_PA_GAS_COMEBACK_RESP)
+               wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0));
+       wpabuf_put_le16(buf, comeback_delay);
+
+       return buf;
+}
+
+
+struct wpabuf *
+gas_build_initial_resp(u8 dialog_token, u16 status_code, u16 comeback_delay,
+                      size_t size)
+{
+       return gas_build_resp(WLAN_PA_GAS_INITIAL_RESP, dialog_token,
+                             status_code, 0, 0, comeback_delay, size);
+}
+
+
+static struct wpabuf *
+gas_build_comeback_resp(u8 dialog_token, u16 status_code, u8 frag_id, u8 more,
+                       u16 comeback_delay, size_t size)
+{
+       return gas_build_resp(WLAN_PA_GAS_COMEBACK_RESP, dialog_token,
+                             status_code, frag_id, more, comeback_delay,
+                             size);
+}
+
+
+/**
+ * gas_add_adv_proto_anqp - Add an Advertisement Protocol element
+ * @buf: Buffer to which the element is added
+ * @query_resp_len_limit: Query Response Length Limit in units of 256 octets
+ * @pame_bi: Pre-Association Message Exchange BSSID Independent (0/1)
+ *
+ *
+ * @query_resp_len_limit is 0 for request and 1-0x7f for response. 0x7f means
+ * that the maximum limit is determined by the maximum allowable number of
+ * fragments in the GAS Query Response Fragment ID.
+ */
+static void gas_add_adv_proto_anqp(struct wpabuf *buf, u8 query_resp_len_limit,
+                                  u8 pame_bi)
+{
+       /* Advertisement Protocol IE */
+       wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
+       wpabuf_put_u8(buf, 2); /* Length */
+       wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) |
+                     (pame_bi ? 0x80 : 0));
+       /* Advertisement Protocol */
+       wpabuf_put_u8(buf, ACCESS_NETWORK_QUERY_PROTOCOL);
+}
+
+
+struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size)
+{
+       struct wpabuf *buf;
+
+       buf = gas_build_initial_req(dialog_token, 4 + size);
+       if (buf == NULL)
+               return NULL;
+
+       gas_add_adv_proto_anqp(buf, 0, 0);
+
+       wpabuf_put(buf, 2); /* Query Request Length to be filled */
+
+       return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
+                                           u16 comeback_delay, size_t size)
+{
+       struct wpabuf *buf;
+
+       buf = gas_build_initial_resp(dialog_token, status_code, comeback_delay,
+                                    4 + size);
+       if (buf == NULL)
+               return NULL;
+
+       gas_add_adv_proto_anqp(buf, 0x7f, 0);
+
+       wpabuf_put(buf, 2); /* Query Response Length to be filled */
+
+       return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
+                                               u16 status_code,
+                                               u16 comeback_delay,
+                                               struct wpabuf *payload)
+{
+       struct wpabuf *buf;
+
+       buf = gas_anqp_build_initial_resp(dialog_token, status_code,
+                                         comeback_delay,
+                                         payload ? wpabuf_len(payload) : 0);
+       if (buf == NULL)
+               return NULL;
+
+       if (payload)
+               wpabuf_put_buf(buf, payload);
+
+       gas_anqp_set_len(buf);
+
+       return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
+                                            u8 frag_id, u8 more,
+                                            u16 comeback_delay, size_t size)
+{
+       struct wpabuf *buf;
+
+       buf = gas_build_comeback_resp(dialog_token, status_code,
+                                     frag_id, more, comeback_delay, 4 + size);
+       if (buf == NULL)
+               return NULL;
+
+       gas_add_adv_proto_anqp(buf, 0x7f, 0);
+
+       wpabuf_put(buf, 2); /* Query Response Length to be filled */
+
+       return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
+                                                u16 status_code,
+                                                u8 frag_id, u8 more,
+                                                u16 comeback_delay,
+                                                struct wpabuf *payload)
+{
+       struct wpabuf *buf;
+
+       buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
+                                          more, comeback_delay,
+                                          payload ? wpabuf_len(payload) : 0);
+       if (buf == NULL)
+               return NULL;
+
+       if (payload)
+               wpabuf_put_buf(buf, payload);
+
+       gas_anqp_set_len(buf);
+
+       return buf;
+}
+
+
+/**
+ * gas_anqp_set_len - Set Query Request/Response Length
+ * @buf: GAS message
+ *
+ * This function is used to update the Query Request/Response Length field once
+ * the payload has been filled.
+ */
+void gas_anqp_set_len(struct wpabuf *buf)
+{
+       u8 action;
+       size_t offset;
+       u8 *len;
+
+       if (buf == NULL || wpabuf_len(buf) < 2)
+               return;
+
+       action = *(wpabuf_head_u8(buf) + 1);
+       switch (action) {
+       case WLAN_PA_GAS_INITIAL_REQ:
+               offset = 3 + 4;
+               break;
+       case WLAN_PA_GAS_INITIAL_RESP:
+               offset = 7 + 4;
+               break;
+       case WLAN_PA_GAS_COMEBACK_RESP:
+               offset = 8 + 4;
+               break;
+       default:
+               return;
+       }
+
+       if (wpabuf_len(buf) < offset + 2)
+               return;
+
+       len = wpabuf_mhead_u8(buf) + offset;
+       WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
+}
+
+
+/**
+ * gas_anqp_add_element - Add ANQP element header
+ * @buf: GAS message
+ * @info_id: ANQP Info ID
+ * Returns: Pointer to the Length field for gas_anqp_set_element_len()
+ */
+u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id)
+{
+       wpabuf_put_le16(buf, info_id);
+       return wpabuf_put(buf, 2); /* Length to be filled */
+}
+
+
+/**
+ * gas_anqp_set_element_len - Update ANQP element Length field
+ * @buf: GAS message
+ * @len_pos: Length field position from gas_anqp_add_element()
+ *
+ * This function is called after the ANQP element payload has been added to the
+ * buffer.
+ */
+void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos)
+{
+       WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
+}
diff --git a/src/common/gas.h b/src/common/gas.h
new file mode 100644 (file)
index 0000000..2f8d2cb
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Generic advertisement service (GAS) (IEEE 802.11u)
+ * 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.
+ */
+
+#ifndef GAS_H
+#define GAS_H
+
+struct wpabuf * gas_build_comeback_req(u8 dialog_token);
+struct wpabuf * gas_build_initial_resp(u8 dialog_token, u16 status_code,
+                                      u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size);
+struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
+                                           u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
+                                               u16 status_code,
+                                               u16 comeback_delay,
+                                               struct wpabuf *payload);
+struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
+                                            u8 frag_id, u8 more,
+                                            u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
+                                                u16 status_code,
+                                                u8 frag_id, u8 more,
+                                                u16 comeback_delay,
+                                                struct wpabuf *payload);
+void gas_anqp_set_len(struct wpabuf *buf);
+
+u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id);
+void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos);
+
+#endif /* GAS_H */
index 96ef5b6..43cb2c6 100644 (file)
@@ -75,7 +75,7 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
                                elems->wmm_tspec_len = elen;
                                break;
                        default:
-                               wpa_printf(MSG_MSGDUMP, "unknown WMM "
+                               wpa_printf(MSG_EXCESSIVE, "unknown WMM "
                                           "information element ignored "
                                           "(subtype=%d len=%lu)",
                                           pos[4], (unsigned long) elen);
@@ -88,7 +88,23 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
                        elems->wps_ie_len = elen;
                        break;
                default:
-                       wpa_printf(MSG_MSGDUMP, "Unknown Microsoft "
+                       wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft "
+                                  "information element ignored "
+                                  "(type=%d len=%lu)",
+                                  pos[3], (unsigned long) elen);
+                       return -1;
+               }
+               break;
+
+       case OUI_WFA:
+               switch (pos[3]) {
+               case P2P_OUI_TYPE:
+                       /* Wi-Fi Alliance - P2P IE */
+                       elems->p2p = pos;
+                       elems->p2p_len = elen;
+                       break;
+               default:
+                       wpa_printf(MSG_MSGDUMP, "Unknown WFA "
                                   "information element ignored "
                                   "(type=%d len=%lu)\n",
                                   pos[3], (unsigned long) elen);
@@ -103,18 +119,18 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
                        elems->vendor_ht_cap_len = elen;
                        break;
                default:
-                       wpa_printf(MSG_MSGDUMP, "Unknown Broadcom "
+                       wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
                                   "information element ignored "
-                                  "(type=%d len=%lu)\n",
+                                  "(type=%d len=%lu)",
                                   pos[3], (unsigned long) elen);
                        return -1;
                }
                break;
 
        default:
-               wpa_printf(MSG_MSGDUMP, "unknown vendor specific information "
-                          "element ignored (vendor OUI %02x:%02x:%02x "
-                          "len=%lu)",
+               wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
+                          "information element ignored (vendor OUI "
+                          "%02x:%02x:%02x len=%lu)",
                           pos[0], pos[1], pos[2], (unsigned long) elen);
                return -1;
        }
@@ -238,6 +254,15 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
                        elems->ht_operation = pos;
                        elems->ht_operation_len = elen;
                        break;
+               case WLAN_EID_LINK_ID:
+                       if (elen < 18)
+                               break;
+                       elems->link_id = pos;
+                       break;
+               case WLAN_EID_INTERWORKING:
+                       elems->interworking = pos;
+                       elems->interworking_len = elen;
+                       break;
                default:
                        unknown++;
                        if (!show_errors)
@@ -324,3 +349,43 @@ struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
 
        return buf;
 }
+
+
+const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
+{
+       u16 fc, type, stype;
+
+       /*
+        * PS-Poll frames are 16 bytes. All other frames are
+        * 24 bytes or longer.
+        */
+       if (len < 16)
+               return NULL;
+
+       fc = le_to_host16(hdr->frame_control);
+       type = WLAN_FC_GET_TYPE(fc);
+       stype = WLAN_FC_GET_STYPE(fc);
+
+       switch (type) {
+       case WLAN_FC_TYPE_DATA:
+               if (len < 24)
+                       return NULL;
+               switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
+               case WLAN_FC_FROMDS | WLAN_FC_TODS:
+               case WLAN_FC_TODS:
+                       return hdr->addr1;
+               case WLAN_FC_FROMDS:
+                       return hdr->addr2;
+               default:
+                       return NULL;
+               }
+       case WLAN_FC_TYPE_CTRL:
+               if (stype != WLAN_FC_STYPE_PSPOLL)
+                       return NULL;
+               return hdr->addr1;
+       case WLAN_FC_TYPE_MGMT:
+               return hdr->addr3;
+       default:
+               return NULL;
+       }
+}
index 4a4f5a7..60f0974 100644 (file)
@@ -40,6 +40,9 @@ struct ieee802_11_elems {
        const u8 *ht_capabilities;
        const u8 *ht_operation;
        const u8 *vendor_ht_cap;
+       const u8 *p2p;
+       const u8 *link_id;
+       const u8 *interworking;
 
        u8 ssid_len;
        u8 supp_rates_len;
@@ -64,6 +67,8 @@ struct ieee802_11_elems {
        u8 ht_capabilities_len;
        u8 ht_operation_len;
        u8 vendor_ht_cap_len;
+       u8 p2p_len;
+       u8 interworking_len;
 };
 
 typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
@@ -74,5 +79,7 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
 int ieee802_11_ie_count(const u8 *ies, size_t ies_len);
 struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
                                            u32 oui_type);
+struct ieee80211_hdr;
+const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len);
 
 #endif /* IEEE802_11_COMMON_H */
index 4881e39..66801fd 100644 (file)
 #define WLAN_FC_STYPE_CFPOLL           6
 #define WLAN_FC_STYPE_CFACKPOLL                7
 #define WLAN_FC_STYPE_QOS_DATA         8
+#define WLAN_FC_STYPE_QOS_DATA_CFACK   9
+#define WLAN_FC_STYPE_QOS_DATA_CFPOLL  10
+#define WLAN_FC_STYPE_QOS_DATA_CFACKPOLL       11
+#define WLAN_FC_STYPE_QOS_NULL         12
+#define WLAN_FC_STYPE_QOS_CFPOLL       14
+#define WLAN_FC_STYPE_QOS_CFACKPOLL    15
 
 /* Authentication algorithms */
 #define WLAN_AUTH_OPEN                 0
 /* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */
 #define WLAN_STATUS_SUCCESS 0
 #define WLAN_STATUS_UNSPECIFIED_FAILURE 1
+#define WLAN_STATUS_TDLS_WAKEUP_ALTERNATE 2
+#define WLAN_STATUS_TDLS_WAKEUP_REJECT 3
+#define WLAN_STATUS_SECURITY_DISABLED 5
+#define WLAN_STATUS_UNACCEPTABLE_LIFETIME 6
+#define WLAN_STATUS_NOT_IN_SAME_BSS 7
 #define WLAN_STATUS_CAPS_UNSUPPORTED 10
 #define WLAN_STATUS_REASSOC_NO_ASSOC 11
 #define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
 #define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
 /* IEEE 802.11g */
 #define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25
-#define WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC 26
-#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 27
+#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 26
+#define WLAN_STATUS_ASSOC_DENIED_NO_HT 27
 #define WLAN_STATUS_R0KH_UNREACHABLE 28
+#define WLAN_STATUS_ASSOC_DENIED_NO_PCO 29
 /* IEEE 802.11w */
 #define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30
 #define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31
 #define WLAN_STATUS_INVALID_PMKID 53
 #define WLAN_STATUS_INVALID_MDIE 54
 #define WLAN_STATUS_INVALID_FTIE 55
+#define WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED 59
+#define WLAN_STATUS_NO_OUTSTANDING_GAS_REQ 60
+#define WLAN_STATUS_GAS_RESP_NOT_RECEIVED 61
+#define WLAN_STATUS_STA_TIMED_OUT_WAITING_FOR_GAS_RESP 62
+#define WLAN_STATUS_GAS_RESP_LARGER_THAN_LIMIT 63
+#define WLAN_STATUS_REQ_REFUSED_HOME 64
+#define WLAN_STATUS_ADV_SRV_UNREACHABLE 65
+#define WLAN_STATUS_REQ_REFUSED_SSPN 67
+#define WLAN_STATUS_REQ_REFUSED_UNAUTH_ACCESS 68
+#define WLAN_STATUS_INVALID_RSNIE 72
+#define WLAN_STATUS_TRANSMISSION_FAILURE 79
 
 /* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
 #define WLAN_REASON_UNSPECIFIED 1
 #define WLAN_REASON_INVALID_RSN_IE_CAPAB 22
 #define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23
 #define WLAN_REASON_CIPHER_SUITE_REJECTED 24
+#define WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE 25
+#define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26
+/* IEEE 802.11e */
+#define WLAN_REASON_DISASSOC_LOW_ACK 34
 
 
 /* Information Element IDs */
 #define WLAN_EID_RIC_DATA 57
 #define WLAN_EID_HT_OPERATION 61
 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
+#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_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_VENDOR_SPECIFIC 221
 
 
 #define WLAN_ACTION_FT 6
 #define WLAN_ACTION_HT 7
 #define WLAN_ACTION_SA_QUERY 8
+#define WLAN_ACTION_WNM 10
+#define WLAN_ACTION_UNPROTECTED_WNM 11
+#define WLAN_ACTION_TDLS 12
 #define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
+#define WLAN_ACTION_VENDOR_SPECIFIC 127
+
+/* Public action codes */
+#define WLAN_PA_VENDOR_SPECIFIC 9
+#define WLAN_PA_GAS_INITIAL_REQ 10
+#define WLAN_PA_GAS_INITIAL_RESP 11
+#define WLAN_PA_GAS_COMEBACK_REQ 12
+#define WLAN_PA_GAS_COMEBACK_RESP 13
+#define WLAN_TDLS_DISCOVERY_RESPONSE 14
 
 /* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
 #define WLAN_SA_QUERY_REQUEST 0
 
 #define WLAN_SA_QUERY_TR_ID_LEN 2
 
+/* TDLS action codes */
+#define WLAN_TDLS_SETUP_REQUEST 0
+#define WLAN_TDLS_SETUP_RESPONSE 1
+#define WLAN_TDLS_SETUP_CONFIRM 2
+#define WLAN_TDLS_TEARDOWN 3
+#define WLAN_TDLS_PEER_TRAFFIC_INDICATION 4
+#define WLAN_TDLS_CHANNEL_SWITCH_REQUEST 5
+#define WLAN_TDLS_CHANNEL_SWITCH_RESPONSE 6
+#define WLAN_TDLS_PEER_PSM_REQUEST 7
+#define WLAN_TDLS_PEER_PSM_RESPONSE 8
+#define WLAN_TDLS_PEER_TRAFFIC_RESPONSE 9
+#define WLAN_TDLS_DISCOVERY_REQUEST 10
+
 /* Timeout Interval Type */
 #define WLAN_TIMEOUT_REASSOC_DEADLINE 1
 #define WLAN_TIMEOUT_KEY_LIFETIME 2
 #define WLAN_TIMEOUT_ASSOC_COMEBACK 3
 
+/* Interworking element (IEEE 802.11u) - Access Network Options */
+#define INTERWORKING_ANO_ACCESS_NETWORK_MASK 0x0f
+#define INTERWORKING_ANO_INTERNET 0x10
+#define INTERWORKING_ANO_ASRA 0x20
+#define INTERWORKING_ANO_ESR 0x40
+#define INTERWORKING_ANO_UESA 0x80
+
+#define INTERWORKING_ANT_PRIVATE 0
+#define INTERWORKING_ANT_PRIVATE_WITH_GUEST 1
+#define INTERWORKING_ANT_CHARGEABLE_PUBLIC 2
+#define INTERWORKING_ANT_FREE_PUBLIC 3
+#define INTERWORKING_ANT_PERSONAL_DEVICE 4
+#define INTERWORKING_ANT_EMERGENCY_SERVICES 5
+#define INTERWORKING_ANT_TEST 6
+#define INTERWORKING_ANT_WILDCARD 15
+
+/* Advertisement Protocol ID definitions (IEEE Std 802.11u-2011) */
+enum adv_proto_id {
+       ACCESS_NETWORK_QUERY_PROTOCOL = 0,
+       MIH_INFO_SERVICE = 1,
+       MIH_CMD_AND_EVENT_DISCOVERY = 2,
+       EMERGENCY_ALERT_SYSTEM = 3,
+       ADV_PROTO_VENDOR_SPECIFIC = 221
+};
+
+/* Access Network Query Protocol info ID definitions (IEEE Std 802.11u-2011) */
+enum anqp_info_id {
+       ANQP_QUERY_LIST = 256,
+       ANQP_CAPABILITY_LIST = 257,
+       ANQP_VENUE_NAME = 258,
+       ANQP_EMERGENCY_CALL_NUMBER = 259,
+       ANQP_NETWORK_AUTH_TYPE = 260,
+       ANQP_ROAMING_CONSORTIUM = 261,
+       ANQP_IP_ADDR_TYPE_AVAILABILITY = 262,
+       ANQP_NAI_REALM = 263,
+       ANQP_3GPP_CELLULAR_NETWORK = 264,
+       ANQP_AP_GEOSPATIAL_LOCATION = 265,
+       ANQP_AP_CIVIC_LOCATION = 266,
+       ANQP_AP_LOCATION_PUBLIC_URI = 267,
+       ANQP_DOMAIN_NAME = 268,
+       ANQP_EMERGENCY_ALERT_URI = 269,
+       ANQP_EMERGENCY_NAI = 271,
+       ANQP_VENDOR_SPECIFIC = 56797
+};
+
+/* NAI Realm list - EAP Method subfield - Authentication Parameter ID */
+enum nai_realm_eap_auth_param {
+       NAI_REALM_EAP_AUTH_EXPANDED_EAP_METHOD = 1,
+       NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH = 2,
+       NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD = 3,
+       NAI_REALM_EAP_AUTH_EXPANDED_INNER_EAP_METHOD = 4,
+       NAI_REALM_EAP_AUTH_CRED_TYPE = 5,
+       NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE = 6,
+       NAI_REALM_EAP_AUTH_VENDOR_SPECIFIC = 221
+};
+
+enum nai_realm_eap_auth_inner_non_eap {
+       NAI_REALM_INNER_NON_EAP_PAP = 1,
+       NAI_REALM_INNER_NON_EAP_CHAP = 2,
+       NAI_REALM_INNER_NON_EAP_MSCHAP = 3,
+       NAI_REALM_INNER_NON_EAP_MSCHAPV2 = 4
+};
+
+enum nai_realm_eap_cred_type {
+       NAI_REALM_CRED_TYPE_SIM = 1,
+       NAI_REALM_CRED_TYPE_USIM = 2,
+       NAI_REALM_CRED_TYPE_NFC_SECURE_ELEMENT = 3,
+       NAI_REALM_CRED_TYPE_HARDWARE_TOKEN = 4,
+       NAI_REALM_CRED_TYPE_SOFTOKEN = 5,
+       NAI_REALM_CRED_TYPE_CERTIFICATE = 6,
+       NAI_REALM_CRED_TYPE_USERNAME_PASSWORD = 7,
+       NAI_REALM_CRED_TYPE_NONE = 8,
+       NAI_REALM_CRED_TYPE_ANONYMOUS = 9,
+       NAI_REALM_CRED_TYPE_VENDOR_SPECIFIC = 10
+};
 
 #ifdef _MSC_VER
 #pragma pack(push, 1)
@@ -273,6 +407,7 @@ struct ieee80211_mgmt {
                } STRUCT_PACKED auth;
                struct {
                        le16 reason_code;
+                       u8 variable[0];
                } STRUCT_PACKED deauth;
                struct {
                        le16 capab_info;
@@ -296,6 +431,7 @@ struct ieee80211_mgmt {
                } STRUCT_PACKED reassoc_req;
                struct {
                        le16 reason_code;
+                       u8 variable[0];
                } STRUCT_PACKED disassoc;
                struct {
                        u8 timestamp[8];
@@ -355,6 +491,28 @@ struct ieee80211_mgmt {
                                        u8 action; /* */
                                        u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
                                } STRUCT_PACKED sa_query_resp;
+                               struct {
+                                       u8 action;
+                                       u8 variable[0];
+                               } STRUCT_PACKED public_action;
+                               struct {
+                                       u8 action; /* 9 */
+                                       u8 oui[3];
+                                       /* Vendor-specific content */
+                                       u8 variable[0];
+                               } STRUCT_PACKED vs_public_action;
+                               struct {
+                                       u8 action; /* 7 */
+                                       u8 dialog_token;
+                                       u8 req_mode;
+                                       le16 disassoc_timer;
+                                       u8 validity_interval;
+                                       /* BSS Termination Duration (optional),
+                                        * Session Information URL (optional),
+                                        * BSS Transition Candidate List
+                                        * Entries */
+                                       u8 variable[0];
+                               } STRUCT_PACKED bss_tm_req;
                        } u;
                } STRUCT_PACKED action;
        } u;
@@ -460,7 +618,7 @@ struct ieee80211_ht_operation {
 #define OP_MODE_MIXED                   3
 
 #define HT_INFO_OPERATION_MODE_OP_MODE_MASK    \
-               ((le16) (0x0001 | 0x0002))
+               (0x0001 | 0x0002)
 #define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET          0
 #define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT     ((u8) BIT(2))
 #define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT    ((u8) BIT(3))
@@ -473,11 +631,14 @@ 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_HT_PHY 127
 
 #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 WMM_OUI_TYPE 2
 #define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
@@ -516,6 +677,10 @@ struct wmm_information_element {
 
 } STRUCT_PACKED;
 
+#define WMM_QOSINFO_STA_AC_MASK 0x0f
+#define WMM_QOSINFO_STA_SP_MASK 0x03
+#define WMM_QOSINFO_STA_SP_SHIFT 5
+
 #define WMM_AC_AIFSN_MASK 0x0f
 #define WMM_AC_AIFNS_SHIFT 0
 #define WMM_AC_ACM 0x10
@@ -544,7 +709,7 @@ struct wmm_parameter_element {
        u8 oui_type; /* 2 */
        u8 oui_subtype; /* 1 */
        u8 version; /* 1 for WMM version 1.0 */
-       u8 qos_info; /* AP/STA specif QoS info */
+       u8 qos_info; /* AP/STA specific QoS info */
        u8 reserved; /* 0 */
        struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */
 
@@ -587,6 +752,115 @@ enum {
 };
 
 
+/* Wi-Fi Direct (P2P) */
+
+#define P2P_OUI_TYPE 9
+
+enum p2p_attr_id {
+       P2P_ATTR_STATUS = 0,
+       P2P_ATTR_MINOR_REASON_CODE = 1,
+       P2P_ATTR_CAPABILITY = 2,
+       P2P_ATTR_DEVICE_ID = 3,
+       P2P_ATTR_GROUP_OWNER_INTENT = 4,
+       P2P_ATTR_CONFIGURATION_TIMEOUT = 5,
+       P2P_ATTR_LISTEN_CHANNEL = 6,
+       P2P_ATTR_GROUP_BSSID = 7,
+       P2P_ATTR_EXT_LISTEN_TIMING = 8,
+       P2P_ATTR_INTENDED_INTERFACE_ADDR = 9,
+       P2P_ATTR_MANAGEABILITY = 10,
+       P2P_ATTR_CHANNEL_LIST = 11,
+       P2P_ATTR_NOTICE_OF_ABSENCE = 12,
+       P2P_ATTR_DEVICE_INFO = 13,
+       P2P_ATTR_GROUP_INFO = 14,
+       P2P_ATTR_GROUP_ID = 15,
+       P2P_ATTR_INTERFACE = 16,
+       P2P_ATTR_OPERATING_CHANNEL = 17,
+       P2P_ATTR_INVITATION_FLAGS = 18,
+       P2P_ATTR_VENDOR_SPECIFIC = 221
+};
+
+#define P2P_MAX_GO_INTENT 15
+
+/* P2P Capability - Device Capability bitmap */
+#define P2P_DEV_CAPAB_SERVICE_DISCOVERY BIT(0)
+#define P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY BIT(1)
+#define P2P_DEV_CAPAB_CONCURRENT_OPER BIT(2)
+#define P2P_DEV_CAPAB_INFRA_MANAGED BIT(3)
+#define P2P_DEV_CAPAB_DEVICE_LIMIT BIT(4)
+#define P2P_DEV_CAPAB_INVITATION_PROCEDURE BIT(5)
+
+/* P2P Capability - Group Capability bitmap */
+#define P2P_GROUP_CAPAB_GROUP_OWNER BIT(0)
+#define P2P_GROUP_CAPAB_PERSISTENT_GROUP BIT(1)
+#define P2P_GROUP_CAPAB_GROUP_LIMIT BIT(2)
+#define P2P_GROUP_CAPAB_INTRA_BSS_DIST BIT(3)
+#define P2P_GROUP_CAPAB_CROSS_CONN BIT(4)
+#define P2P_GROUP_CAPAB_PERSISTENT_RECONN BIT(5)
+#define P2P_GROUP_CAPAB_GROUP_FORMATION BIT(6)
+
+/* Invitation Flags */
+#define P2P_INVITATION_FLAGS_TYPE BIT(0)
+
+/* P2P Manageability */
+#define P2P_MAN_DEVICE_MANAGEMENT BIT(0)
+#define P2P_MAN_CROSS_CONNECTION_PERMITTED BIT(1)
+#define P2P_MAN_COEXISTENCE_OPTIONAL BIT(2)
+
+enum p2p_status_code {
+       P2P_SC_SUCCESS = 0,
+       P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE = 1,
+       P2P_SC_FAIL_INCOMPATIBLE_PARAMS = 2,
+       P2P_SC_FAIL_LIMIT_REACHED = 3,
+       P2P_SC_FAIL_INVALID_PARAMS = 4,
+       P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE = 5,
+       P2P_SC_FAIL_PREV_PROTOCOL_ERROR = 6,
+       P2P_SC_FAIL_NO_COMMON_CHANNELS = 7,
+       P2P_SC_FAIL_UNKNOWN_GROUP = 8,
+       P2P_SC_FAIL_BOTH_GO_INTENT_15 = 9,
+       P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10,
+       P2P_SC_FAIL_REJECTED_BY_USER = 11,
+};
+
+#define P2P_WILDCARD_SSID "DIRECT-"
+#define P2P_WILDCARD_SSID_LEN 7
+
+/* P2P action frames */
+enum p2p_act_frame_type {
+       P2P_NOA = 0,
+       P2P_PRESENCE_REQ = 1,
+       P2P_PRESENCE_RESP = 2,
+       P2P_GO_DISC_REQ = 3
+};
+
+/* P2P public action frames */
+enum p2p_action_frame_type {
+       P2P_GO_NEG_REQ = 0,
+       P2P_GO_NEG_RESP = 1,
+       P2P_GO_NEG_CONF = 2,
+       P2P_INVITATION_REQ = 3,
+       P2P_INVITATION_RESP = 4,
+       P2P_DEV_DISC_REQ = 5,
+       P2P_DEV_DISC_RESP = 6,
+       P2P_PROV_DISC_REQ = 7,
+       P2P_PROV_DISC_RESP = 8
+};
+
+enum p2p_service_protocol_type {
+       P2P_SERV_ALL_SERVICES = 0,
+       P2P_SERV_BONJOUR = 1,
+       P2P_SERV_UPNP = 2,
+       P2P_SERV_WS_DISCOVERY = 3,
+       P2P_SERV_VENDOR_SPECIFIC = 255
+};
+
+enum p2p_sd_status {
+       P2P_SD_SUCCESS = 0,
+       P2P_SD_PROTO_NOT_AVAILABLE = 1,
+       P2P_SD_REQUESTED_INFO_NOT_AVAILABLE = 2,
+       P2P_SD_BAD_REQUEST = 3
+};
+
+
 #define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
 
 #define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
@@ -604,4 +878,44 @@ enum {
 #define WLAN_AKM_SUITE_8021X           0x000FAC01
 #define WLAN_AKM_SUITE_PSK             0x000FAC02
 
+
+/* IEEE 802.11v - WNM Action field values */
+enum wnm_action {
+       WNM_EVENT_REQ = 0,
+       WNM_EVENT_REPORT = 1,
+       WNM_DIAGNOSTIC_REQ = 2,
+       WNM_DIAGNOSTIC_REPORT = 3,
+       WNM_LOCATION_CFG_REQ = 4,
+       WNM_LOCATION_CFG_RESP = 5,
+       WNM_BSS_TRANS_MGMT_QUERY = 6,
+       WNM_BSS_TRANS_MGMT_REQ = 7,
+       WNM_BSS_TRANS_MGMT_RESP = 8,
+       WNM_FMS_REQ = 9,
+       WNM_FMS_RESP = 10,
+       WNM_COLLOCATED_INTERFERENCE_REQ = 11,
+       WNM_COLLOCATED_INTERFERENCE_REPORT = 12,
+       WNM_TFS_REQ = 13,
+       WNM_TFS_RESP = 14,
+       WNM_TFS_NOTIFY = 15,
+       WNM_SLEEP_MODE_REQ = 16,
+       WNM_SLEEP_MODE_RESP = 17,
+       WNM_TIM_BROADCAST_REQ = 18,
+       WNM_TIM_BROADCAST_RESP = 19,
+       WNM_QOS_TRAFFIC_CAPAB_UPDATE = 20,
+       WNM_CHANNEL_USAGE_REQ = 21,
+       WNM_CHANNEL_USAGE_RESP = 22,
+       WNM_DMS_REQ = 23,
+       WNM_DMS_RESP = 24,
+       WNM_TIMING_MEASUREMENT_REQ = 25,
+       WNM_NOTIFICATION_REQ = 26,
+       WNM_NOTIFICATION_RESP = 27
+};
+
+/* IEEE 802.11v - BSS Transition Management Request - Request Mode */
+#define WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED BIT(0)
+#define WNM_BSS_TM_REQ_ABRIDGED BIT(1)
+#define WNM_BSS_TM_REQ_DISASSOC_IMMINENT BIT(2)
+#define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3)
+#define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4)
+
 #endif /* IEEE802_11_DEFS_H */
index 02f34be..7afba48 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef VERSION_H
 #define VERSION_H
 
-#define VERSION_STR "0.7.3"
+#ifndef VERSION_STR_POSTFIX
+#define VERSION_STR_POSTFIX ""
+#endif /* VERSION_STR_POSTFIX */
+
+#define VERSION_STR "2.0-devel" VERSION_STR_POSTFIX
 
 #endif /* VERSION_H */
index b295f31..24a61e4 100644 (file)
@@ -126,6 +126,8 @@ void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
 
        wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
                   MAC2STR(addr1), MAC2STR(addr2));
+       wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
+       wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
        wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
        wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len);
 }
@@ -186,6 +188,154 @@ int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
 
        return 0;
 }
+
+
+static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
+                            struct wpa_ft_ies *parse)
+{
+       const u8 *end, *pos;
+
+       parse->ftie = ie;
+       parse->ftie_len = ie_len;
+
+       pos = ie + sizeof(struct rsn_ftie);
+       end = ie + ie_len;
+
+       while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
+               switch (pos[0]) {
+               case FTIE_SUBELEM_R1KH_ID:
+                       if (pos[1] != FT_R1KH_ID_LEN) {
+                               wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
+                                          "length in FTIE: %d", pos[1]);
+                               return -1;
+                       }
+                       parse->r1kh_id = pos + 2;
+                       break;
+               case FTIE_SUBELEM_GTK:
+                       parse->gtk = pos + 2;
+                       parse->gtk_len = pos[1];
+                       break;
+               case FTIE_SUBELEM_R0KH_ID:
+                       if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
+                               wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
+                                          "length in FTIE: %d", pos[1]);
+                               return -1;
+                       }
+                       parse->r0kh_id = pos + 2;
+                       parse->r0kh_id_len = pos[1];
+                       break;
+#ifdef CONFIG_IEEE80211W
+               case FTIE_SUBELEM_IGTK:
+                       parse->igtk = pos + 2;
+                       parse->igtk_len = pos[1];
+                       break;
+#endif /* CONFIG_IEEE80211W */
+               }
+
+               pos += 2 + pos[1];
+       }
+
+       return 0;
+}
+
+
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
+                    struct wpa_ft_ies *parse)
+{
+       const u8 *end, *pos;
+       struct wpa_ie_data data;
+       int ret;
+       const struct rsn_ftie *ftie;
+       int prot_ie_count = 0;
+
+       os_memset(parse, 0, sizeof(*parse));
+       if (ies == NULL)
+               return 0;
+
+       pos = ies;
+       end = ies + ies_len;
+       while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
+               switch (pos[0]) {
+               case WLAN_EID_RSN:
+                       parse->rsn = pos + 2;
+                       parse->rsn_len = pos[1];
+                       ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
+                                                  parse->rsn_len + 2,
+                                                  &data);
+                       if (ret < 0) {
+                               wpa_printf(MSG_DEBUG, "FT: Failed to parse "
+                                          "RSN IE: %d", ret);
+                               return -1;
+                       }
+                       if (data.num_pmkid == 1 && data.pmkid)
+                               parse->rsn_pmkid = data.pmkid;
+                       break;
+               case WLAN_EID_MOBILITY_DOMAIN:
+                       parse->mdie = pos + 2;
+                       parse->mdie_len = pos[1];
+                       break;
+               case WLAN_EID_FAST_BSS_TRANSITION:
+                       if (pos[1] < sizeof(*ftie))
+                               return -1;
+                       ftie = (const struct rsn_ftie *) (pos + 2);
+                       prot_ie_count = ftie->mic_control[1];
+                       if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
+                               return -1;
+                       break;
+               case WLAN_EID_TIMEOUT_INTERVAL:
+                       parse->tie = pos + 2;
+                       parse->tie_len = pos[1];
+                       break;
+               case WLAN_EID_RIC_DATA:
+                       if (parse->ric == NULL)
+                               parse->ric = pos;
+                       break;
+               }
+
+               pos += 2 + pos[1];
+       }
+
+       if (prot_ie_count == 0)
+               return 0; /* no MIC */
+
+       /*
+        * Check that the protected IE count matches with IEs included in the
+        * frame.
+        */
+       if (parse->rsn)
+               prot_ie_count--;
+       if (parse->mdie)
+               prot_ie_count--;
+       if (parse->ftie)
+               prot_ie_count--;
+       if (prot_ie_count < 0) {
+               wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
+                          "the protected IE count");
+               return -1;
+       }
+
+       if (prot_ie_count == 0 && parse->ric) {
+               wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
+                          "included in protected IE count");
+               return -1;
+       }
+
+       /* Determine the end of the RIC IE(s) */
+       pos = parse->ric;
+       while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
+              prot_ie_count) {
+               prot_ie_count--;
+               pos += 2 + pos[1];
+       }
+       parse->ric_len = pos - parse->ric;
+       if (prot_ie_count) {
+               wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
+                          "frame", (int) prot_ie_count);
+               return -1;
+       }
+
+       return 0;
+}
 #endif /* CONFIG_IEEE80211R */
 
 
@@ -403,6 +553,144 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
 }
 
 
+static int wpa_selector_to_bitfield(const u8 *s)
+{
+       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
+               return WPA_CIPHER_NONE;
+       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
+               return WPA_CIPHER_WEP40;
+       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
+               return WPA_CIPHER_TKIP;
+       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
+               return WPA_CIPHER_CCMP;
+       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
+               return WPA_CIPHER_WEP104;
+       return 0;
+}
+
+
+static int wpa_key_mgmt_to_bitfield(const u8 *s)
+{
+       if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
+               return WPA_KEY_MGMT_IEEE8021X;
+       if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
+               return WPA_KEY_MGMT_PSK;
+       if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
+               return WPA_KEY_MGMT_WPA_NONE;
+       return 0;
+}
+
+
+int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
+                        struct wpa_ie_data *data)
+{
+       const struct wpa_ie_hdr *hdr;
+       const u8 *pos;
+       int left;
+       int i, count;
+
+       os_memset(data, 0, sizeof(*data));
+       data->proto = WPA_PROTO_WPA;
+       data->pairwise_cipher = WPA_CIPHER_TKIP;
+       data->group_cipher = WPA_CIPHER_TKIP;
+       data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+       data->capabilities = 0;
+       data->pmkid = NULL;
+       data->num_pmkid = 0;
+       data->mgmt_group_cipher = 0;
+
+       if (wpa_ie_len == 0) {
+               /* No WPA IE - fail silently */
+               return -1;
+       }
+
+       if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
+               wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
+                          __func__, (unsigned long) wpa_ie_len);
+               return -1;
+       }
+
+       hdr = (const struct wpa_ie_hdr *) wpa_ie;
+
+       if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
+           hdr->len != wpa_ie_len - 2 ||
+           RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
+           WPA_GET_LE16(hdr->version) != WPA_VERSION) {
+               wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
+                          __func__);
+               return -2;
+       }
+
+       pos = (const u8 *) (hdr + 1);
+       left = wpa_ie_len - sizeof(*hdr);
+
+       if (left >= WPA_SELECTOR_LEN) {
+               data->group_cipher = wpa_selector_to_bitfield(pos);
+               pos += WPA_SELECTOR_LEN;
+               left -= WPA_SELECTOR_LEN;
+       } else if (left > 0) {
+               wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
+                          __func__, left);
+               return -3;
+       }
+
+       if (left >= 2) {
+               data->pairwise_cipher = 0;
+               count = WPA_GET_LE16(pos);
+               pos += 2;
+               left -= 2;
+               if (count == 0 || left < count * WPA_SELECTOR_LEN) {
+                       wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
+                                  "count %u left %u", __func__, count, left);
+                       return -4;
+               }
+               for (i = 0; i < count; i++) {
+                       data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
+                       pos += WPA_SELECTOR_LEN;
+                       left -= WPA_SELECTOR_LEN;
+               }
+       } else if (left == 1) {
+               wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
+                          __func__);
+               return -5;
+       }
+
+       if (left >= 2) {
+               data->key_mgmt = 0;
+               count = WPA_GET_LE16(pos);
+               pos += 2;
+               left -= 2;
+               if (count == 0 || left < count * WPA_SELECTOR_LEN) {
+                       wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
+                                  "count %u left %u", __func__, count, left);
+                       return -6;
+               }
+               for (i = 0; i < count; i++) {
+                       data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
+                       pos += WPA_SELECTOR_LEN;
+                       left -= WPA_SELECTOR_LEN;
+               }
+       } else if (left == 1) {
+               wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
+                          __func__);
+               return -7;
+       }
+
+       if (left >= 2) {
+               data->capabilities = WPA_GET_LE16(pos);
+               pos += 2;
+               left -= 2;
+       }
+
+       if (left > 0) {
+               wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
+                          __func__, left);
+       }
+
+       return 0;
+}
+
+
 #ifdef CONFIG_IEEE80211R
 
 /**
index fd8a79f..69437a7 100644 (file)
@@ -56,6 +56,7 @@
 #endif /* CONFIG_IEEE80211R */
 #define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
 #define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
+#define RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
 
 #define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
 #define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
@@ -68,6 +69,7 @@
 #ifdef CONFIG_IEEE80211W
 #define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
 #endif /* CONFIG_IEEE80211W */
+#define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
 
 /* EAPOL-Key Key Data Encapsulation
  * GroupKey and PeerKey require encryption, otherwise, encryption is optional.
 /* B4-B5: GTKSA Replay Counter */
 #define WPA_CAPABILITY_MFPR BIT(6)
 #define WPA_CAPABILITY_MFPC BIT(7)
+/* B8: Reserved */
 #define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9)
+#define WPA_CAPABILITY_SPP_A_MSDU_CAPABLE BIT(10)
+#define WPA_CAPABILITY_SPP_A_MSDU_REQUIRED BIT(11)
+#define WPA_CAPABILITY_PBAC BIT(12)
+#define WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST BIT(13)
+/* B14-B15: Reserved */
 
 
 /* IEEE 802.11r */
@@ -337,6 +345,8 @@ struct wpa_ie_data {
 
 int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
                         struct wpa_ie_data *data);
+int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
+                        struct wpa_ie_data *data);
 
 void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
               u8 *pmkid, int use_sha256);
@@ -348,4 +358,27 @@ int wpa_compare_rsn_ie(int ft_initial_assoc,
                       const u8 *ie2, size_t ie2len);
 int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid);
 
+struct wpa_ft_ies {
+       const u8 *mdie;
+       size_t mdie_len;
+       const u8 *ftie;
+       size_t ftie_len;
+       const u8 *r1kh_id;
+       const u8 *gtk;
+       size_t gtk_len;
+       const u8 *r0kh_id;
+       size_t r0kh_id_len;
+       const u8 *rsn;
+       size_t rsn_len;
+       const u8 *rsn_pmkid;
+       const u8 *tie;
+       size_t tie_len;
+       const u8 *igtk;
+       size_t igtk_len;
+       const u8 *ric;
+       size_t ric_len;
+};
+
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse);
+
 #endif /* WPA_COMMON_H */
index 2b4e3aa..3b25f77 100644 (file)
 #include <sys/un.h>
 #endif /* CONFIG_CTRL_IFACE_UNIX */
 
+#ifdef ANDROID
+#include <dirent.h>
+#include <cutils/sockets.h>
+#include "private/android_filesystem_config.h"
+#endif /* ANDROID */
+
 #include "wpa_ctrl.h"
 #include "common.h"
 
@@ -58,6 +64,14 @@ struct wpa_ctrl {
 
 #ifdef CONFIG_CTRL_IFACE_UNIX
 
+#ifndef CONFIG_CTRL_IFACE_CLIENT_DIR
+#define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp"
+#endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */
+#ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX
+#define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_"
+#endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */
+
+
 struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
 {
        struct wpa_ctrl *ctrl;
@@ -81,7 +95,9 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
        counter++;
 try_again:
        ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
-                         "/tmp/wpa_ctrl_%d-%d", getpid(), counter);
+                         CONFIG_CTRL_IFACE_CLIENT_DIR "/"
+                         CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
+                         (int) getpid(), counter);
        if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
                close(ctrl->s);
                os_free(ctrl);
@@ -105,6 +121,31 @@ try_again:
                return NULL;
        }
 
+#ifdef ANDROID
+       chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+       chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
+       /*
+        * If the ctrl_path isn't an absolute pathname, assume that
+        * it's the name of a socket in the Android reserved namespace.
+        * Otherwise, it's a normal UNIX domain socket appearing in the
+        * filesystem.
+        */
+       if (ctrl_path != NULL && *ctrl_path != '/') {
+               char buf[21];
+               os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
+               if (socket_local_client_connect(
+                           ctrl->s, buf,
+                           ANDROID_SOCKET_NAMESPACE_RESERVED,
+                           SOCK_DGRAM) < 0) {
+                       close(ctrl->s);
+                       unlink(ctrl->local.sun_path);
+                       os_free(ctrl);
+                       return NULL;
+               }
+               return ctrl;
+       }
+#endif /* ANDROID */
+
        ctrl->dest.sun_family = AF_UNIX;
        res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
                         sizeof(ctrl->dest.sun_path));
@@ -127,11 +168,64 @@ try_again:
 
 void wpa_ctrl_close(struct wpa_ctrl *ctrl)
 {
+       if (ctrl == NULL)
+               return;
        unlink(ctrl->local.sun_path);
-       close(ctrl->s);
+       if (ctrl->s >= 0)
+               close(ctrl->s);
        os_free(ctrl);
 }
 
+
+#ifdef ANDROID
+/**
+ * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
+ * may be left over from clients that were previously connected to
+ * wpa_supplicant. This keeps these files from being orphaned in the
+ * event of crashes that prevented them from being removed as part
+ * of the normal orderly shutdown.
+ */
+void wpa_ctrl_cleanup(void)
+{
+       DIR *dir;
+       struct dirent entry;
+       struct dirent *result;
+       size_t dirnamelen;
+       int prefixlen = os_strlen(CONFIG_CTRL_IFACE_CLIENT_PREFIX);
+       size_t maxcopy;
+       char pathname[PATH_MAX];
+       char *namep;
+
+       if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL)
+               return;
+
+       dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/",
+                                         CONFIG_CTRL_IFACE_CLIENT_DIR);
+       if (dirnamelen >= sizeof(pathname)) {
+               closedir(dir);
+               return;
+       }
+       namep = pathname + dirnamelen;
+       maxcopy = PATH_MAX - dirnamelen;
+       while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
+               if (os_strncmp(entry.d_name, CONFIG_CTRL_IFACE_CLIENT_PREFIX,
+                              prefixlen) == 0) {
+                       if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy)
+                               unlink(pathname);
+               }
+       }
+       closedir(dir);
+}
+#endif /* ANDROID */
+
+#else /* CONFIG_CTRL_IFACE_UNIX */
+
+#ifdef ANDROID
+void wpa_ctrl_cleanup(void)
+{
+}
+#endif /* ANDROID */
+
 #endif /* CONFIG_CTRL_IFACE_UNIX */
 
 
@@ -234,11 +328,13 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
        os_free(cmd_buf);
 
        for (;;) {
-               tv.tv_sec = 2;
+               tv.tv_sec = 10;
                tv.tv_usec = 0;
                FD_ZERO(&rfds);
                FD_SET(ctrl->s, &rfds);
                res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
+               if (res < 0)
+                       return res;
                if (FD_ISSET(ctrl->s, &rfds)) {
                        res = recv(ctrl->s, reply, *reply_len, 0);
                        if (res < 0)
index d770fd4..6cd9de5 100644 (file)
@@ -32,6 +32,8 @@ extern "C" {
 #define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "
 /** Disconnected, data connection is not available */
 #define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED "
+/** Association rejected during connection attempt */
+#define WPA_EVENT_ASSOC_REJECT "CTRL-EVENT-ASSOC-REJECT "
 /** wpa_supplicant is exiting */
 #define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
 /** Password change was completed successfully */
@@ -54,6 +56,8 @@ extern "C" {
 #define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
 /** New scan results available */
 #define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
+/** wpa_supplicant state change */
+#define WPA_EVENT_STATE_CHANGE "CTRL-EVENT-STATE-CHANGE "
 /** A new BSS entry was added (followed by BSS entry id and BSSID) */
 #define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED "
 /** A BSS entry was removed (followed by BSS entry id and BSSID) */
@@ -63,6 +67,8 @@ extern "C" {
 #define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
 /** Available WPS AP with active PBC found in scan results */
 #define WPS_EVENT_AP_AVAILABLE_PBC "WPS-AP-AVAILABLE-PBC "
+/** Available WPS AP with our address as authorized in scan results */
+#define WPS_EVENT_AP_AVAILABLE_AUTH "WPS-AP-AVAILABLE-AUTH "
 /** Available WPS AP with recently selected PIN registrar found in scan results
  */
 #define WPS_EVENT_AP_AVAILABLE_PIN "WPS-AP-AVAILABLE-PIN "
@@ -81,11 +87,50 @@ extern "C" {
 
 #define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN "
 
+#define WPS_EVENT_OPEN_NETWORK "WPS-OPEN-NETWORK "
+
 /* WPS ER events */
 #define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD "
 #define WPS_EVENT_ER_AP_REMOVE "WPS-ER-AP-REMOVE "
 #define WPS_EVENT_ER_ENROLLEE_ADD "WPS-ER-ENROLLEE-ADD "
 #define WPS_EVENT_ER_ENROLLEE_REMOVE "WPS-ER-ENROLLEE-REMOVE "
+#define WPS_EVENT_ER_AP_SETTINGS "WPS-ER-AP-SETTINGS "
+#define WPS_EVENT_ER_SET_SEL_REG "WPS-ER-AP-SET-SEL-REG "
+
+/** P2P device found */
+#define P2P_EVENT_DEVICE_FOUND "P2P-DEVICE-FOUND "
+
+/** P2P device lost */
+#define P2P_EVENT_DEVICE_LOST "P2P-DEVICE-LOST "
+
+/** A P2P device requested GO negotiation, but we were not ready to start the
+ * negotiation */
+#define P2P_EVENT_GO_NEG_REQUEST "P2P-GO-NEG-REQUEST "
+#define P2P_EVENT_GO_NEG_SUCCESS "P2P-GO-NEG-SUCCESS "
+#define P2P_EVENT_GO_NEG_FAILURE "P2P-GO-NEG-FAILURE "
+#define P2P_EVENT_GROUP_FORMATION_SUCCESS "P2P-GROUP-FORMATION-SUCCESS "
+#define P2P_EVENT_GROUP_FORMATION_FAILURE "P2P-GROUP-FORMATION-FAILURE "
+#define P2P_EVENT_GROUP_STARTED "P2P-GROUP-STARTED "
+#define P2P_EVENT_GROUP_REMOVED "P2P-GROUP-REMOVED "
+#define P2P_EVENT_CROSS_CONNECT_ENABLE "P2P-CROSS-CONNECT-ENABLE "
+#define P2P_EVENT_CROSS_CONNECT_DISABLE "P2P-CROSS-CONNECT-DISABLE "
+/* parameters: <peer address> <PIN> */
+#define P2P_EVENT_PROV_DISC_SHOW_PIN "P2P-PROV-DISC-SHOW-PIN "
+/* parameters: <peer address> */
+#define P2P_EVENT_PROV_DISC_ENTER_PIN "P2P-PROV-DISC-ENTER-PIN "
+/* parameters: <peer address> */
+#define P2P_EVENT_PROV_DISC_PBC_REQ "P2P-PROV-DISC-PBC-REQ "
+/* parameters: <peer address> */
+#define P2P_EVENT_PROV_DISC_PBC_RESP "P2P-PROV-DISC-PBC-RESP "
+/* parameters: <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 INTERWORKING_AP "INTERWORKING-AP "
+#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
 
 /* hostapd control interface - fixed message prefixes */
 #define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
@@ -223,6 +268,17 @@ int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
  */
 int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
 
+#ifdef ANDROID
+/**
+ * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
+ * may be left over from clients that were previously connected to
+ * wpa_supplicant. This keeps these files from being orphaned in the
+ * event of crashes that prevented them from being removed as part
+ * of the normal orderly shutdown.
+ */
+void wpa_ctrl_cleanup(void);
+#endif /* ANDROID */
+
 #ifdef CONFIG_CTRL_IFACE_UDP
 #define WPA_CTRL_IFACE_PORT 9877
 #define WPA_GLOBAL_CTRL_IFACE_PORT 9878
diff --git a/src/crypto/.gitignore b/src/crypto/.gitignore
deleted file mode 100644 (file)
index ee60604..0000000
+++ /dev/null
@@ -1 +0,0 @@
-libcrypto.a
index 69aa16a..b221dd4 100644 (file)
@@ -12,6 +12,7 @@ include ../lib.rules
 CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
 CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
 #CFLAGS += -DALL_DH_GROUPS
+CFLAGS += -DCONFIG_SHA256
 
 LIB_OBJS= \
        aes-cbc.o \
@@ -40,6 +41,7 @@ LIB_OBJS= \
        sha1-tlsprf.o \
        sha1-tprf.o \
        sha256.o \
+       sha256-tlsprf.o \
        sha256-internal.o
 
 LIB_OBJS += crypto_internal.o
@@ -48,6 +50,7 @@ LIB_OBJS += crypto_internal-modexp.o
 LIB_OBJS += crypto_internal-rsa.o
 LIB_OBJS += tls_internal.o
 LIB_OBJS += fips_prf_internal.o
+LIB_OBJS += random.o
 
 
 libcrypto.a: $(LIB_OBJS)
index 2d32c03..a0fc45b 100644 (file)
@@ -32,7 +32,7 @@
  *
  * @return     the number of rounds for the given cipher key size.
  */
-void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[])
+static void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[])
 {
        int Nr = 10, i, j;
        u32 temp;
index 2f19826..8726aa7 100644 (file)
@@ -27,7 +27,7 @@
 #include "crypto.h"
 #include "aes_i.h"
 
-void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
+static void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
 {
        u32 s0, s1, s2, s3, t0, t1, t2, t3;
        const int Nr = 10;
index 587b5a9..6dca191 100644 (file)
@@ -155,7 +155,8 @@ void aes_decrypt_deinit(void *ctx);
 
 enum crypto_hash_alg {
        CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,
-       CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1
+       CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1,
+       CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256
 };
 
 struct crypto_hash;
index 205042c..7f0a5cf 100644 (file)
@@ -17,7 +17,6 @@
 #include "common.h"
 #include "crypto.h"
 #include "tls/rsa.h"
-#include "tls/bignum.h"
 #include "tls/pkcs1.h"
 #include "tls/pkcs8.h"
 
index 8fdba65..9362fe1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Crypto wrapper for internal crypto implementation
- * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
+ * 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
@@ -16,6 +16,7 @@
 
 #include "common.h"
 #include "crypto.h"
+#include "sha256_i.h"
 #include "sha1_i.h"
 #include "md5_i.h"
 
@@ -24,6 +25,9 @@ struct crypto_hash {
        union {
                struct MD5Context md5;
                struct SHA1Context sha1;
+#ifdef CONFIG_SHA256
+               struct sha256_state sha256;
+#endif /* CONFIG_SHA256 */
        } u;
        u8 key[64];
        size_t key_len;
@@ -35,7 +39,7 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
 {
        struct crypto_hash *ctx;
        u8 k_pad[64];
-       u8 tk[20];
+       u8 tk[32];
        size_t i;
 
        ctx = os_zalloc(sizeof(*ctx));
@@ -51,6 +55,11 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
        case CRYPTO_HASH_ALG_SHA1:
                SHA1Init(&ctx->u.sha1);
                break;
+#ifdef CONFIG_SHA256
+       case CRYPTO_HASH_ALG_SHA256:
+               sha256_init(&ctx->u.sha256);
+               break;
+#endif /* CONFIG_SHA256 */
        case CRYPTO_HASH_ALG_HMAC_MD5:
                if (key_len > sizeof(k_pad)) {
                        MD5Init(&ctx->u.md5);
@@ -63,7 +72,8 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
                ctx->key_len = key_len;
 
                os_memcpy(k_pad, key, key_len);
-               os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+               if (key_len < sizeof(k_pad))
+                       os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
                for (i = 0; i < sizeof(k_pad); i++)
                        k_pad[i] ^= 0x36;
                MD5Init(&ctx->u.md5);
@@ -81,12 +91,34 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
                ctx->key_len = key_len;
 
                os_memcpy(k_pad, key, key_len);
-               os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+               if (key_len < sizeof(k_pad))
+                       os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
                for (i = 0; i < sizeof(k_pad); i++)
                        k_pad[i] ^= 0x36;
                SHA1Init(&ctx->u.sha1);
                SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
                break;
+#ifdef CONFIG_SHA256
+       case CRYPTO_HASH_ALG_HMAC_SHA256:
+               if (key_len > sizeof(k_pad)) {
+                       sha256_init(&ctx->u.sha256);
+                       sha256_process(&ctx->u.sha256, key, key_len);
+                       sha256_done(&ctx->u.sha256, tk);
+                       key = tk;
+                       key_len = 32;
+               }
+               os_memcpy(ctx->key, key, key_len);
+               ctx->key_len = key_len;
+
+               os_memcpy(k_pad, key, key_len);
+               if (key_len < sizeof(k_pad))
+                       os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+               for (i = 0; i < sizeof(k_pad); i++)
+                       k_pad[i] ^= 0x36;
+               sha256_init(&ctx->u.sha256);
+               sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
+               break;
+#endif /* CONFIG_SHA256 */
        default:
                os_free(ctx);
                return NULL;
@@ -110,6 +142,14 @@ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
        case CRYPTO_HASH_ALG_HMAC_SHA1:
                SHA1Update(&ctx->u.sha1, data, len);
                break;
+#ifdef CONFIG_SHA256
+       case CRYPTO_HASH_ALG_SHA256:
+       case CRYPTO_HASH_ALG_HMAC_SHA256:
+               sha256_process(&ctx->u.sha256, data, len);
+               break;
+#endif /* CONFIG_SHA256 */
+       default:
+               break;
        }
 }
 
@@ -146,6 +186,17 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
                *len = 20;
                SHA1Final(mac, &ctx->u.sha1);
                break;
+#ifdef CONFIG_SHA256
+       case CRYPTO_HASH_ALG_SHA256:
+               if (*len < 32) {
+                       *len = 32;
+                       os_free(ctx);
+                       return -1;
+               }
+               *len = 32;
+               sha256_done(&ctx->u.sha256, mac);
+               break;
+#endif /* CONFIG_SHA256 */
        case CRYPTO_HASH_ALG_HMAC_MD5:
                if (*len < 16) {
                        *len = 16;
@@ -186,6 +237,31 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
                SHA1Update(&ctx->u.sha1, mac, 20);
                SHA1Final(mac, &ctx->u.sha1);
                break;
+#ifdef CONFIG_SHA256
+       case CRYPTO_HASH_ALG_HMAC_SHA256:
+               if (*len < 32) {
+                       *len = 32;
+                       os_free(ctx);
+                       return -1;
+               }
+               *len = 32;
+
+               sha256_done(&ctx->u.sha256, mac);
+
+               os_memcpy(k_pad, ctx->key, ctx->key_len);
+               os_memset(k_pad + ctx->key_len, 0,
+                         sizeof(k_pad) - ctx->key_len);
+               for (i = 0; i < sizeof(k_pad); i++)
+                       k_pad[i] ^= 0x5c;
+               sha256_init(&ctx->u.sha256);
+               sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
+               sha256_process(&ctx->u.sha256, mac, 32);
+               sha256_done(&ctx->u.sha256, mac);
+               break;
+#endif /* CONFIG_SHA256 */
+       default:
+               os_free(ctx);
+               return -1;
        }
 
        os_free(ctx);
index 8c475bf..2a67d99 100644 (file)
@@ -22,7 +22,7 @@
 void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
 {
        *publ = dh_init(dh_groups_get(5), priv);
-       if (*publ == 0)
+       if (*publ == NULL)
                return NULL;
        return (void *) 1;
 }
index 7bd2fb7..e5b7d4c 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "common.h"
 #include "crypto.h"
+#include "random.h"
 #include "dh_groups.h"
 
 
@@ -564,7 +565,8 @@ struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv)
        if (*priv == NULL)
                return NULL;
 
-       if (os_get_random(wpabuf_put(*priv, dh->prime_len), dh->prime_len)) {
+       if (random_get_bytes(wpabuf_put(*priv, dh->prime_len), dh->prime_len))
+       {
                wpabuf_free(*priv);
                *priv = NULL;
                return NULL;
index a85cb14..1e0c453 100644 (file)
@@ -28,13 +28,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 f8692a9..137ad91 100644 (file)
@@ -188,7 +188,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
     MD5Transform(ctx->buf, (u32 *) ctx->in);
     byteReverse((unsigned char *) ctx->buf, 4);
     os_memcpy(digest, ctx->buf, 16);
-    os_memset(ctx, 0, sizeof(ctx));    /* In case it's sensitive */
+    os_memset(ctx, 0, sizeof(*ctx));   /* In case it's sensitive */
 }
 
 /* The four core functions - F1 is optimized somewhat */
index dae15ab..c439ae9 100644 (file)
 #include "ms_funcs.h"
 #include "crypto.h"
 
+/**
+ * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding
+ * @utf8_string: UTF-8 string (IN)
+ * @utf8_string_len: Length of utf8_string (IN)
+ * @ucs2_buffer: UCS-2 buffer (OUT)
+ * @ucs2_buffer_size: Length of UCS-2 buffer (IN)
+ * @ucs2_string_size: Number of 2-byte words in the resulting UCS-2 string
+ * Returns: 0 on success, -1 on failure
+ */
+static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
+                        u8 *ucs2_buffer, size_t ucs2_buffer_size,
+                        size_t *ucs2_string_size)
+{
+       size_t i, j;
+
+       for (i = 0, j = 0; i < utf8_string_len; i++) {
+               u8 c = utf8_string[i];
+               if (j >= ucs2_buffer_size) {
+                       /* input too long */
+                       return -1;
+               }
+               if (c <= 0x7F) {
+                       WPA_PUT_LE16(ucs2_buffer + j, c);
+                       j += 2;
+               } else if (i == utf8_string_len - 1 ||
+                          j >= ucs2_buffer_size - 1) {
+                       /* incomplete surrogate */
+                       return -1;
+               } else {
+                       u8 c2 = utf8_string[++i];
+                       if ((c & 0xE0) == 0xC0) {
+                               /* two-byte encoding */
+                               WPA_PUT_LE16(ucs2_buffer + j,
+                                            ((c & 0x1F) << 6) | (c2 & 0x3F));
+                               j += 2;
+                       } else if (i == utf8_string_len ||
+                                  j >= ucs2_buffer_size - 1) {
+                               /* incomplete surrogate */
+                               return -1;
+                       } else {
+                               /* three-byte encoding */
+                               u8 c3 = utf8_string[++i];
+                               WPA_PUT_LE16(ucs2_buffer + j,
+                                            ((c & 0xF) << 12) |
+                                            ((c2 & 0x3F) << 6) | (c3 & 0x3F));
+                       }
+               }
+       }
+
+       if (ucs2_string_size)
+               *ucs2_string_size = j / 2;
+       return 0;
+}
+
 
 /**
  * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
@@ -53,7 +107,7 @@ static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
 
 /**
  * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
  * @password_len: Length of password
  * @password_hash: 16-octet PasswordHash (OUT)
  * Returns: 0 on success, -1 on failure
@@ -62,18 +116,13 @@ int nt_password_hash(const u8 *password, size_t password_len,
                      u8 *password_hash)
 {
        u8 buf[512], *pos;
-       size_t i, len;
+       size_t len, max_len;
 
-       if (password_len > 256)
-               password_len = 256;
-
-       /* Convert password into unicode */
-       for (i = 0; i < password_len; i++) {
-               buf[2 * i] = password[i];
-               buf[2 * i + 1] = 0;
-       }
+       max_len = sizeof(buf);
+       if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0)
+               return -1;
 
-       len = password_len * 2;
+       len *= 2;
        pos = buf;
        return md4_vector(1, (const u8 **) &pos, &len, password_hash);
 }
@@ -117,7 +166,7 @@ void challenge_response(const u8 *challenge, const u8 *password_hash,
  * @peer_challenge: 16-octet PeerChallenge (IN)
  * @username: 0-to-256-char UserName (IN)
  * @username_len: Length of username
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
  * @password_len: Length of password
  * @response: 24-octet Response (OUT)
  * Returns: 0 on success, -1 on failure
@@ -225,7 +274,7 @@ int generate_authenticator_response_pwhash(
 
 /**
  * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
  * @password_len: Length of password
  * @nt_response: 24-octet NT-Response (IN)
  * @peer_challenge: 16-octet PeerChallenge (IN)
@@ -254,7 +303,7 @@ int generate_authenticator_response(const u8 *password, size_t password_len,
 /**
  * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
  * @challenge: 8-octet Challenge (IN)
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
  * @password_len: Length of password
  * @response: 24-octet Response (OUT)
  * Returns: 0 on success, -1 on failure
@@ -375,7 +424,7 @@ int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
 
 /**
  * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
  * @password_len: Length of password
  * @password_hash: 16-octet PasswordHash (IN)
  * @pw_block: 516-byte PwBlock (OUT)
@@ -385,18 +434,23 @@ int encrypt_pw_block_with_password_hash(
        const u8 *password, size_t password_len,
        const u8 *password_hash, u8 *pw_block)
 {
-       size_t i, offset;
+       size_t ucs2_len, offset;
        u8 *pos;
 
-       if (password_len > 256)
+       os_memset(pw_block, 0, PWBLOCK_LEN);
+
+       if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0)
                return -1;
 
-       os_memset(pw_block, 0, PWBLOCK_LEN);
-       offset = (256 - password_len) * 2;
-       if (os_get_random(pw_block, offset) < 0)
+       if (ucs2_len > 256)
                return -1;
-       for (i = 0; i < password_len; i++)
-               pw_block[offset + i * 2] = password[i];
+
+       offset = (256 - ucs2_len) * 2;
+       if (offset != 0) {
+               os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
+               if (os_get_random(pw_block, offset) < 0)
+                       return -1;
+       }
        /*
         * PasswordLength is 4 octets, but since the maximum password length is
         * 256, only first two (in little endian byte order) can be non-zero.
@@ -410,9 +464,9 @@ int encrypt_pw_block_with_password_hash(
 
 /**
  * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
- * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
+ * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
  * @new_password_len: Length of new_password
- * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
+ * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
  * @old_password_len: Length of old_password
  * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
  * Returns: 0 on success, -1 on failure
@@ -450,9 +504,9 @@ void nt_password_hash_encrypted_with_block(const u8 *password_hash,
 
 /**
  * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
- * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
+ * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
  * @new_password_len: Length of new_password
- * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
+ * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
  * @old_password_len: Length of old_password
  * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
  * Returns: 0 on success, -1 on failure
diff --git a/src/crypto/random.c b/src/crypto/random.c
new file mode 100644 (file)
index 0000000..a54e197
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * 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 random number generator is used to provide additional entropy to the
+ * one provided by the operating system (os_get_random()) for session key
+ * generation. The os_get_random() output is expected to be secure and the
+ * implementation here is expected to provide only limited protection against
+ * cases where os_get_random() cannot provide strong randomness. This
+ * implementation shall not be assumed to be secure as the sole source of
+ * randomness. The random_get_bytes() function mixes in randomness from
+ * os_get_random() and as such, calls to os_get_random() can be replaced with
+ * calls to random_get_bytes() without reducing security.
+ *
+ * The design here follows partially the design used in the Linux
+ * drivers/char/random.c, but the implementation here is simpler and not as
+ * strong. This is a compromise to reduce duplicated CPU effort and to avoid
+ * extra code/memory size. As pointed out above, os_get_random() needs to be
+ * guaranteed to be secure for any of the security assumptions to hold.
+ */
+
+#include "utils/includes.h"
+#ifdef __linux__
+#include <fcntl.h>
+#endif /* __linux__ */
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "sha1.h"
+#include "random.h"
+
+#define POOL_WORDS 32
+#define POOL_WORDS_MASK (POOL_WORDS - 1)
+#define POOL_TAP1 26
+#define POOL_TAP2 20
+#define POOL_TAP3 14
+#define POOL_TAP4 7
+#define POOL_TAP5 1
+#define EXTRACT_LEN 16
+#define MIN_READY_MARK 2
+
+static u32 pool[POOL_WORDS];
+static unsigned int input_rotate = 0;
+static unsigned int pool_pos = 0;
+static u8 dummy_key[20];
+#ifdef __linux__
+static size_t dummy_key_avail = 0;
+static int random_fd = -1;
+#endif /* __linux__ */
+static unsigned int own_pool_ready = 0;
+#define RANDOM_ENTROPY_SIZE 20
+static char *random_entropy_file = NULL;
+static int random_entropy_file_read = 0;
+
+#define MIN_COLLECT_ENTROPY 1000
+static unsigned int entropy = 0;
+static unsigned int total_collected = 0;
+
+
+static void random_write_entropy(void);
+
+
+static u32 __ROL32(u32 x, u32 y)
+{
+       return (x << (y & 31)) | (x >> (32 - (y & 31)));
+}
+
+
+static void random_mix_pool(const void *buf, size_t len)
+{
+       static const u32 twist[8] = {
+               0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
+               0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278
+       };
+       const u8 *pos = buf;
+       u32 w;
+
+       wpa_hexdump_key(MSG_EXCESSIVE, "random_mix_pool", buf, len);
+
+       while (len--) {
+               w = __ROL32(*pos++, input_rotate & 31);
+               input_rotate += pool_pos ? 7 : 14;
+               pool_pos = (pool_pos - 1) & POOL_WORDS_MASK;
+               w ^= pool[pool_pos];
+               w ^= pool[(pool_pos + POOL_TAP1) & POOL_WORDS_MASK];
+               w ^= pool[(pool_pos + POOL_TAP2) & POOL_WORDS_MASK];
+               w ^= pool[(pool_pos + POOL_TAP3) & POOL_WORDS_MASK];
+               w ^= pool[(pool_pos + POOL_TAP4) & POOL_WORDS_MASK];
+               w ^= pool[(pool_pos + POOL_TAP5) & POOL_WORDS_MASK];
+               pool[pool_pos] = (w >> 3) ^ twist[w & 7];
+       }
+}
+
+
+static void random_extract(u8 *out)
+{
+       unsigned int i;
+       u8 hash[SHA1_MAC_LEN];
+       u32 *hash_ptr;
+       u32 buf[POOL_WORDS / 2];
+
+       /* First, add hash back to pool to make backtracking more difficult. */
+       hmac_sha1(dummy_key, sizeof(dummy_key), (const u8 *) pool,
+                 sizeof(pool), hash);
+       random_mix_pool(hash, sizeof(hash));
+       /* Hash half the pool to extra data */
+       for (i = 0; i < POOL_WORDS / 2; i++)
+               buf[i] = pool[(pool_pos - i) & POOL_WORDS_MASK];
+       hmac_sha1(dummy_key, sizeof(dummy_key), (const u8 *) buf,
+                 sizeof(buf), hash);
+       /*
+        * Fold the hash to further reduce any potential output pattern.
+        * Though, compromise this to reduce CPU use for the most common output
+        * length (32) and return 16 bytes from instead of only half.
+        */
+       hash_ptr = (u32 *) hash;
+       hash_ptr[0] ^= hash_ptr[4];
+       os_memcpy(out, hash, EXTRACT_LEN);
+}
+
+
+void random_add_randomness(const void *buf, size_t len)
+{
+       struct os_time t;
+       static unsigned int count = 0;
+
+       count++;
+       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
+                * skip the update.
+                */
+               return;
+       }
+
+       os_get_time(&t);
+       wpa_hexdump_key(MSG_EXCESSIVE, "random pool",
+                       (const u8 *) pool, sizeof(pool));
+       random_mix_pool(&t, sizeof(t));
+       random_mix_pool(buf, len);
+       wpa_hexdump_key(MSG_EXCESSIVE, "random pool",
+                       (const u8 *) pool, sizeof(pool));
+       entropy++;
+       total_collected++;
+}
+
+
+int random_get_bytes(void *buf, size_t len)
+{
+       int ret;
+       u8 *bytes = buf;
+       size_t left;
+
+       wpa_printf(MSG_MSGDUMP, "Get randomness: len=%u entropy=%u",
+                  (unsigned int) len, entropy);
+
+       /* Start with assumed strong randomness from OS */
+       ret = os_get_random(buf, len);
+       wpa_hexdump_key(MSG_EXCESSIVE, "random from os_get_random",
+                       buf, len);
+
+       /* Mix in additional entropy extracted from the internal pool */
+       left = len;
+       while (left) {
+               size_t siz, i;
+               u8 tmp[EXTRACT_LEN];
+               random_extract(tmp);
+               wpa_hexdump_key(MSG_EXCESSIVE, "random from internal pool",
+                               tmp, sizeof(tmp));
+               siz = left > EXTRACT_LEN ? EXTRACT_LEN : left;
+               for (i = 0; i < siz; i++)
+                       *bytes++ ^= tmp[i];
+               left -= siz;
+       }
+       wpa_hexdump_key(MSG_EXCESSIVE, "mixed random", buf, len);
+
+       if (entropy < len)
+               entropy = 0;
+       else
+               entropy -= len;
+
+       return ret;
+}
+
+
+int random_pool_ready(void)
+{
+#ifdef __linux__
+       int fd;
+       ssize_t res;
+
+       /*
+        * Make sure that there is reasonable entropy available before allowing
+        * some key derivation operations to proceed.
+        */
+
+       if (dummy_key_avail == sizeof(dummy_key))
+               return 1; /* Already initialized - good to continue */
+
+       /*
+        * Try to fetch some more data from the kernel high quality
+        * /dev/random. There may not be enough data available at this point,
+        * so use non-blocking read to avoid blocking the application
+        * completely.
+        */
+       fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+       if (fd < 0) {
+#ifndef CONFIG_NO_STDOUT_DEBUG
+               int error = errno;
+               perror("open(/dev/random)");
+               wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
+                          strerror(error));
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+               return -1;
+       }
+
+       res = read(fd, dummy_key + dummy_key_avail,
+                  sizeof(dummy_key) - dummy_key_avail);
+       if (res < 0) {
+               wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: "
+                          "%s", strerror(errno));
+               res = 0;
+       }
+       wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from "
+                  "/dev/random", (unsigned) res,
+                  (unsigned) (sizeof(dummy_key) - dummy_key_avail));
+       dummy_key_avail += res;
+       close(fd);
+
+       if (dummy_key_avail == sizeof(dummy_key)) {
+               if (own_pool_ready < MIN_READY_MARK)
+                       own_pool_ready = MIN_READY_MARK;
+               random_write_entropy();
+               return 1;
+       }
+
+       wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
+                  "random data available from /dev/random",
+                  (unsigned) dummy_key_avail, (unsigned) sizeof(dummy_key));
+
+       if (own_pool_ready >= MIN_READY_MARK ||
+           total_collected + 10 * own_pool_ready > MIN_COLLECT_ENTROPY) {
+               wpa_printf(MSG_INFO, "random: Allow operation to proceed "
+                          "based on internal entropy");
+               return 1;
+       }
+
+       wpa_printf(MSG_INFO, "random: Not enough entropy pool available for "
+                  "secure operations");
+       return 0;
+#else /* __linux__ */
+       /* TODO: could do similar checks on non-Linux platforms */
+       return 1;
+#endif /* __linux__ */
+}
+
+
+void random_mark_pool_ready(void)
+{
+       own_pool_ready++;
+       wpa_printf(MSG_DEBUG, "random: Mark internal entropy pool to be "
+                  "ready (count=%u/%u)", own_pool_ready, MIN_READY_MARK);
+       random_write_entropy();
+}
+
+
+#ifdef __linux__
+
+static void random_close_fd(void)
+{
+       if (random_fd >= 0) {
+               eloop_unregister_read_sock(random_fd);
+               close(random_fd);
+               random_fd = -1;
+       }
+}
+
+
+static void random_read_fd(int sock, void *eloop_ctx, void *sock_ctx)
+{
+       ssize_t res;
+
+       if (dummy_key_avail == sizeof(dummy_key)) {
+               random_close_fd();
+               return;
+       }
+
+       res = read(sock, dummy_key + dummy_key_avail,
+                  sizeof(dummy_key) - dummy_key_avail);
+       if (res < 0) {
+               wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: "
+                          "%s", strerror(errno));
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from /dev/random",
+                  (unsigned) res,
+                  (unsigned) (sizeof(dummy_key) - dummy_key_avail));
+       dummy_key_avail += res;
+
+       if (dummy_key_avail == sizeof(dummy_key)) {
+               random_close_fd();
+               if (own_pool_ready < MIN_READY_MARK)
+                       own_pool_ready = MIN_READY_MARK;
+               random_write_entropy();
+       }
+}
+
+#endif /* __linux__ */
+
+
+static void random_read_entropy(void)
+{
+       char *buf;
+       size_t len;
+
+       if (!random_entropy_file)
+               return;
+
+       buf = os_readfile(random_entropy_file, &len);
+       if (buf == NULL)
+               return; /* entropy file not yet available */
+
+       if (len != 1 + RANDOM_ENTROPY_SIZE) {
+               wpa_printf(MSG_DEBUG, "random: Invalid entropy file %s",
+                          random_entropy_file);
+               os_free(buf);
+               return;
+       }
+
+       own_pool_ready = (u8) buf[0];
+       random_add_randomness(buf + 1, RANDOM_ENTROPY_SIZE);
+       random_entropy_file_read = 1;
+       os_free(buf);
+       wpa_printf(MSG_DEBUG, "random: Added entropy from %s "
+                  "(own_pool_ready=%u)",
+                  random_entropy_file, own_pool_ready);
+}
+
+
+static void random_write_entropy(void)
+{
+       char buf[RANDOM_ENTROPY_SIZE];
+       FILE *f;
+       u8 opr;
+       int fail = 0;
+
+       if (!random_entropy_file)
+               return;
+
+       if (random_get_bytes(buf, RANDOM_ENTROPY_SIZE) < 0)
+               return;
+
+       f = fopen(random_entropy_file, "wb");
+       if (f == NULL) {
+               wpa_printf(MSG_ERROR, "random: Could not open entropy file %s "
+                          "for writing", random_entropy_file);
+               return;
+       }
+
+       opr = own_pool_ready > 0xff ? 0xff : own_pool_ready;
+       if (fwrite(&opr, 1, 1, f) != 1 ||
+           fwrite(buf, RANDOM_ENTROPY_SIZE, 1, f) != 1)
+               fail = 1;
+       fclose(f);
+       if (fail) {
+               wpa_printf(MSG_ERROR, "random: Could not write entropy data "
+                          "to %s", random_entropy_file);
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "random: Updated entropy file %s "
+                  "(own_pool_ready=%u)",
+                  random_entropy_file, own_pool_ready);
+}
+
+
+void random_init(const char *entropy_file)
+{
+       os_free(random_entropy_file);
+       if (entropy_file)
+               random_entropy_file = os_strdup(entropy_file);
+       else
+               random_entropy_file = NULL;
+       random_read_entropy();
+
+#ifdef __linux__
+       if (random_fd >= 0)
+               return;
+
+       random_fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+       if (random_fd < 0) {
+#ifndef CONFIG_NO_STDOUT_DEBUG
+               int error = errno;
+               perror("open(/dev/random)");
+               wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
+                          strerror(error));
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+               return;
+       }
+       wpa_printf(MSG_DEBUG, "random: Trying to read entropy from "
+                  "/dev/random");
+
+       eloop_register_read_sock(random_fd, random_read_fd, NULL, NULL);
+#endif /* __linux__ */
+
+       random_write_entropy();
+}
+
+
+void random_deinit(void)
+{
+#ifdef __linux__
+       random_close_fd();
+#endif /* __linux__ */
+       random_write_entropy();
+       os_free(random_entropy_file);
+       random_entropy_file = NULL;
+}
diff --git a/src/crypto/random.h b/src/crypto/random.h
new file mode 100644 (file)
index 0000000..1048bb4
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef RANDOM_H
+#define RANDOM_H
+
+#ifdef CONFIG_NO_RANDOM_POOL
+#define random_init(e) do { } while (0)
+#define random_deinit() do { } while (0)
+#define random_add_randomness(b, l) do { } while (0)
+#define random_get_bytes(b, l) os_get_random((b), (l))
+#define random_pool_ready() 1
+#define random_mark_pool_ready() do { } while (0)
+#else /* CONFIG_NO_RANDOM_POOL */
+void random_init(const char *entropy_file);
+void random_deinit(void);
+void random_add_randomness(const void *buf, size_t len);
+int random_get_bytes(void *buf, size_t len);
+int random_pool_ready(void);
+void random_mark_pool_ready(void);
+#endif /* CONFIG_NO_RANDOM_POOL */
+
+#endif /* RANDOM_H */
index 11323de..9dac977 100644 (file)
@@ -16,8 +16,6 @@
 
 #include "common.h"
 #include "sha1.h"
-#include "md5.h"
-#include "crypto.h"
 
 static int pbkdf2_sha1_f(const char *passphrase, const char *ssid,
                         size_t ssid_len, int iterations, unsigned int count,
index 2c8c029..f98fd65 100644 (file)
 #include "common.h"
 #include "sha1.h"
 #include "md5.h"
-#include "crypto.h"
 
 
 /**
- * tls_prf - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
+ * tls_prf_sha1_md5 - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
  * @secret: Key for PRF
  * @secret_len: Length of the key in bytes
  * @label: A unique label for each purpose of the PRF
@@ -34,8 +33,8 @@
  * This function is used to derive new, cryptographically separate keys from a
  * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
  */
-int tls_prf(const u8 *secret, size_t secret_len, const char *label,
-           const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
+                    const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
 {
        size_t L_S1, L_S2, i;
        const u8 *S1, *S2;
index c1a6233..f0c1a5f 100644 (file)
@@ -25,9 +25,9 @@ int sha1_prf(const u8 *key, size_t key_len, const char *label,
             const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
 int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
               const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len);
-int __must_check tls_prf(const u8 *secret, size_t secret_len,
-                        const char *label, const u8 *seed, size_t seed_len,
-                        u8 *out, size_t outlen);
+int __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 iterations, u8 *buf, size_t buflen);
 #endif /* SHA1_H */
index b061373..ef5751d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * SHA-256 hash implementation and interface functions
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * 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
 
 #include "common.h"
 #include "sha256.h"
+#include "sha256_i.h"
 #include "crypto.h"
 
-struct sha256_state {
-       u64 length;
-       u32 state[8], curlen;
-       u8 buf[64];
-};
-
-static void sha256_init(struct sha256_state *md);
-static int sha256_process(struct sha256_state *md, const unsigned char *in,
-                         unsigned long inlen);
-static int sha256_done(struct sha256_state *md, unsigned char *out);
-
 
 /**
  * sha256_vector - SHA256 hash for data vector
@@ -137,7 +127,7 @@ static int sha256_compress(struct sha256_state *md, unsigned char *buf)
 
 
 /* Initialize the hash state */
-static void sha256_init(struct sha256_state *md)
+void sha256_init(struct sha256_state *md)
 {
        md->curlen = 0;
        md->length = 0;
@@ -158,32 +148,31 @@ static void sha256_init(struct sha256_state *md)
    @param inlen  The length of the data (octets)
    @return CRYPT_OK if successful
 */
-static int sha256_process(struct sha256_state *md, const unsigned char *in,
-                         unsigned long inlen)
+int sha256_process(struct sha256_state *md, const unsigned char *in,
+                  unsigned long inlen)
 {
        unsigned long n;
-#define block_size 64
 
-       if (md->curlen > sizeof(md->buf))
+       if (md->curlen >= sizeof(md->buf))
                return -1;
 
        while (inlen > 0) {
-               if (md->curlen == 0 && inlen >= block_size) {
+               if (md->curlen == 0 && inlen >= SHA256_BLOCK_SIZE) {
                        if (sha256_compress(md, (unsigned char *) in) < 0)
                                return -1;
-                       md->length += block_size * 8;
-                       in += block_size;
-                       inlen -= block_size;
+                       md->length += SHA256_BLOCK_SIZE * 8;
+                       in += SHA256_BLOCK_SIZE;
+                       inlen -= SHA256_BLOCK_SIZE;
                } else {
-                       n = MIN(inlen, (block_size - md->curlen));
+                       n = MIN(inlen, (SHA256_BLOCK_SIZE - md->curlen));
                        os_memcpy(md->buf + md->curlen, in, n);
                        md->curlen += n;
                        in += n;
                        inlen -= n;
-                       if (md->curlen == block_size) {
+                       if (md->curlen == SHA256_BLOCK_SIZE) {
                                if (sha256_compress(md, md->buf) < 0)
                                        return -1;
-                               md->length += 8 * block_size;
+                               md->length += 8 * SHA256_BLOCK_SIZE;
                                md->curlen = 0;
                        }
                }
@@ -199,7 +188,7 @@ static int sha256_process(struct sha256_state *md, const unsigned char *in,
    @param out [out] The destination of the hash (32 bytes)
    @return CRYPT_OK if successful
 */
-static int sha256_done(struct sha256_state *md, unsigned char *out)
+int sha256_done(struct sha256_state *md, unsigned char *out)
 {
        int i;
 
@@ -217,14 +206,14 @@ static int sha256_done(struct sha256_state *md, unsigned char *out)
         * encoding like normal.
         */
        if (md->curlen > 56) {
-               while (md->curlen < 64) {
+               while (md->curlen < SHA256_BLOCK_SIZE) {
                        md->buf[md->curlen++] = (unsigned char) 0;
                }
                sha256_compress(md, md->buf);
                md->curlen = 0;
        }
 
-       /* pad upto 56 bytes of zeroes */
+       /* pad up to 56 bytes of zeroes */
        while (md->curlen < 56) {
                md->buf[md->curlen++] = (unsigned char) 0;
        }
diff --git a/src/crypto/sha256-tlsprf.c b/src/crypto/sha256-tlsprf.c
new file mode 100644 (file)
index 0000000..6763c96
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha256.h"
+
+
+/**
+ * tls_prf_sha256 - Pseudo-Random Function for TLS v1.2 (P_SHA256, RFC 5246)
+ * @secret: Key for PRF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
+ */
+void tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
+                   const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+{
+       size_t clen;
+       u8 A[SHA256_MAC_LEN];
+       u8 P[SHA256_MAC_LEN];
+       size_t pos;
+       const unsigned char *addr[3];
+       size_t len[3];
+
+       addr[0] = A;
+       len[0] = SHA256_MAC_LEN;
+       addr[1] = (unsigned char *) label;
+       len[1] = os_strlen(label);
+       addr[2] = seed;
+       len[2] = seed_len;
+
+       /*
+        * RFC 5246, Chapter 5
+        * A(0) = seed, A(i) = HMAC(secret, A(i-1))
+        * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
+        * PRF(secret, label, seed) = P_SHA256(secret, label + seed)
+        */
+
+       hmac_sha256_vector(secret, secret_len, 2, &addr[1], &len[1], A);
+
+       pos = 0;
+       while (pos < outlen) {
+               hmac_sha256_vector(secret, secret_len, 3, addr, len, P);
+               hmac_sha256(secret, secret_len, A, SHA256_MAC_LEN, A);
+
+               clen = outlen - pos;
+               if (clen > SHA256_MAC_LEN)
+                       clen = SHA256_MAC_LEN;
+               os_memcpy(out + pos, P, clen);
+               pos += clen;
+       }
+}
index dc597f0..b1ce6af 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * SHA256 hash implementation and interface functions
- * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ * 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
@@ -23,5 +23,8 @@ void hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
                 size_t data_len, u8 *mac);
 void sha256_prf(const u8 *key, size_t key_len, const char *label,
              const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+void tls_prf_sha256(const u8 *secret, size_t secret_len,
+                   const char *label, const u8 *seed, size_t seed_len,
+                   u8 *out, size_t outlen);
 
 #endif /* SHA256_H */
diff --git a/src/crypto/sha256_i.h b/src/crypto/sha256_i.h
new file mode 100644 (file)
index 0000000..20ae488
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#ifndef SHA256_I_H
+#define SHA256_I_H
+
+#define SHA256_BLOCK_SIZE 64
+
+struct sha256_state {
+       u64 length;
+       u32 state[8], curlen;
+       u8 buf[SHA256_BLOCK_SIZE];
+};
+
+void sha256_init(struct sha256_state *md);
+int sha256_process(struct sha256_state *md, const unsigned char *in,
+                  unsigned long inlen);
+int sha256_done(struct sha256_state *md, unsigned char *out);
+
+#endif /* SHA256_I_H */
index 0928b5b..d9d88cb 100644 (file)
@@ -24,8 +24,6 @@ struct tls_keys {
        size_t client_random_len;
        const u8 *server_random;
        size_t server_random_len;
-       const u8 *inner_secret; /* TLS/IA inner secret */
-       size_t inner_secret_len;
 };
 
 enum tls_event {
@@ -72,6 +70,7 @@ struct tls_config {
        const char *pkcs11_engine_path;
        const char *pkcs11_module_path;
        int fips_mode;
+       int cert_in_cb;
 
        void (*event_cb)(void *ctx, enum tls_event ev,
                         union tls_event_data *data);
@@ -114,7 +113,6 @@ struct tls_config {
  * specific for now)
  * @cert_id: the certificate's id when using engine
  * @ca_cert_id: the CA certificate's id when using engine
- * @tls_ia: Whether to enable TLS/IA (for EAP-TTLSv1)
  * @flags: Parameter options (TLS_CONN_*)
  *
  * TLS connection parameters to be configured with tls_connection_set_params()
@@ -142,7 +140,6 @@ struct tls_connection_params {
        const char *dh_file;
        const u8 *dh_blob;
        size_t dh_blob_len;
-       int tls_ia;
 
        /* OpenSSL specific variables */
        int engine;
@@ -282,20 +279,6 @@ int __must_check tls_connection_set_verify(void *tls_ctx,
                                           int verify_peer);
 
 /**
- * tls_connection_set_ia - Set TLS/IA parameters
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @tls_ia: 1 = enable TLS/IA
- * Returns: 0 on success, -1 on failure
- *
- * This function is used to configure TLS/IA in server mode where
- * tls_connection_set_params() is not used.
- */
-int __must_check tls_connection_set_ia(void *tls_ctx,
-                                      struct tls_connection *conn,
-                                      int tls_ia);
-
-/**
  * tls_connection_get_keys - Get master key and random data from TLS connection
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
@@ -322,7 +305,7 @@ int __must_check tls_connection_get_keys(void *tls_ctx,
  * not exported from the TLS library, tls_connection_prf() is required so that
  * further keying material can be derived from the master secret. If not
  * implemented, the function will still need to be defined, but it can just
- * return -1. Example implementation of this function is in tls_prf() function
+ * return -1. Example implementation of this function is in tls_prf_sha1_md5()
  * when it is called with seed set to client_random|server_random (or
  * server_random|client_random).
  */
@@ -364,6 +347,12 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
                                         const struct wpabuf *in_data,
                                         struct wpabuf **appl_data);
 
+struct wpabuf * tls_connection_handshake2(void *tls_ctx,
+                                         struct tls_connection *conn,
+                                         const struct wpabuf *in_data,
+                                         struct wpabuf **appl_data,
+                                         int *more_data_needed);
+
 /**
  * tls_connection_server_handshake - Process TLS handshake (server side)
  * @tls_ctx: TLS context data from tls_init()
@@ -409,6 +398,11 @@ struct wpabuf * tls_connection_decrypt(void *tls_ctx,
                                       struct tls_connection *conn,
                                       const struct wpabuf *in_data);
 
+struct wpabuf * tls_connection_decrypt2(void *tls_ctx,
+                                       struct tls_connection *conn,
+                                       const struct wpabuf *in_data,
+                                       int *more_data_needed);
+
 /**
  * tls_connection_resumed - Was session resumption used
  * @tls_ctx: TLS context data from tls_init()
@@ -514,7 +508,6 @@ int tls_connection_get_write_alerts(void *tls_ctx,
 int tls_connection_get_keyblock_size(void *tls_ctx,
                                     struct tls_connection *conn);
 
-#define TLS_CAPABILITY_IA 0x0001 /* TLS Inner Application (TLS/IA) */
 /**
  * tls_capabilities - Get supported TLS capabilities
  * @tls_ctx: TLS context data from tls_init()
@@ -522,42 +515,6 @@ int tls_connection_get_keyblock_size(void *tls_ctx,
  */
 unsigned int tls_capabilities(void *tls_ctx);
 
-/**
- * tls_connection_ia_send_phase_finished - Send a TLS/IA PhaseFinished message
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @final: 1 = FinalPhaseFinished, 0 = IntermediatePhaseFinished
- * Returns: Encrypted TLS/IA data, %NULL on failure
- *
- * This function is used to send the TLS/IA end phase message, e.g., when the
- * EAP server completes EAP-TTLSv1.
- */
-struct wpabuf * tls_connection_ia_send_phase_finished(
-       void *tls_ctx, struct tls_connection *conn, int final);
-
-/**
- * tls_connection_ia_final_phase_finished - Has final phase been completed
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * Returns: 1 if valid FinalPhaseFinished has been received, 0 if not, or -1
- * on failure
- */
-int __must_check tls_connection_ia_final_phase_finished(
-       void *tls_ctx, struct tls_connection *conn);
-
-/**
- * tls_connection_ia_permute_inner_secret - Permute TLS/IA inner secret
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @key: Session key material (session_key vectors with 2-octet length), or
- * %NULL if no session key was generating in the current phase
- * @key_len: Length of session key material
- * Returns: 0 on success, -1 on failure
- */
-int __must_check tls_connection_ia_permute_inner_secret(
-       void *tls_ctx, struct tls_connection *conn,
-       const u8 *key, size_t key_len);
-
 typedef int (*tls_session_ticket_cb)
 (void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
  const u8 *server_random, u8 *master_secret);
index c3a7358..afa5268 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * SSL/TLS interface functions for GnuTLS
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * 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
 #include <gnutls/pkcs12.h>
 #endif /* PKCS12_FUNCS */
 
-#ifdef CONFIG_GNUTLS_EXTRA
-#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
-#define GNUTLS_IA
-#include <gnutls/extra.h>
-#if LIBGNUTLS_VERSION_NUMBER == 0x010302
-/* This function is not included in the current gnutls/extra.h even though it
- * should be, so define it here as a workaround for the time being. */
-int gnutls_ia_verify_endphase(gnutls_session_t session, char *checksum);
-#endif /* LIBGNUTLS_VERSION_NUMBER == 0x010302 */
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
-#endif /* CONFIG_GNUTLS_EXTRA */
-
 #include "common.h"
 #include "tls.h"
 
 
-#ifndef TLS_RANDOM_SIZE
-#define TLS_RANDOM_SIZE 32
-#endif
-#ifndef TLS_MASTER_SIZE
-#define TLS_MASTER_SIZE 48
-#endif
+#define WPA_TLS_RANDOM_SIZE 32
+#define WPA_TLS_MASTER_SIZE 48
 
 
 #if LIBGNUTLS_VERSION_NUMBER < 0x010302
@@ -77,9 +61,9 @@ typedef struct {
        gnutls_mac_algorithm_t write_mac_algorithm;
        gnutls_compression_method_t write_compression_algorithm;
        cipher_suite_st current_cipher_suite;
-       opaque master_secret[TLS_MASTER_SIZE];
-       opaque client_random[TLS_RANDOM_SIZE];
-       opaque server_random[TLS_RANDOM_SIZE];
+       opaque master_secret[WPA_TLS_MASTER_SIZE];
+       opaque client_random[WPA_TLS_RANDOM_SIZE];
+       opaque server_random[WPA_TLS_RANDOM_SIZE];
        /* followed by stuff we are not interested in */
 } security_parameters_st;
 
@@ -118,21 +102,6 @@ struct tls_connection {
 
        int params_set;
        gnutls_certificate_credentials_t xcred;
-
-       int tls_ia;
-       int final_phase_finished;
-
-#ifdef GNUTLS_IA
-       gnutls_ia_server_credentials_t iacred_srv;
-       gnutls_ia_client_credentials_t iacred_cli;
-
-       /* Session keys generated in the current phase for inner secret
-        * permutation before generating/verifying PhaseFinished. */
-       u8 *session_keys;
-       size_t session_keys_len;
-
-       u8 inner_secret[TLS_MASTER_SIZE];
-#endif /* GNUTLS_IA */
 };
 
 
@@ -285,8 +254,12 @@ static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
 static int tls_gnutls_init_session(struct tls_global *global,
                                   struct tls_connection *conn)
 {
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
+       const char *err;
+#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
        const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
        const int protos[2] = { GNUTLS_TLS1, 0 };
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
        int ret;
 
        ret = gnutls_init(&conn->session,
@@ -301,6 +274,15 @@ static int tls_gnutls_init_session(struct tls_global *global,
        if (ret < 0)
                goto fail;
 
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
+       ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
+                                        &err);
+       if (ret < 0) {
+               wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
+                          "'%s'", err);
+               goto fail;
+       }
+#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
        ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
        if (ret < 0)
                goto fail;
@@ -308,6 +290,7 @@ static int tls_gnutls_init_session(struct tls_global *global,
        ret = gnutls_protocol_set_priority(conn->session, protos);
        if (ret < 0)
                goto fail;
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
 
        gnutls_transport_set_pull_function(conn->session, tls_pull_func);
        gnutls_transport_set_push_function(conn->session, tls_push_func);
@@ -364,17 +347,6 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
        if (conn == NULL)
                return;
 
-#ifdef GNUTLS_IA
-       if (conn->iacred_srv)
-               gnutls_ia_free_server_credentials(conn->iacred_srv);
-       if (conn->iacred_cli)
-               gnutls_ia_free_client_credentials(conn->iacred_cli);
-       if (conn->session_keys) {
-               os_memset(conn->session_keys, 0, conn->session_keys_len);
-               os_free(conn->session_keys);
-       }
-#endif /* GNUTLS_IA */
-
        gnutls_certificate_free_credentials(conn->xcred);
        gnutls_deinit(conn->session);
        os_free(conn->pre_shared_secret);
@@ -407,14 +379,6 @@ int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
        wpabuf_free(conn->push_buf);
        conn->push_buf = NULL;
        conn->established = 0;
-       conn->final_phase_finished = 0;
-#ifdef GNUTLS_IA
-       if (conn->session_keys) {
-               os_memset(conn->session_keys, 0, conn->session_keys_len);
-               os_free(conn->session_keys);
-       }
-       conn->session_keys_len = 0;
-#endif /* GNUTLS_IA */
 
        gnutls_deinit(conn->session);
        if (tls_gnutls_init_session(global, conn)) {
@@ -597,11 +561,13 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
                                conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
                }
 
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
                if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
                        gnutls_certificate_set_verify_flags(
                                conn->xcred,
                                GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
                }
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
        }
 
        if (params->client_cert && params->private_key) {
@@ -646,7 +612,6 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
                }
        }
 
-       conn->tls_ia = params->tls_ia;
        conn->params_set = 1;
 
        ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
@@ -656,28 +621,6 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
                           gnutls_strerror(ret));
        }
 
-#ifdef GNUTLS_IA
-       if (conn->iacred_cli)
-               gnutls_ia_free_client_credentials(conn->iacred_cli);
-
-       ret = gnutls_ia_allocate_client_credentials(&conn->iacred_cli);
-       if (ret) {
-               wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
-                          gnutls_strerror(ret));
-               return -1;
-       }
-
-       ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
-                                    conn->iacred_cli);
-       if (ret) {
-               wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
-                          gnutls_strerror(ret));
-               gnutls_ia_free_client_credentials(conn->iacred_cli);
-               conn->iacred_cli = NULL;
-               return -1;
-       }
-#endif /* GNUTLS_IE */
-
        return ret;
 }
 
@@ -729,11 +672,13 @@ int tls_global_set_params(void *tls_ctx,
                                GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
                }
 
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
                if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
                        gnutls_certificate_set_verify_flags(
                                global->xcred,
                                GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
                }
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
        }
 
        if (params->client_cert && params->private_key) {
@@ -822,10 +767,11 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
 
        os_memset(keys, 0, sizeof(*keys));
 
+#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
        sec = &conn->session->security_parameters;
        keys->master_key = sec->master_secret;
-       keys->master_key_len = TLS_MASTER_SIZE;
+       keys->master_key_len = WPA_TLS_MASTER_SIZE;
        keys->client_random = sec->client_random;
        keys->server_random = sec->server_random;
 #else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
@@ -835,16 +781,12 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
                (u8 *) gnutls_session_get_server_random(conn->session);
        /* No access to master_secret */
 #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
 
-#ifdef GNUTLS_IA
-       gnutls_ia_extract_inner_secret(conn->session,
-                                      (char *) conn->inner_secret);
-       keys->inner_secret = conn->inner_secret;
-       keys->inner_secret_len = TLS_MASTER_SIZE;
-#endif /* GNUTLS_IA */
-
-       keys->client_random_len = TLS_RANDOM_SIZE;
-       keys->server_random_len = TLS_RANDOM_SIZE;
+#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
+       keys->client_random_len = WPA_TLS_RANDOM_SIZE;
+       keys->server_random_len = WPA_TLS_RANDOM_SIZE;
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
 
        return 0;
 }
@@ -883,11 +825,13 @@ static int tls_connection_verify_peer(struct tls_connection *conn,
 
        if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
                wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
+               *err = GNUTLS_A_INTERNAL_ERROR;
                if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
                        wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
                                   "algorithm");
                        *err = GNUTLS_A_INSUFFICIENT_SECURITY;
                }
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
                if (status & GNUTLS_CERT_NOT_ACTIVATED) {
                        wpa_printf(MSG_INFO, "TLS: Certificate not yet "
                                   "activated");
@@ -897,6 +841,7 @@ static int tls_connection_verify_peer(struct tls_connection *conn,
                        wpa_printf(MSG_INFO, "TLS: Certificate expired");
                        *err = GNUTLS_A_CERTIFICATE_EXPIRED;
                }
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
                return -1;
        }
 
@@ -988,7 +933,7 @@ static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
                                 wpabuf_size(ad));
        wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
        if (res < 0) {
-               wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
+               wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
                           "(%s)", __func__, (int) res,
                           gnutls_strerror(res));
                wpabuf_free(ad);
@@ -1062,20 +1007,7 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
                        goto out;
                }
 
-#ifdef CONFIG_GNUTLS_EXTRA
-               if (conn->tls_ia && !gnutls_ia_handshake_p(conn->session)) {
-                       wpa_printf(MSG_INFO, "TLS: No TLS/IA negotiation");
-                       conn->failed++;
-                       return NULL;
-               }
-#endif /* CONFIG_GNUTLS_EXTRA */
-
-               if (conn->tls_ia)
-                       wpa_printf(MSG_DEBUG, "TLS: Start TLS/IA handshake");
-               else {
-                       wpa_printf(MSG_DEBUG, "TLS: Handshake completed "
-                                  "successfully");
-               }
+               wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
                conn->established = 1;
                if (conn->push_buf == NULL) {
                        /* Need to return something to get final TLS ACK. */
@@ -1122,12 +1054,6 @@ struct wpabuf * tls_connection_encrypt(void *tls_ctx,
        ssize_t res;
        struct wpabuf *buf;
 
-#ifdef GNUTLS_IA
-       if (conn->tls_ia)
-               res = gnutls_ia_send(conn->session, wpabuf_head(in_data),
-                                    wpabuf_len(in_data));
-       else
-#endif /* GNUTLS_IA */
        res = gnutls_record_send(conn->session, wpabuf_head(in_data),
                                 wpabuf_len(in_data));
        if (res < 0) {
@@ -1170,65 +1096,6 @@ struct wpabuf * tls_connection_decrypt(void *tls_ctx,
        if (out == NULL)
                return NULL;
 
-#ifdef GNUTLS_IA
-       if (conn->tls_ia) {
-               res = gnutls_ia_recv(conn->session, wpabuf_mhead(out),
-                                    wpabuf_size(out));
-               if (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
-                   res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED) {
-                       int final = res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED;
-                       wpa_printf(MSG_DEBUG, "%s: Received %sPhaseFinished",
-                                  __func__, final ? "Final" : "Intermediate");
-
-                       res = gnutls_ia_permute_inner_secret(
-                               conn->session, conn->session_keys_len,
-                               (char *) conn->session_keys);
-                       if (conn->session_keys) {
-                               os_memset(conn->session_keys, 0,
-                                         conn->session_keys_len);
-                               os_free(conn->session_keys);
-                       }
-                       conn->session_keys = NULL;
-                       conn->session_keys_len = 0;
-                       if (res) {
-                               wpa_printf(MSG_DEBUG, "%s: Failed to permute "
-                                          "inner secret: %s",
-                                          __func__, gnutls_strerror(res));
-                               wpabuf_free(out);
-                               return NULL;
-                       }
-
-                       res = gnutls_ia_verify_endphase(conn->session,
-                                                       wpabuf_head(out));
-                       if (res == 0) {
-                               wpa_printf(MSG_DEBUG, "%s: Correct endphase "
-                                          "checksum", __func__);
-                       } else {
-                               wpa_printf(MSG_INFO, "%s: Endphase "
-                                          "verification failed: %s",
-                                          __func__, gnutls_strerror(res));
-                               wpabuf_free(out);
-                               return NULL;
-                       }
-
-                       if (final)
-                               conn->final_phase_finished = 1;
-
-                       return out;
-               }
-
-               if (res < 0) {
-                       wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
-                                  "(%s)", __func__, (int) res,
-                                  gnutls_strerror(res));
-                       wpabuf_free(out);
-                       return NULL;
-               }
-               wpabuf_put(out, res);
-               return out;
-       }
-#endif /* GNUTLS_IA */
-
        res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
                                 wpabuf_size(out));
        if (res < 0) {
@@ -1319,133 +1186,7 @@ int tls_connection_get_keyblock_size(void *tls_ctx,
 
 unsigned int tls_capabilities(void *tls_ctx)
 {
-       unsigned int capa = 0;
-
-#ifdef GNUTLS_IA
-       capa |= TLS_CAPABILITY_IA;
-#endif /* GNUTLS_IA */
-
-       return capa;
-}
-
-
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-                         int tls_ia)
-{
-#ifdef GNUTLS_IA
-       int ret;
-
-       if (conn == NULL)
-               return -1;
-
-       conn->tls_ia = tls_ia;
-       if (!tls_ia)
-               return 0;
-
-       ret = gnutls_ia_allocate_server_credentials(&conn->iacred_srv);
-       if (ret) {
-               wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
-                          gnutls_strerror(ret));
-               return -1;
-       }
-
-       ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
-                                    conn->iacred_srv);
-       if (ret) {
-               wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
-                          gnutls_strerror(ret));
-               gnutls_ia_free_server_credentials(conn->iacred_srv);
-               conn->iacred_srv = NULL;
-               return -1;
-       }
-
-       return 0;
-#else /* GNUTLS_IA */
-       return -1;
-#endif /* GNUTLS_IA */
-}
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
-       void *tls_ctx, struct tls_connection *conn, int final)
-{
-#ifdef GNUTLS_IA
-       int ret;
-       struct wpabuf *buf;
-
-       if (conn == NULL || conn->session == NULL || !conn->tls_ia)
-               return NULL;
-
-       ret = gnutls_ia_permute_inner_secret(conn->session,
-                                            conn->session_keys_len,
-                                            (char *) conn->session_keys);
-       if (conn->session_keys) {
-               os_memset(conn->session_keys, 0, conn->session_keys_len);
-               os_free(conn->session_keys);
-       }
-       conn->session_keys = NULL;
-       conn->session_keys_len = 0;
-       if (ret) {
-               wpa_printf(MSG_DEBUG, "%s: Failed to permute inner secret: %s",
-                          __func__, gnutls_strerror(ret));
-               return NULL;
-       }
-
-       ret = gnutls_ia_endphase_send(conn->session, final);
-       if (ret) {
-               wpa_printf(MSG_DEBUG, "%s: Failed to send endphase: %s",
-                          __func__, gnutls_strerror(ret));
-               return NULL;
-       }
-
-       buf = conn->push_buf;
-       conn->push_buf = NULL;
-       return buf;
-#else /* GNUTLS_IA */
-       return NULL;
-#endif /* GNUTLS_IA */
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-                                          struct tls_connection *conn)
-{
-       if (conn == NULL)
-               return -1;
-
-       return conn->final_phase_finished;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-                                          struct tls_connection *conn,
-                                          const u8 *key, size_t key_len)
-{
-#ifdef GNUTLS_IA
-       if (conn == NULL || !conn->tls_ia)
-               return -1;
-
-       if (conn->session_keys) {
-               os_memset(conn->session_keys, 0, conn->session_keys_len);
-               os_free(conn->session_keys);
-       }
-       conn->session_keys_len = 0;
-
-       if (key) {
-               conn->session_keys = os_malloc(key_len);
-               if (conn->session_keys == NULL)
-                       return -1;
-               os_memcpy(conn->session_keys, key, key_len);
-               conn->session_keys_len = key_len;
-       } else {
-               conn->session_keys = NULL;
-               conn->session_keys_len = 0;
-       }
-
        return 0;
-#else /* GNUTLS_IA */
-       return -1;
-#endif /* GNUTLS_IA */
 }
 
 
index 64124d8..f5e31d9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * TLS interface functions and an internal TLS implementation
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * 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
@@ -211,6 +211,9 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
                return -1;
        }
 
+       tlsv1_client_set_time_checks(
+               conn->client, !(params->flags & TLS_CONN_DISABLE_TIME_CHECKS));
+
        return 0;
 #else /* CONFIG_TLS_INTERNAL_CLIENT */
        return -1;
@@ -287,13 +290,6 @@ int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
 }
 
 
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-                         int tls_ia)
-{
-       return -1;
-}
-
-
 int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
                            struct tls_keys *keys)
 {
@@ -336,6 +332,17 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
                                         const struct wpabuf *in_data,
                                         struct wpabuf **appl_data)
 {
+       return tls_connection_handshake2(tls_ctx, conn, in_data, appl_data,
+                                        NULL);
+}
+
+
+struct wpabuf * tls_connection_handshake2(void *tls_ctx,
+                                         struct tls_connection *conn,
+                                         const struct wpabuf *in_data,
+                                         struct wpabuf **appl_data,
+                                         int *need_more_data)
+{
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
        u8 *res, *ad;
        size_t res_len, ad_len;
@@ -348,7 +355,7 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
        res = tlsv1_client_handshake(conn->client,
                                     in_data ? wpabuf_head(in_data) : NULL,
                                     in_data ? wpabuf_len(in_data) : 0,
-                                    &res_len, &ad, &ad_len);
+                                    &res_len, &ad, &ad_len, need_more_data);
        if (res == NULL)
                return NULL;
        out = wpabuf_alloc_ext_data(res, res_len);
@@ -459,23 +466,23 @@ struct wpabuf * tls_connection_decrypt(void *tls_ctx,
                                       struct tls_connection *conn,
                                       const struct wpabuf *in_data)
 {
+       return tls_connection_decrypt2(tls_ctx, conn, in_data, NULL);
+}
+
+
+struct wpabuf * tls_connection_decrypt2(void *tls_ctx,
+                                       struct tls_connection *conn,
+                                       const struct wpabuf *in_data,
+                                       int *need_more_data)
+{
+       if (need_more_data)
+               *need_more_data = 0;
+
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
        if (conn->client) {
-               struct wpabuf *buf;
-               int res;
-               buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
-               if (buf == NULL)
-                       return NULL;
-               res = tlsv1_client_decrypt(conn->client, wpabuf_head(in_data),
-                                          wpabuf_len(in_data),
-                                          wpabuf_mhead(buf),
-                                          wpabuf_size(buf));
-               if (res < 0) {
-                       wpabuf_free(buf);
-                       return NULL;
-               }
-               wpabuf_put(buf, res);
-               return buf;
+               return tlsv1_client_decrypt(conn->client, wpabuf_head(in_data),
+                                           wpabuf_len(in_data),
+                                           need_more_data);
        }
 #endif /* CONFIG_TLS_INTERNAL_CLIENT */
 #ifdef CONFIG_TLS_INTERNAL_SERVER
@@ -608,28 +615,6 @@ unsigned int tls_capabilities(void *tls_ctx)
 }
 
 
-struct wpabuf * tls_connection_ia_send_phase_finished(
-       void *tls_ctx, struct tls_connection *conn, int final)
-{
-       return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-                                          struct tls_connection *conn)
-{
-       return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-                                          struct tls_connection *conn,
-                                          const u8 *key, size_t key_len)
-{
-       return -1;
-}
-
-
 int tls_connection_set_session_ticket_cb(void *tls_ctx,
                                         struct tls_connection *conn,
                                         tls_session_ticket_cb cb,
index 0c836bb..927edf5 100644 (file)
@@ -84,13 +84,6 @@ int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
 }
 
 
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-                         int tls_ia)
-{
-       return -1;
-}
-
-
 int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
                            struct tls_keys *keys)
 {
@@ -205,25 +198,3 @@ unsigned int tls_capabilities(void *tls_ctx)
 {
        return 0;
 }
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
-       void *tls_ctx, struct tls_connection *conn, int final)
-{
-       return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-                                          struct tls_connection *conn)
-{
-       return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-                                          struct tls_connection *conn,
-                                          const u8 *key, size_t key_len)
-{
-       return -1;
-}
index ad834b6..09a1e73 100644 (file)
@@ -419,13 +419,6 @@ int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
 }
 
 
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-                         int tls_ia)
-{
-       return -1;
-}
-
-
 int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
                            struct tls_keys *keys)
 {
@@ -649,28 +642,6 @@ unsigned int tls_capabilities(void *tls_ctx)
 }
 
 
-struct wpabuf * tls_connection_ia_send_phase_finished(
-       void *tls_ctx, struct tls_connection *conn, int final)
-{
-       return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-                                          struct tls_connection *conn)
-{
-       return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-                                          struct tls_connection *conn,
-                                          const u8 *key, size_t key_len)
-{
-       return -1;
-}
-
-
 int tls_connection_set_session_ticket_cb(void *tls_ctx,
                                         struct tls_connection *conn,
                                         tls_session_ticket_cb cb,
index c0a40f9..8374096 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * SSL/TLS interface functions for OpenSSL
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * 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
 #include <openssl/engine.h>
 #endif /* OPENSSL_NO_ENGINE */
 
+#ifdef ANDROID
+#include <openssl/pem.h>
+#include "keystore_get.h"
+#endif /* ANDROID */
+
 #include "common.h"
 #include "crypto.h"
 #include "tls.h"
@@ -54,6 +59,7 @@ struct tls_global {
        void (*event_cb)(void *ctx, enum tls_event ev,
                         union tls_event_data *data);
        void *cb_ctx;
+       int cert_in_cb;
 };
 
 static struct tls_global *tls_global = NULL;
@@ -81,6 +87,8 @@ struct tls_connection {
        unsigned int server_cert_only:1;
 
        u8 srv_cert_hash[32];
+
+       unsigned int flags;
 };
 
 
@@ -687,6 +695,7 @@ void * tls_init(const struct tls_config *conf)
                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
@@ -711,7 +720,7 @@ void * tls_init(const struct tls_config *conf)
 #endif /* CONFIG_FIPS */
                SSL_load_error_strings();
                SSL_library_init();
-#ifndef OPENSSL_NO_SHA256
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
                EVP_add_digest(EVP_sha256());
 #endif /* OPENSSL_NO_SHA256 */
                /* TODO: if /dev/urandom is available, PRNG is seeded
@@ -1137,7 +1146,7 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
                return;
 
        os_memset(&ev, 0, sizeof(ev));
-       if (conn->cert_probe) {
+       if (conn->cert_probe || tls_global->cert_in_cb) {
                cert = get_x509_cert(err_cert);
                ev.peer_cert.cert = cert;
        }
@@ -1178,13 +1187,22 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
        X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
 
        conn = SSL_get_app_data(ssl);
-       match = conn ? conn->subject_match : NULL;
-       altmatch = conn ? conn->altsubject_match : NULL;
+       if (conn == NULL)
+               return 0;
+       match = conn->subject_match;
+       altmatch = conn->altsubject_match;
 
        if (!preverify_ok && !conn->ca_cert_verify)
                preverify_ok = 1;
        if (!preverify_ok && depth > 0 && conn->server_cert_only)
                preverify_ok = 1;
+       if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) &&
+           (err == X509_V_ERR_CERT_HAS_EXPIRED ||
+            err == X509_V_ERR_CERT_NOT_YET_VALID)) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: Ignore certificate validity "
+                          "time mismatch");
+               preverify_ok = 1;
+       }
 
        err_str = X509_verify_cert_error_string(err);
 
@@ -1290,6 +1308,19 @@ static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert)
 #endif /* OPENSSL_NO_STDIO */
 
 
+#ifdef ANDROID
+static BIO * BIO_from_keystore(const char *key)
+{
+       BIO *bio = NULL;
+       char value[KEYSTORE_MESSAGE_SIZE];
+       int length = keystore_get(key, strlen(key), value);
+       if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL)
+               BIO_write(bio, value, length);
+       return bio;
+}
+#endif /* ANDROID */
+
+
 static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
                                  const char *ca_cert, const u8 *ca_cert_blob,
                                  size_t ca_cert_blob_len, const char *ca_path)
@@ -1380,6 +1411,36 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
                return 0;
        }
 
+#ifdef ANDROID
+       if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
+               BIO *bio = BIO_from_keystore(&ca_cert[11]);
+               STACK_OF(X509_INFO) *stack = NULL;
+               int i;
+
+               if (bio) {
+                       stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
+                       BIO_free(bio);
+               }
+               if (!stack)
+                       return -1;
+
+               for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
+                       X509_INFO *info = sk_X509_INFO_value(stack, i);
+                       if (info->x509) {
+                               X509_STORE_add_cert(ssl_ctx->cert_store,
+                                                   info->x509);
+                       }
+                       if (info->crl) {
+                               X509_STORE_add_crl(ssl_ctx->cert_store,
+                                                  info->crl);
+                       }
+               }
+               sk_X509_INFO_pop_free(stack, X509_INFO_free);
+               SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+               return 0;
+       }
+#endif /* ANDROID */
+
 #ifdef CONFIG_NATIVE_WINDOWS
        if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) ==
            0) {
@@ -1550,26 +1611,42 @@ static int tls_connection_client_cert(struct tls_connection *conn,
        if (client_cert == NULL)
                return -1;
 
+#ifdef ANDROID
+       if (os_strncmp("keystore://", client_cert, 11) == 0) {
+               BIO *bio = BIO_from_keystore(&client_cert[11]);
+               X509 *x509 = NULL;
+               int ret = -1;
+               if (bio) {
+                       x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+                       BIO_free(bio);
+               }
+               if (x509) {
+                       if (SSL_use_certificate(conn->ssl, x509) == 1)
+                               ret = 0;
+                       X509_free(x509);
+               }
+               return ret;
+       }
+#endif /* ANDROID */
+
 #ifndef OPENSSL_NO_STDIO
        if (SSL_use_certificate_file(conn->ssl, client_cert,
                                     SSL_FILETYPE_ASN1) == 1) {
                wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)"
                           " --> OK");
                return 0;
-       } else {
-               tls_show_errors(MSG_DEBUG, __func__,
-                               "SSL_use_certificate_file (DER) failed");
        }
 
        if (SSL_use_certificate_file(conn->ssl, client_cert,
                                     SSL_FILETYPE_PEM) == 1) {
+               ERR_clear_error();
                wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)"
                           " --> OK");
                return 0;
-       } else {
-               tls_show_errors(MSG_DEBUG, __func__,
-                               "SSL_use_certificate_file (PEM) failed");
        }
+
+       tls_show_errors(MSG_DEBUG, __func__,
+                       "SSL_use_certificate_file failed");
 #else /* OPENSSL_NO_STDIO */
        wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
 #endif /* OPENSSL_NO_STDIO */
@@ -1586,6 +1663,7 @@ static int tls_global_client_cert(SSL_CTX *ssl_ctx, const char *client_cert)
 
        if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
                                         SSL_FILETYPE_ASN1) != 1 &&
+           SSL_CTX_use_certificate_chain_file(ssl_ctx, client_cert) != 1 &&
            SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
                                         SSL_FILETYPE_PEM) != 1) {
                tls_show_errors(MSG_INFO, __func__,
@@ -1900,10 +1978,6 @@ static int tls_connection_private_key(void *_ssl_ctx,
                                   "ASN1(EVP_PKEY_RSA) --> OK");
                        ok = 1;
                        break;
-               } else {
-                       tls_show_errors(MSG_DEBUG, __func__,
-                                       "SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA)"
-                                       " failed");
                }
 
                if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl,
@@ -1913,10 +1987,6 @@ static int tls_connection_private_key(void *_ssl_ctx,
                                   "ASN1(EVP_PKEY_DSA) --> OK");
                        ok = 1;
                        break;
-               } else {
-                       tls_show_errors(MSG_DEBUG, __func__,
-                                       "SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA)"
-                                       " failed");
                }
 
                if (SSL_use_RSAPrivateKey_ASN1(conn->ssl,
@@ -1926,9 +1996,6 @@ static int tls_connection_private_key(void *_ssl_ctx,
                                   "SSL_use_RSAPrivateKey_ASN1 --> OK");
                        ok = 1;
                        break;
-               } else {
-                       tls_show_errors(MSG_DEBUG, __func__,
-                                       "SSL_use_RSAPrivateKey_ASN1 failed");
                }
 
                if (tls_read_pkcs12_blob(ssl_ctx, conn->ssl, private_key_blob,
@@ -1942,6 +2009,26 @@ static int tls_connection_private_key(void *_ssl_ctx,
                break;
        }
 
+#ifdef ANDROID
+       if (!ok && private_key &&
+           os_strncmp("keystore://", private_key, 11) == 0) {
+               BIO *bio = BIO_from_keystore(&private_key[11]);
+               EVP_PKEY *pkey = NULL;
+               if (bio) {
+                       pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+                       BIO_free(bio);
+               }
+               if (pkey) {
+                       if (SSL_use_PrivateKey(conn->ssl, pkey) == 1) {
+                               wpa_printf(MSG_DEBUG, "OpenSSL: Private key "
+                                          "from keystore");
+                               ok = 1;
+                       }
+                       EVP_PKEY_free(pkey);
+               }
+       }
+#endif /* ANDROID */
+
        while (!ok && private_key) {
 #ifndef OPENSSL_NO_STDIO
                if (SSL_use_PrivateKey_file(conn->ssl, private_key,
@@ -1950,10 +2037,6 @@ static int tls_connection_private_key(void *_ssl_ctx,
                                   "SSL_use_PrivateKey_File (DER) --> OK");
                        ok = 1;
                        break;
-               } else {
-                       tls_show_errors(MSG_DEBUG, __func__,
-                                       "SSL_use_PrivateKey_File (DER) "
-                                       "failed");
                }
 
                if (SSL_use_PrivateKey_file(conn->ssl, private_key,
@@ -1962,10 +2045,6 @@ static int tls_connection_private_key(void *_ssl_ctx,
                                   "SSL_use_PrivateKey_File (PEM) --> OK");
                        ok = 1;
                        break;
-               } else {
-                       tls_show_errors(MSG_DEBUG, __func__,
-                                       "SSL_use_PrivateKey_File (PEM) "
-                                       "failed");
                }
 #else /* OPENSSL_NO_STDIO */
                wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
@@ -1991,9 +2070,9 @@ static int tls_connection_private_key(void *_ssl_ctx,
        }
 
        if (!ok) {
-               wpa_printf(MSG_INFO, "OpenSSL: Failed to load private key");
+               tls_show_errors(MSG_INFO, __func__,
+                               "Failed to load private key");
                os_free(passwd);
-               ERR_clear_error();
                return -1;
        }
        ERR_clear_error();
@@ -2663,6 +2742,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
                return -1;
        }
 
+       conn->flags = params->flags;
+
        tls_get_errors(tls_ctx);
 
        return 0;
@@ -2731,35 +2812,6 @@ unsigned int tls_capabilities(void *tls_ctx)
 }
 
 
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-                         int tls_ia)
-{
-       return -1;
-}
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
-       void *tls_ctx, struct tls_connection *conn, int final)
-{
-       return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-                                          struct tls_connection *conn)
-{
-       return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-                                          struct tls_connection *conn,
-                                          const u8 *key, size_t key_len)
-{
-       return -1;
-}
-
-
 #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
 /* Pre-shared secred requires a patch to openssl, so this function is
  * commented out unless explicitly needed for EAP-FAST in order to be able to
index 4a94e99..a33d24e 100644 (file)
@@ -736,32 +736,3 @@ unsigned int tls_capabilities(void *tls_ctx)
 {
        return 0;
 }
-
-
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-                         int tls_ia)
-{
-       return -1;
-}
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
-       void *tls_ctx, struct tls_connection *conn, int final);
-{
-       return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-                                          struct tls_connection *conn)
-{
-       return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-                                          struct tls_connection *conn,
-                                          const u8 *key, size_t key_len)
-{
-       return -1;
-}
diff --git a/src/drivers/.gitignore b/src/drivers/.gitignore
deleted file mode 100644 (file)
index 1d9e0e6..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-build.wpa_supplicant
-build.hostapd
diff --git a/src/drivers/Apple80211.h b/src/drivers/Apple80211.h
deleted file mode 100644 (file)
index 2a612e7..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-#ifndef APPLE80211_H
-#define APPLE80211_H
-
-/*
- * Apple80211 framework definitions
- * This is an undocumented interface and the definitions here are based on
- * information from MacStumbler (http://www.macstumbler.com/Apple80211.h) and
- * whatever related information can be found with google and experiments ;-).
- */
-
-typedef struct __WirelessRef *WirelessRef;
-typedef SInt32 WirelessError;
-#define errWirelessNoError 0
-
-typedef struct WirelessInfo {
-       UInt16 link_qual;
-       UInt16 comms_qual;
-       UInt16 signal;
-       UInt16 noise;
-       UInt16 port_stat;
-       UInt16 client_mode;
-       UInt16 res1;
-       UInt16 power;
-       UInt16 res2;
-       UInt8 bssID[6];
-       UInt8 ssid[34];
-} WirelessInfo;
-
-typedef struct WirelessInfo2 {
-       /* TODO - these are probably not in correct order or complete */
-       WirelessInfo info1;
-       UInt8 macAddress[6];
-} WirelessInfo2;
-
-typedef struct WirelessNetworkInfo {
-       UInt16 channel;
-       UInt16 noise;
-       UInt16 signal;
-       UInt8 bssid[6];
-       UInt16 beacon_int;
-       UInt16 capability;
-       UInt16 ssid_len;
-       UInt8 ssid[32];
-} WirelessNetworkInfo;
-
-typedef int wirelessKeyType; /* TODO */
-
-int WirelessIsAvailable(void);
-WirelessError WirelessAttach(WirelessRef *ref, UInt32 res);
-WirelessError WirelessDetach(WirelessRef ref);
-WirelessError WirelessPrivate(WirelessRef ref, void *in_ptr, int in_bytes,
-                             void *out_ptr, int out_bytes);
-WirelessError WirelessSetEnabled(WirelessRef ref, UInt8 enabled);
-WirelessError WirelessGetEnabled(WirelessRef ref, UInt8 *enabled);
-WirelessError WirelessSetPower(WirelessRef ref, UInt8 power);
-WirelessError WirelessGetPower(WirelessRef ref, UInt8 *power);
-WirelessError WirelessGetInfo(WirelessRef ref, WirelessInfo *info);
-WirelessError WirelessGetInfo2(WirelessRef ref, WirelessInfo2 *info);
-WirelessError WirelessScan(WirelessRef ref, CFArrayRef *results,
-                          UInt32 strip_dups);
-WirelessError WirelessScanSplit(WirelessRef ref, CFArrayRef *ap_results,
-                               CFArrayRef *ibss_results, UInt32 strip_dups);
-WirelessError WirelessDirectedScan(WirelessRef ref, CFArrayRef *results,
-                                  UInt32 strip_dups, CFStringRef ssid);
-WirelessError WirelessDirectedScan2(WirelessRef ref, CFDataRef ssid,
-                                   UInt32 strip_dups, CFArrayRef *results);
-WirelessError WirelessJoin(WirelessRef ref, CFStringRef ssid);
-WirelessError WirelessJoinWEP(WirelessRef ref, CFStringRef ssid,
-                             CFStringRef passwd);
-WirelessError WirelessJoin8021x(WirelessRef ref, CFStringRef ssid);
-/*
- * Set WEP key
- * ref: wireless reference from WirelessAttach()
- * type: ?
- * key_idx: 0..3
- * key_len: 13 for WEP-104 or 0 for clearing the key
- * key: Pointer to the key or %NULL if key_len = 0
- */
-WirelessError WirelessSetKey(WirelessRef ref, wirelessKeyType type,
-                            int key_idx, int key_len,
-                            const unsigned char *key);
-/*
- * Set WPA key (e.g., PMK for 4-way handshake)
- * ref: wireless reference from WirelessAttach()
- * type: 0..4; 1 = PMK
- * key_len: 16, 32, or 0
- * key: Pointer to the key or %NULL if key_len = 0
- */
-WirelessError WirelessSetWPAKey(WirelessRef ref, wirelessKeyType type,
-                               int key_len, const unsigned char *key);
-WirelessError WirelessAssociate(WirelessRef ref, int type, CFDataRef ssid,
-                               CFStringRef key);
-WirelessError WirelessAssociate2(WirelessRef ref, CFDictionaryRef scan_res,
-                                CFStringRef key);
-WirelessError WirelessDisassociate(WirelessRef ref);
-
-/*
- * Get a copy of scan results for the given SSID
- * The returned dictionary includes following entries:
- * beaconInterval: CFNumber(kCFNumberSInt32Type)
- * SSID: CFData buffer of the SSID
- * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 = WPA2
- * name: Name of the network (SSID string)
- * BSSID: CFData buffer of the BSSID
- * channel: CFNumber(kCFNumberSInt32Type)
- * signal: CFNumber(kCFNumberSInt32Type)
- * appleIE: CFData
- * WPSNOPINRequired: CFBoolean
- * noise: CFNumber(kCFNumberSInt32Type)
- * capability: CFNumber(kCFNumberSInt32Type)
- * uniCipher: CFArray of CFNumber(kCFNumberSInt32Type)
- * appleIE_Version: CFNumber(kCFNumberSInt32Type)
- * appleIE_Robust: CFBoolean
- * WPSConfigured: CFBoolean
- * scanWasDirected: CFBoolean
- * appleIE_Product: CFNumber(kCFNumberSInt32Type)
- * authModes: CFArray of CFNumber(kCFNumberSInt32Type)
- * multiCipher: CFNumber(kCFNumberSInt32Type)
- */
-CFDictionaryRef WirelessSafeDirectedScanCopy(WirelessRef ref, CFDataRef ssid);
-
-/*
- * Get information about the current association
- * The returned dictionary includes following entries:
- * keyData: CFData buffer of the key (e.g., 32-octet PSK)
- * multiCipher: CFNumber(kCFNumberSInt32Type); 0 = none, 5 = CCMP?
- * channel: CFNumber(kCFNumberSInt32Type)
- * isIBSS: CFBoolean
- * authMode: CFNumber(kCFNumberSInt32Type); 2 = WPA-Personal; 3 = open,
- *     129 = WPA2-Enterprise
- * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 == WPA2
- * SSID: CFData buffer of the SSID
- * cipherMode: CFNumber(kCFNumberSInt32Type); 0 = none, 4 = CCMP?
- */
-CFDictionaryRef WirelessGetAssociationInfo(WirelessRef ref);
-
-WirelessError WirelessConfigure(WirelessRef ref);
-
-/*
- * Get ASP information
- * The returned dictionary includes following entries:
- * Version: version number (e.g., 3.0)
- * Channel: channel (e.g., 1)
- * Vendor: vendor (e.g., 2)
- */
-CFDictionaryRef WirelessGetInfoASP(void);
-
-/*
- * Get a copy of the interface dictionary
- * The returned dictionary has a key,value pairs for wireless interfaces.
- * The key is the interface name and the value is the driver identifier, e.g.,
- * en1: com.apple.driver.AirPort.Atheros
- */
-CFDictionaryRef WirelessCopyInterfaceDict(void);
-
-#endif /* APPLE80211_H */
diff --git a/src/drivers/MobileApple80211.c b/src/drivers/MobileApple80211.c
deleted file mode 100644 (file)
index ce004fe..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-#include "includes.h"
-#include <dlfcn.h>
-
-#include "common.h"
-
-#include <CoreFoundation/CoreFoundation.h>
-#include "MobileApple80211.h"
-
-/*
- * Code for dynamically loading Apple80211 functions from Aeropuerto to avoid
- * having to link with full Preferences.framework.
- */
-
-static void *aeropuerto = NULL;
-
-
-int _Apple80211Initialized(void)
-{
-       return aeropuerto ? 1 : 0;
-}
-
-
-static int (*__Apple80211Open)(Apple80211Ref *ctx) = NULL;
-
-int Apple80211Open(Apple80211Ref *ctx)
-{
-       return __Apple80211Open(ctx);
-}
-
-
-static int (*__Apple80211Close)(Apple80211Ref ctx) = NULL;
-
-int Apple80211Close(Apple80211Ref ctx)
-{
-       return __Apple80211Close(ctx);
-}
-
-
-static int (*__Apple80211GetIfListCopy)(Apple80211Ref handle, CFArrayRef *list)
-       = NULL;
-
-int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list)
-{
-       return __Apple80211GetIfListCopy(handle, list);
-}
-
-
-static int (*__Apple80211BindToInterface)(Apple80211Ref handle,
-                                         CFStringRef interface) = NULL;
-
-int Apple80211BindToInterface(Apple80211Ref handle,
-                             CFStringRef interface)
-{
-       return __Apple80211BindToInterface(handle, interface);
-}
-
-
-static int (*__Apple80211GetInterfaceNameCopy)(Apple80211Ref handle,
-                                              CFStringRef *name) = NULL;
-
-int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
-                                  CFStringRef *name)
-{
-       return __Apple80211GetInterfaceNameCopy(handle, name);
-}
-
-
-static int (*__Apple80211GetInfoCopy)(Apple80211Ref handle,
-                                     CFDictionaryRef *info) = NULL;
-
-int Apple80211GetInfoCopy(Apple80211Ref handle,
-                         CFDictionaryRef *info)
-{
-       return __Apple80211GetInfoCopy(handle, info);
-}
-
-
-static int (*__Apple80211GetPower)(Apple80211Ref handle, char *pwr) = NULL;
-
-int Apple80211GetPower(Apple80211Ref handle, char *pwr)
-{
-       return __Apple80211GetPower(handle, pwr);
-}
-
-
-static int (*__Apple80211SetPower)(Apple80211Ref handle, char pwr) = NULL;
-
-int Apple80211SetPower(Apple80211Ref handle, char pwr)
-{
-       return __Apple80211SetPower(handle, pwr);
-}
-
-
-static int (*__Apple80211Scan)(Apple80211Ref handle, CFArrayRef *list,
-                              CFDictionaryRef parameters) = NULL;
-
-int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
-                  CFDictionaryRef parameters)
-{
-       return __Apple80211Scan(handle, list, parameters);
-}
-
-
-static int (*__Apple80211Associate)(Apple80211Ref handle, CFDictionaryRef bss,
-                                   CFStringRef password) = NULL;
-
-int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
-                       CFStringRef password)
-{
-       return __Apple80211Associate(handle, bss, password);
-}
-
-
-static int (*__Apple80211AssociateAndCopyInfo)(Apple80211Ref handle,
-                                              CFDictionaryRef bss,
-                                              CFStringRef password,
-                                              CFDictionaryRef *info) =
-       NULL;
-
-int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
-                                  CFStringRef password, CFDictionaryRef *info)
-{
-       return __Apple80211AssociateAndCopyInfo(handle, bss, password, info);
-}
-
-
-static int (*__Apple80211CopyValue)(Apple80211Ref handle, int field,
-                                   CFDictionaryRef arg2, void *value) = NULL;
-
-int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
-                       void *value)
-{
-       return __Apple80211CopyValue(handle, field, arg2, value);
-}
-
-
-#define DLSYM(s) \
-do { \
-       __ ## s = dlsym(aeropuerto, #s); \
-       if (__ ## s == NULL) { \
-               wpa_printf(MSG_ERROR, "MobileApple80211: Could not resolve " \
-                          "symbol '" #s "' (%s)", dlerror()); \
-               err = 1; \
-       } \
-} while (0)
-
-
-__attribute__ ((constructor))
-void _Apple80211_constructor(void)
-{
-       const char *fname = "/System/Library/SystemConfiguration/"
-               "Aeropuerto.bundle/Aeropuerto";
-       int err = 0;
-
-       aeropuerto = dlopen(fname, RTLD_LAZY);
-       if (!aeropuerto) {
-               wpa_printf(MSG_ERROR, "MobileApple80211: Failed to open %s "
-                          "for symbols", fname);
-               return;
-       }
-
-       DLSYM(Apple80211Open);
-       DLSYM(Apple80211Close);
-       DLSYM(Apple80211GetIfListCopy);
-       DLSYM(Apple80211BindToInterface);
-       DLSYM(Apple80211GetInterfaceNameCopy);
-       DLSYM(Apple80211GetInfoCopy);
-       DLSYM(Apple80211GetPower);
-       DLSYM(Apple80211SetPower);
-       DLSYM(Apple80211Scan);
-       DLSYM(Apple80211Associate);
-       DLSYM(Apple80211AssociateAndCopyInfo);
-       DLSYM(Apple80211CopyValue);
-
-       if (err) {
-               dlclose(aeropuerto);
-               aeropuerto = NULL;
-       }
-}
-
-
-__attribute__ ((destructor))
-void _Apple80211_destructor(void)
-{
-       if (aeropuerto) {
-               dlclose(aeropuerto);
-               aeropuerto = NULL;
-       }
-}
diff --git a/src/drivers/MobileApple80211.h b/src/drivers/MobileApple80211.h
deleted file mode 100644 (file)
index 64d439d..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef MOBILEAPPLE80211_H
-#define MOBILEAPPLE80211_H
-
-/*
- * MobileApple80211 interface for iPhone/iPod touch
- * These functions are available from Aeropuerto.
- */
-
-struct Apple80211;
-typedef struct Apple80211 *Apple80211Ref;
-
-int Apple80211Open(Apple80211Ref *ctx);
-int Apple80211Close(Apple80211Ref ctx);
-int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list);
-int Apple80211BindToInterface(Apple80211Ref handle,
-                             CFStringRef interface);
-int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
-                                  CFStringRef *name);
-int Apple80211GetInfoCopy(Apple80211Ref handle,
-                         CFDictionaryRef *info);
-int Apple80211GetPower(Apple80211Ref handle, char *pwr);
-int Apple80211SetPower(Apple80211Ref handle, char pwr);
-
-/* parameters can be NULL; returns scan results in CFArrayRef *list;
- * caller will need to free with CFRelease() */
-int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
-                  CFDictionaryRef parameters);
-
-int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
-                       CFStringRef password);
-int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
-                                  CFStringRef password,
-                                  CFDictionaryRef *info);
-
-enum {
-       APPLE80211_VALUE_SSID = 1,
-       APPLE80211_VALUE_BSSID = 9
-};
-
-int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
-                       void *value);
-
-#endif /* MOBILEAPPLE80211_H */
diff --git a/src/drivers/android_drv.h b/src/drivers/android_drv.h
new file mode 100644 (file)
index 0000000..5906527
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Android driver interface
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ */
+
+#ifndef ANDROID_DRV_H
+#define ANDROID_DRV_H
+
+#define WPA_EVENT_DRIVER_STATE "CTRL-EVENT-DRIVER-STATE "
+
+#define MAX_SSID_LEN 32
+
+#define MAX_DRV_CMD_SIZE               248
+#define DRV_NUMBER_SEQUENTIAL_ERRORS   4
+
+#define WEXT_PNOSETUP_HEADER           "PNOSETUP "
+#define WEXT_PNOSETUP_HEADER_SIZE      9
+#define WEXT_PNO_TLV_PREFIX            'S'
+#define WEXT_PNO_TLV_VERSION           '1'
+#define WEXT_PNO_TLV_SUBVERSION                '2'
+#define WEXT_PNO_TLV_RESERVED          '0'
+#define WEXT_PNO_VERSION_SIZE          4
+#define WEXT_PNO_AMOUNT                        16
+#define WEXT_PNO_SSID_SECTION          'S'
+/* SSID header size is SSID section type above + SSID length */
+#define WEXT_PNO_SSID_HEADER_SIZE      2
+#define WEXT_PNO_SCAN_INTERVAL_SECTION 'T'
+#define WEXT_PNO_SCAN_INTERVAL_LENGTH  2
+#define WEXT_PNO_SCAN_INTERVAL         30
+/* Scan interval size is scan interval section type + scan interval length
+ * above */
+#define WEXT_PNO_SCAN_INTERVAL_SIZE    (1 + WEXT_PNO_SCAN_INTERVAL_LENGTH)
+#define WEXT_PNO_REPEAT_SECTION                'R'
+#define WEXT_PNO_REPEAT_LENGTH         1
+#define WEXT_PNO_REPEAT                        4
+/* Repeat section size is Repeat section type + Repeat value length above */
+#define WEXT_PNO_REPEAT_SIZE           (1 + WEXT_PNO_REPEAT_LENGTH)
+#define WEXT_PNO_MAX_REPEAT_SECTION    'M'
+#define WEXT_PNO_MAX_REPEAT_LENGTH     1
+#define WEXT_PNO_MAX_REPEAT            3
+/* Max Repeat section size is Max Repeat section type + Max Repeat value length
+ * above */
+#define WEXT_PNO_MAX_REPEAT_SIZE       (1 + WEXT_PNO_MAX_REPEAT_LENGTH)
+/* This corresponds to the size of all sections expect SSIDs */
+#define WEXT_PNO_NONSSID_SECTIONS_SIZE \
+(WEXT_PNO_SCAN_INTERVAL_SIZE + WEXT_PNO_REPEAT_SIZE + WEXT_PNO_MAX_REPEAT_SIZE)
+/* PNO Max command size is total of header, version, ssid and other sections +
+ * Null termination */
+#define WEXT_PNO_MAX_COMMAND_SIZE \
+       (WEXT_PNOSETUP_HEADER_SIZE + WEXT_PNO_VERSION_SIZE \
+        + WEXT_PNO_AMOUNT * (WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN) \
+        + WEXT_PNO_NONSSID_SECTIONS_SIZE + 1)
+
+#endif /* ANDROID_DRV_H */
index fa49da4..53d1c25 100644 (file)
@@ -31,6 +31,9 @@
 #define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002
 #define HOSTAPD_CHAN_NO_IBSS 0x00000004
 #define HOSTAPD_CHAN_RADAR 0x00000008
+#define HOSTAPD_CHAN_HT40PLUS 0x00000010
+#define HOSTAPD_CHAN_HT40MINUS 0x00000020
+#define HOSTAPD_CHAN_HT40 0x00000040
 
 /**
  * struct hostapd_channel_data - Channel information
@@ -57,6 +60,8 @@ struct hostapd_channel_data {
        u8 max_tx_power;
 };
 
+#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
+
 /**
  * struct hostapd_hw_modes - Supported hardware mode information
  */
@@ -100,6 +105,8 @@ struct hostapd_hw_modes {
         * a_mpdu_params - A-MPDU (IEEE 802.11n) parameters
         */
        u8 a_mpdu_params;
+
+       unsigned int flags; /* HOSTAPD_MODE_FLAG_* */
 };
 
 
@@ -192,7 +199,7 @@ struct wpa_interface_info {
        const char *drv_name;
 };
 
-#define WPAS_MAX_SCAN_SSIDS 4
+#define WPAS_MAX_SCAN_SSIDS 16
 
 /**
  * struct wpa_driver_scan_params - Scan parameters
@@ -261,6 +268,15 @@ struct wpa_driver_scan_params {
         * num_filter_ssids - Number of entries in filter_ssids array
         */
        size_t num_filter_ssids;
+
+       /**
+        * p2p_probe - Used to disable CCK (802.11b) rates for P2P probes
+        *
+        * When set, the driver is expected to remove rates 1, 2, 5.5, and 11
+        * Mbps from the support rates element(s) in the Probe Request frames
+        * and not to transmit the frames at any of those rates.
+        */
+       u8 p2p_probe;
 };
 
 /**
@@ -279,6 +295,19 @@ struct wpa_driver_auth_params {
        size_t wep_key_len[4];
        int wep_tx_keyidx;
        int local_state_change;
+
+       /**
+        * p2p - Whether this connection is a P2P group
+        */
+       int p2p;
+
+};
+
+enum wps_mode {
+       WPS_MODE_NONE /* no WPS provisioning being used */,
+       WPS_MODE_OPEN /* WPS provisioning with AP that is in open mode */,
+       WPS_MODE_PRIVACY /* WPS provisioning with AP that is using protection
+                         */
 };
 
 /**
@@ -335,6 +364,11 @@ struct wpa_driver_associate_params {
        size_t wpa_ie_len;
 
        /**
+        * wpa_proto - Bitfield of WPA_PROTO_* values to indicate WPA/WPA2
+        */
+       unsigned int wpa_proto;
+
+       /**
         * pairwise_suite - Selected pairwise cipher suite
         *
         * This is usually ignored if @wpa_ie is used.
@@ -460,6 +494,205 @@ struct wpa_driver_associate_params {
         * association.
         */
        const u8 *prev_bssid;
+
+       /**
+        * wps - WPS mode
+        *
+        * If the driver needs to do special configuration for WPS association,
+        * this variable provides more information on what type of association
+        * is being requested. Most drivers should not need ot use this.
+        */
+       enum wps_mode wps;
+
+       /**
+        * p2p - Whether this connection is a P2P group
+        */
+       int p2p;
+
+       /**
+        * uapsd - UAPSD parameters for the network
+        * -1 = do not change defaults
+        * AP mode: 1 = enabled, 0 = disabled
+        * STA mode: bits 0..3 UAPSD enabled for VO,VI,BK,BE
+        */
+       int uapsd;
+};
+
+enum hide_ssid {
+       NO_SSID_HIDING,
+       HIDDEN_SSID_ZERO_LEN,
+       HIDDEN_SSID_ZERO_CONTENTS
+};
+
+struct wpa_driver_ap_params {
+       /**
+        * head - Beacon head from IEEE 802.11 header to IEs before TIM IE
+        */
+       const u8 *head;
+
+       /**
+        * head_len - Length of the head buffer in octets
+        */
+       size_t head_len;
+
+       /**
+        * tail - Beacon tail following TIM IE
+        */
+       const u8 *tail;
+
+       /**
+        * tail_len - Length of the tail buffer in octets
+        */
+       size_t tail_len;
+
+       /**
+        * dtim_period - DTIM period
+        */
+       int dtim_period;
+
+       /**
+        * beacon_int - Beacon interval
+        */
+       int beacon_int;
+
+       /**
+        * basic_rates: -1 terminated array of basic rates in 100 kbps
+        *
+        * This parameter can be used to set a specific basic rate set for the
+        * BSS. If %NULL, default basic rate set is used.
+        */
+       int *basic_rates;
+
+       /**
+        * proberesp - Probe Response template
+        *
+        * This is used by drivers that reply to Probe Requests internally in
+        * AP mode and require the full Probe Response template.
+        */
+       const u8 *proberesp;
+
+       /**
+        * proberesp_len - Length of the proberesp buffer in octets
+        */
+       size_t proberesp_len;
+
+       /**
+        * ssid - The SSID to use in Beacon/Probe Response frames
+        */
+       const u8 *ssid;
+
+       /**
+        * ssid_len - Length of the SSID (1..32)
+        */
+       size_t ssid_len;
+
+       /**
+        * hide_ssid - Whether to hide the SSID
+        */
+       enum hide_ssid hide_ssid;
+
+       /**
+        * pairwise_ciphers - WPA_CIPHER_* bitfield
+        */
+       unsigned int pairwise_ciphers;
+
+       /**
+        * group_cipher - WPA_CIPHER_*
+        */
+       unsigned int group_cipher;
+
+       /**
+        * key_mgmt_suites - WPA_KEY_MGMT_* bitfield
+        */
+       unsigned int key_mgmt_suites;
+
+       /**
+        * auth_algs - WPA_AUTH_ALG_* bitfield
+        */
+       unsigned int auth_algs;
+
+       /**
+        * wpa_version - WPA_PROTO_* bitfield
+        */
+       unsigned int wpa_version;
+
+       /**
+        * privacy - Whether privacy is used in the BSS
+        */
+       int privacy;
+
+       /**
+        * beacon_ies - WPS/P2P IE(s) for Beacon frames
+        *
+        * This is used to add IEs like WPS IE and P2P IE by drivers that do
+        * not use the full Beacon template.
+        */
+       const struct wpabuf *beacon_ies;
+
+       /**
+        * proberesp_ies - P2P/WPS IE(s) for Probe Response frames
+        *
+        * This is used to add IEs like WPS IE and P2P IE by drivers that
+        * reply to Probe Request frames internally.
+        */
+       const struct wpabuf *proberesp_ies;
+
+       /**
+        * assocresp_ies - WPS IE(s) for (Re)Association Response frames
+        *
+        * This is used to add IEs like WPS IE by drivers that reply to
+        * (Re)Association Request frames internally.
+        */
+       const struct wpabuf *assocresp_ies;
+
+       /**
+        * isolate - Whether to isolate frames between associated stations
+        *
+        * If this is non-zero, the AP is requested to disable forwarding of
+        * frames between associated stations.
+        */
+       int isolate;
+
+       /**
+        * cts_protect - Whether CTS protection is enabled
+        */
+       int cts_protect;
+
+       /**
+        * preamble - Whether short preamble is enabled
+        */
+       int preamble;
+
+       /**
+        * short_slot_time - Whether short slot time is enabled
+        *
+        * 0 = short slot time disable, 1 = short slot time enabled, -1 = do
+        * not set (e.g., when 802.11g mode is not in use)
+        */
+       int short_slot_time;
+
+       /**
+        * ht_opmode - HT operation mode or -1 if HT not in use
+        */
+       int ht_opmode;
+
+       /**
+        * interworking - Whether Interworking is enabled
+        */
+       int interworking;
+
+       /**
+        * hessid - Homogeneous ESS identifier or %NULL if not set
+        */
+       const u8 *hessid;
+
+       /**
+        * access_network_type - Access Network Type (0..15)
+        *
+        * This is used for filtering Probe Request frames when Interworking is
+        * enabled.
+        */
+       u8 access_network_type;
 };
 
 /**
@@ -490,7 +723,7 @@ struct wpa_driver_capa {
 #define WPA_DRIVER_FLAGS_DRIVER_IE     0x00000001
 /* Driver needs static WEP key setup after association command */
 #define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002
-#define WPA_DRIVER_FLAGS_USER_SPACE_MLME 0x00000004
+/* unused: 0x00000004 */
 /* Driver takes care of RSN 4-way handshake internally; PMK is configured with
  * struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */
 #define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008
@@ -502,14 +735,78 @@ struct wpa_driver_capa {
 #define WPA_DRIVER_FLAGS_AP            0x00000040
 /* Driver needs static WEP key setup after association has been completed */
 #define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE     0x00000080
+/* Driver takes care of P2P management operations */
+#define WPA_DRIVER_FLAGS_P2P_MGMT      0x00000100
+/* Driver supports concurrent P2P operations */
+#define WPA_DRIVER_FLAGS_P2P_CONCURRENT        0x00000200
+/*
+ * Driver uses the initial interface as a dedicated management interface, i.e.,
+ * it cannot be used for P2P group operations or non-P2P purposes.
+ */
+#define WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE       0x00000400
+/* This interface is P2P capable (P2P Device, GO, or P2P Client */
+#define WPA_DRIVER_FLAGS_P2P_CAPABLE   0x00000800
+/* Driver supports concurrent operations on multiple channels */
+#define WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT      0x00001000
+/*
+ * Driver uses the initial interface for P2P management interface and non-P2P
+ * purposes (e.g., connect to infra AP), but this interface cannot be used for
+ * P2P group operations.
+ */
+#define WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P          0x00002000
+/*
+ * Driver is known to use sane error codes, i.e., when it indicates that
+ * something (e.g., association) fails, there was indeed a failure and the
+ * operation does not end up getting completed successfully later.
+ */
+#define WPA_DRIVER_FLAGS_SANE_ERROR_CODES              0x00004000
+/* Driver supports off-channel TX */
+#define WPA_DRIVER_FLAGS_OFFCHANNEL_TX                 0x00008000
+/* Driver indicates TX status events for EAPOL Data frames */
+#define WPA_DRIVER_FLAGS_EAPOL_TX_STATUS               0x00010000
+/* Driver indicates TX status events for Deauth/Disassoc frames */
+#define WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS              0x00020000
+/* Driver supports roaming (BSS selection) in firmware */
+#define WPA_DRIVER_FLAGS_BSS_SELECTION                 0x00040000
+/* Driver supports operating as a TDLS peer */
+#define WPA_DRIVER_FLAGS_TDLS_SUPPORT                  0x00080000
+/* Driver requires external TDLS setup/teardown/discovery */
+#define WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP           0x00100000
+/* Driver indicates support for Probe Response offloading in AP mode */
+#define WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD            0x00200000
+/* Driver supports U-APSD in AP mode */
+#define WPA_DRIVER_FLAGS_AP_UAPSD                      0x00400000
        unsigned int flags;
 
        int max_scan_ssids;
+       int max_sched_scan_ssids;
+       int sched_scan_supported;
+       int max_match_sets;
 
        /**
         * max_remain_on_chan - Maximum remain-on-channel duration in msec
         */
        unsigned int max_remain_on_chan;
+
+       /**
+        * max_stations - Maximum number of associated stations the driver
+        * supports in AP mode
+        */
+       unsigned int max_stations;
+
+       /**
+        * probe_resp_offloads - Bitmap of supported protocols by the driver
+        * for Probe Response offloading.
+        */
+/* Driver Probe Response offloading support for WPS ver. 1 */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS              0x00000001
+/* Driver Probe Response offloading support for WPS ver. 2 */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2             0x00000002
+/* Driver Probe Response offloading support for P2P */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P              0x00000004
+/* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING     0x00000008
+       unsigned int probe_resp_offloads;
 };
 
 
@@ -535,6 +832,9 @@ struct hostapd_sta_add_params {
        size_t supp_rates_len;
        u16 listen_interval;
        const struct ieee80211_ht_capabilities *ht_capabilities;
+       u32 flags; /* bitmask of WPA_STA_* flags */
+       int set; /* Set STA parameters instead of add */
+       u8 qosinfo;
 };
 
 struct hostapd_freq_params {
@@ -567,9 +867,26 @@ enum wpa_driver_if_type {
         * This interface has its own address and Beacon frame.
         */
        WPA_IF_AP_BSS,
+
+       /**
+        * WPA_IF_P2P_GO - P2P Group Owner
+        */
+       WPA_IF_P2P_GO,
+
+       /**
+        * WPA_IF_P2P_CLIENT - P2P Client
+        */
+       WPA_IF_P2P_CLIENT,
+
+       /**
+        * WPA_IF_P2P_GROUP - P2P Group interface (will become either
+        * WPA_IF_P2P_GO or WPA_IF_P2P_CLIENT, but the role is not yet known)
+        */
+       WPA_IF_P2P_GROUP
 };
 
 struct wpa_init_params {
+       void *global_priv;
        const u8 *bssid;
        const char *ifname;
        const u8 *ssid;
@@ -595,12 +912,46 @@ struct wpa_bss_params {
        int wpa_pairwise;
        int wpa_key_mgmt;
        int rsn_preauth;
+       enum mfp_options ieee80211w;
 };
 
 #define WPA_STA_AUTHORIZED BIT(0)
 #define WPA_STA_WMM BIT(1)
 #define WPA_STA_SHORT_PREAMBLE BIT(2)
 #define WPA_STA_MFP BIT(3)
+#define WPA_STA_TDLS_PEER BIT(4)
+
+/**
+ * struct p2p_params - P2P parameters for driver-based P2P management
+ */
+struct p2p_params {
+       const char *dev_name;
+       u8 pri_dev_type[8];
+#define DRV_MAX_SEC_DEV_TYPES 5
+       u8 sec_dev_type[DRV_MAX_SEC_DEV_TYPES][8];
+       size_t num_sec_dev_types;
+};
+
+enum tdls_oper {
+       TDLS_DISCOVERY_REQ,
+       TDLS_SETUP,
+       TDLS_TEARDOWN,
+       TDLS_ENABLE_LINK,
+       TDLS_DISABLE_LINK,
+       TDLS_ENABLE,
+       TDLS_DISABLE
+};
+
+/**
+ * struct wpa_signal_info - Information about channel signal quality
+ */
+struct wpa_signal_info {
+       u32 frequency;
+       int above_threshold;
+       int current_signal;
+       int current_noise;
+       int current_txrate;
+};
 
 /**
  * struct wpa_driver_ops - Driver interface API definition
@@ -652,8 +1003,12 @@ struct wpa_driver_ops {
         * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
         *      %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK);
         *      %WPA_ALG_NONE clears the key.
-        * @addr: address of the peer STA or ff:ff:ff:ff:ff:ff for
-        *      broadcast/default keys
+        * @addr: Address of the peer STA (BSSID of the current AP when setting
+        *      pairwise key in station mode), ff:ff:ff:ff:ff:ff for
+        *      broadcast keys, %NULL for default keys that are used both for
+        *      broadcast and unicast; when clearing keys, %NULL is used to
+        *      indicate that both the broadcast-only and default key of the
+        *      specified key index is to be cleared
         * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for
         *      IGTK
         * @set_tx: configure this key as the default Tx key (only used when
@@ -661,7 +1016,7 @@ struct wpa_driver_ops {
         * @seq: sequence number/packet number, seq_len octets, the next
         *      packet number to be used for in replay protection; configured
         *      for Rx keys (in most cases, this is only used with broadcast
-        *      keys and set to zero for unicast keys)
+        *      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
         * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
@@ -684,7 +1039,7 @@ struct wpa_driver_ops {
         * Please note that TKIP keys include separate TX and RX MIC keys and
         * some drivers may expect them in different order than wpa_supplicant
         * is using. If the TX/RX keys are swapped, all TKIP encrypted packets
-        * will tricker Michael MIC errors. This can be fixed by changing the
+        * will trigger Michael MIC errors. This can be fixed by changing the
         * order of MIC keys by swapping te bytes 16..23 and 24..31 of the key
         * in driver_*.c set_key() implementation, see driver_ndis.c for an
         * example on how this can be done.
@@ -951,91 +1306,21 @@ struct wpa_driver_ops {
         * flags: Variable for returning hardware feature flags
         * Returns: Pointer to allocated hardware data on success or %NULL on
         * failure. Caller is responsible for freeing this.
-        *
-        * This function is only needed for drivers that export MLME
-        * (management frame processing) to %wpa_supplicant or hostapd.
         */
        struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv,
                                                         u16 *num_modes,
                                                         u16 *flags);
 
        /**
-        * set_channel - Set channel
-        * @priv: Private driver interface data
-        * @phymode: HOSTAPD_MODE_IEEE80211B, ..
-        * @chan: IEEE 802.11 channel number
-        * @freq: Frequency of the channel in MHz
-        * Returns: 0 on success, -1 on failure
-        *
-        * This function is only needed for drivers that export MLME
-        * (management frame processing) to wpa_supplicant.
-        */
-       int (*set_channel)(void *priv, enum hostapd_hw_mode phymode, int chan,
-                          int freq);
-
-       /**
-        * set_ssid - Set SSID
-        * @priv: Private driver interface data
-        * @ssid: SSID
-        * @ssid_len: SSID length
-        * Returns: 0 on success, -1 on failure
-        *
-        * This function is only needed for drivers that export MLME
-        * (management frame processing) to wpa_supplicant.
-        */
-       int (*set_ssid)(void *priv, const u8 *ssid, size_t ssid_len);
-
-       /**
-        * set_bssid - Set BSSID
-        * @priv: Private driver interface data
-        * @bssid: BSSID
-        * Returns: 0 on success, -1 on failure
-        *
-        * This function is only needed for drivers that export MLME
-        * (management frame processing) to wpa_supplicant.
-        */
-       int (*set_bssid)(void *priv, const u8 *bssid);
-
-       /**
         * send_mlme - Send management frame from MLME
         * @priv: Private driver interface data
         * @data: IEEE 802.11 management frame with IEEE 802.11 header
         * @data_len: Size of the management frame
+        * @noack: Do not wait for this frame to be acked (disable retries)
         * Returns: 0 on success, -1 on failure
-        *
-        * This function is only needed for drivers that export MLME
-        * (management frame processing) to wpa_supplicant.
-        */
-       int (*send_mlme)(void *priv, const u8 *data, size_t data_len);
-
-       /**
-        * mlme_add_sta - Add a STA entry into the driver/netstack
-        * @priv: Private driver interface data
-        * @addr: MAC address of the STA (e.g., BSSID of the AP)
-        * @supp_rates: Supported rate set (from (Re)AssocResp); in IEEE 802.11
-        * format (one octet per rate, 1 = 0.5 Mbps)
-        * @supp_rates_len: Number of entries in supp_rates
-        * Returns: 0 on success, -1 on failure
-        *
-        * This function is only needed for drivers that export MLME
-        * (management frame processing) to wpa_supplicant. When the MLME code
-        * completes association with an AP, this function is called to
-        * configure the driver/netstack with a STA entry for data frame
-        * processing (TX rate control, encryption/decryption).
-        */
-       int (*mlme_add_sta)(void *priv, const u8 *addr, const u8 *supp_rates,
-                           size_t supp_rates_len);
-
-       /**
-        * mlme_remove_sta - Remove a STA entry from the driver/netstack
-        * @priv: Private driver interface data
-        * @addr: MAC address of the STA (e.g., BSSID of the AP)
-        * Returns: 0 on success, -1 on failure
-        *
-        * This function is only needed for drivers that export MLME
-        * (management frame processing) to wpa_supplicant.
         */
-       int (*mlme_remove_sta)(void *priv, const u8 *addr);
+       int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
+                        int noack);
 
        /**
         * update_ft_ies - Update FT (IEEE 802.11r) IEs
@@ -1164,24 +1449,25 @@ struct wpa_driver_ops {
                            struct wpa_driver_auth_params *params);
 
        /**
-        * set_beacon - Set Beacon frame template
+        * set_ap - Set Beacon and Probe Response information for AP mode
         * @priv: Private driver interface data
-        * @head: Beacon head from IEEE 802.11 header to IEs before TIM IE
-        * @head_len: Length of the head buffer in octets
-        * @tail: Beacon tail following TIM IE
-        * @tail_len: Length of the tail buffer in octets
-        * @dtim_period: DTIM period
-        * @beacon_int: Beacon interval
-        * Returns: 0 on success, -1 on failure
+        * @params: Parameters to use in AP mode
         *
-        * This function is used to configure Beacon template for the driver in
+        * This function is used to configure Beacon template and/or extra IEs
+        * to add for Beacon and Probe Response frames for the driver in
         * AP mode. The driver is responsible for building the full Beacon
         * frame by concatenating the head part with TIM IE generated by the
-        * driver/firmware and finishing with the tail part.
+        * driver/firmware and finishing with the tail part. Depending on the
+        * driver architectue, this can be done either by using the full
+        * template or the set of additional IEs (e.g., WPS and P2P IE).
+        * Similarly, Probe Response processing depends on the driver design.
+        * If the driver (or firmware) takes care of replying to Probe Request
+        * frames, the extra IEs provided here needs to be added to the Probe
+        * Response frames.
+        *
+        * Returns: 0 on success, -1 on failure
         */
-       int (*set_beacon)(void *priv, const u8 *head, size_t head_len,
-                         const u8 *tail, size_t tail_len, int dtim_period,
-                         int beacon_int);
+       int (*set_ap)(void *priv, struct wpa_driver_ap_params *params);
 
        /**
         * hapd_init - Initialize driver interface (hostapd only)
@@ -1190,7 +1476,7 @@ struct wpa_driver_ops {
         * Returns: Pointer to private data, %NULL on failure
         *
         * This function is used instead of init() or init2() when the driver
-        * wrapper is used withh hostapd.
+        * wrapper is used with hostapd.
         */
        void * (*hapd_init)(struct hostapd_data *hapd,
                            struct wpa_init_params *params);
@@ -1210,8 +1496,10 @@ struct wpa_driver_ops {
         * This is an optional function to configure the kernel driver to
         * enable/disable IEEE 802.1X support and set WPA/WPA2 parameters. This
         * can be left undefined (set to %NULL) if IEEE 802.1X support is
-        * always enabled and the driver uses set_beacon() to set WPA/RSN IE
+        * always enabled and the driver uses set_ap() to set WPA/RSN IE
         * for Beacon frames.
+        *
+        * DEPRECATED - use set_ap() instead
         */
        int (*set_ieee8021x)(void *priv, struct wpa_bss_params *params);
 
@@ -1223,7 +1511,9 @@ struct wpa_driver_ops {
         *
         * This is an optional function to configure privacy field in the
         * kernel driver for Beacon frames. This can be left undefined (set to
-        * %NULL) if the driver uses the Beacon template from set_beacon().
+        * %NULL) if the driver uses the Beacon template from set_ap().
+        *
+        * DEPRECATED - use set_ap() instead
         */
        int (*set_privacy)(void *priv, int enabled);
 
@@ -1265,7 +1555,9 @@ struct wpa_driver_ops {
         * This is an optional function to add information elements in the
         * kernel driver for Beacon and Probe Response frames. This can be left
         * undefined (set to %NULL) if the driver uses the Beacon template from
-        * set_beacon().
+        * set_ap().
+        *
+        * DEPRECATED - use set_ap() instead
         */
        int (*set_generic_elem)(void *priv, const u8 *elem, size_t elem_len);
 
@@ -1287,12 +1579,13 @@ struct wpa_driver_ops {
         * @data_len: Length of the EAPOL packet in octets
         * @encrypt: Whether the frame should be encrypted
         * @own_addr: Source MAC address
+        * @flags: WPA_STA_* flags for the destination station
         *
         * Returns: 0 on success, -1 on failure
         */
        int (*hapd_send_eapol)(void *priv, const u8 *addr, const u8 *data,
                               size_t data_len, int encrypt,
-                              const u8 *own_addr);
+                              const u8 *own_addr, u32 flags);
 
        /**
         * sta_deauth - Deauthenticate a station (AP only)
@@ -1338,8 +1631,7 @@ struct wpa_driver_ops {
         * Returns: Length of the SSID on success, -1 on failure
         *
         * This function need not be implemented if the driver uses Beacon
-        * template from set_beacon() and does not reply to Probe Request
-        * frames.
+        * template from set_ap() and does not reply to Probe Request frames.
         */
        int (*hapd_get_ssid)(void *priv, u8 *buf, int len);
 
@@ -1349,6 +1641,8 @@ struct wpa_driver_ops {
         * @buf: SSID
         * @len: Length of the SSID in octets
         * Returns: 0 on success, -1 on failure
+        *
+        * DEPRECATED - use set_ap() instead
         */
        int (*hapd_set_ssid)(void *priv, const u8 *buf, int len);
 
@@ -1372,6 +1666,9 @@ struct wpa_driver_ops {
         * This function is used to add a station entry to the driver once the
         * station has completed association. This is only used if the driver
         * does not take care of association processing.
+        *
+        * With TDLS, this function is also used to add or set (params->set 1)
+        * TDLS peer entries.
         */
        int (*sta_add)(void *priv, struct hostapd_sta_add_params *params);
 
@@ -1428,44 +1725,9 @@ struct wpa_driver_ops {
                             int total_flags, int flags_or, int flags_and);
 
        /**
-        * set_rate_sets - Set supported and basic rate sets (AP only)
-        * @priv: Private driver interface data
-        * @supp_rates: -1 terminated array of supported rates in 100 kbps
-        * @basic_rates: -1 terminated array of basic rates in 100 kbps
-        * @mode: hardware mode (HOSTAPD_MODE_*)
-        * Returns: 0 on success, -1 on failure
-        */
-       int (*set_rate_sets)(void *priv, int *supp_rates, int *basic_rates,
-                            int mode);
-
-       /**
-        * set_cts_protect - Set CTS protection mode (AP only)
-        * @priv: Private driver interface data
-        * @value: Whether CTS protection is enabled
-        * Returns: 0 on success, -1 on failure
-        */
-       int (*set_cts_protect)(void *priv, int value);
-
-       /**
-        * set_preamble - Set preamble mode (AP only)
-        * @priv: Private driver interface data
-        * @value: Whether short preamble is enabled
-        * Returns: 0 on success, -1 on failure
-        */
-       int (*set_preamble)(void *priv, int value);
-
-       /**
-        * set_short_slot_time - Set short slot time (AP only)
-        * @priv: Private driver interface data
-        * @value: Whether short slot time is enabled
-        * Returns: 0 on success, -1 on failure
-        */
-       int (*set_short_slot_time)(void *priv, int value);
-
-       /**
         * set_tx_queue_params - Set TX queue parameters
         * @priv: Private driver interface data
-        * @queue: Queue number
+        * @queue: Queue number (0 = VO, 1 = VI, 2 = BE, 3 = BK)
         * @aifs: AIFS
         * @cw_min: cwMin
         * @cw_max: cwMax
@@ -1475,17 +1737,6 @@ struct wpa_driver_ops {
                                   int cw_max, int burst_time);
 
        /**
-        * valid_bss_mask - Validate BSSID mask
-        * @priv: Private driver interface data
-        * @addr: Address
-        * @mask: Mask
-        * Returns: 0 if mask is valid, -1 if mask is not valid, 1 if mask can
-        * be used, but the main interface address must be the first address in
-        * the block if mask is applied
-        */
-       int (*valid_bss_mask)(void *priv, const u8 *addr, const u8 *mask);
-
-       /**
         * if_add - Add a virtual interface
         * @priv: Private driver interface data
         * @type: Interface type
@@ -1500,11 +1751,13 @@ struct wpa_driver_ops {
         * @if_addr: Buffer for returning the allocated interface address
         *      (this may differ from the requested addr if the driver cannot
         *      change interface address)
+        * @bridge: Bridge interface to use or %NULL if no bridge configured
         * Returns: 0 on success, -1 on failure
         */
        int (*if_add)(void *priv, enum wpa_driver_if_type type,
                      const char *ifname, const u8 *addr, void *bss_ctx,
-                     void **drv_priv, char *force_ifname, u8 *if_addr);
+                     void **drv_priv, char *force_ifname, u8 *if_addr,
+                     const char *bridge);
 
        /**
         * if_remove - Remove a virtual interface
@@ -1578,33 +1831,36 @@ struct wpa_driver_ops {
        int (*set_radius_acl_expire)(void *priv, const u8 *mac);
 
        /**
-        * set_ht_params - Set HT parameters (AP only)
-        * @priv: Private driver interface data
-        * @ht_capab: HT Capabilities IE
-        * @ht_capab_len: Length of ht_capab in octets
-        * @ht_oper: HT Operation IE
-        * @ht_oper_len: Length of ht_oper in octets
-        * Returns: 0 on success, -1 on failure
-        */
-       int (*set_ht_params)(void *priv,
-                            const u8 *ht_capab, size_t ht_capab_len,
-                            const u8 *ht_oper, size_t ht_oper_len);
-
-       /**
         * set_ap_wps_ie - Add WPS IE(s) into Beacon/Probe Response frames (AP)
         * @priv: Private driver interface data
         * @beacon: WPS IE(s) for Beacon frames or %NULL to remove extra IE(s)
         * @proberesp: WPS IE(s) for Probe Response frames or %NULL to remove
         *      extra IE(s)
+        * @assocresp: WPS IE(s) for (Re)Association Response frames or %NULL
+        *      to remove extra IE(s)
         * Returns: 0 on success, -1 on failure
         *
         * This is an optional function to add WPS IE in the kernel driver for
         * Beacon and Probe Response frames. This can be left undefined (set
-        * to %NULL) if the driver uses the Beacon template from set_beacon()
-        * and does not process Probe Request frames.
+        * to %NULL) if the driver uses the Beacon template from set_ap()
+        * and does not process Probe Request frames. If the driver takes care
+        * of (Re)Association frame processing, the assocresp buffer includes
+        * WPS IE(s) that need to be added to (Re)Association Response frames
+        * whenever a (Re)Association Request frame indicated use of WPS.
+        *
+        * This will also be used to add P2P IE(s) into Beacon/Probe Response
+        * frames when operating as a GO. The driver is responsible for adding
+        * timing related attributes (e.g., NoA) in addition to the IEs
+        * included here by appending them after these buffers. This call is
+        * also used to provide Probe Response IEs for P2P Listen state
+        * operations for drivers that generate the Probe Response frames
+        * internally.
+        *
+        * DEPRECATED - use set_ap() instead
         */
        int (*set_ap_wps_ie)(void *priv, const struct wpabuf *beacon,
-                            const struct wpabuf *proberesp);
+                            const struct wpabuf *proberesp,
+                            const struct wpabuf *assocresp);
 
        /**
         * set_supp_port - Set IEEE 802.1X Supplicant Port status
@@ -1620,31 +1876,52 @@ struct wpa_driver_ops {
         * @addr: MAC address of the associated station
         * @aid: Association ID
         * @val: 1 = bind to 4-address WDS; 0 = unbind
+        * @bridge_ifname: Bridge interface to use for the WDS station or %NULL
+        *      to indicate that bridge is not to be used
         * Returns: 0 on success, -1 on failure
         */
-       int (*set_wds_sta)(void *priv, const u8 *addr, int aid, int val);
+       int (*set_wds_sta)(void *priv, const u8 *addr, int aid, int val,
+                          const char *bridge_ifname);
 
        /**
         * send_action - Transmit an Action frame
         * @priv: Private driver interface data
         * @freq: Frequency (in MHz) of the channel
+        * @wait: Time to wait off-channel for a response (in ms), or zero
         * @dst: Destination MAC address (Address 1)
         * @src: Source MAC address (Address 2)
         * @bssid: BSSID (Address 3)
         * @data: Frame body
         * @data_len: data length in octets
+        @ @no_cck: Whether CCK rates must not be used to transmit this frame
         * Returns: 0 on success, -1 on failure
         *
         * This command can be used to request the driver to transmit an action
-        * frame to the specified destination. If a remain-on-channel duration
-        * is in progress, the frame is transmitted on that channel. Otherwise,
-        * the frame is transmitted on the current operational channel if in
-        * associated state in station mode or if operating as an AP. If none
-        * of these conditions is in effect, send_action() cannot be used.
+        * frame to the specified destination.
+        *
+        * If the %WPA_DRIVER_FLAGS_OFFCHANNEL_TX flag is set, the frame will
+        * be transmitted on the given channel and the device will wait for a
+        * response on that channel for the given wait time.
+        *
+        * If the flag is not set, the wait time will be ignored. In this case,
+        * if a remain-on-channel duration is in progress, the frame must be
+        * transmitted on that channel; alternatively the frame may be sent on
+        * the current operational channel (if in associated state in station
+        * mode or while operating as an AP.)
         */
-       int (*send_action)(void *priv, unsigned int freq,
+       int (*send_action)(void *priv, unsigned int freq, unsigned int wait,
                           const u8 *dst, const u8 *src, const u8 *bssid,
-                          const u8 *data, size_t data_len);
+                          const u8 *data, size_t data_len, int no_cck);
+
+       /**
+        * send_action_cancel_wait - Cancel action frame TX wait
+        * @priv: Private driver interface data
+        *
+        * This command cancels the wait time associated with sending an action
+        * frame. It is only available when %WPA_DRIVER_FLAGS_OFFCHANNEL_TX is
+        * set in the driver flags.
+        */
+       void (*send_action_cancel_wait)(void *priv);
 
        /**
         * remain_on_channel - Remain awake on a channel
@@ -1701,19 +1978,6 @@ struct wpa_driver_ops {
        int (*probe_req_report)(void *priv, int report);
 
        /**
-        * disable_11b_rates - Set whether IEEE 802.11b rates are used for TX
-        * @priv: Private driver interface data
-        * @disabled: Whether IEEE 802.11b rates are disabled
-        * Returns: 0 on success, -1 on failure (or if not supported)
-        *
-        * This command is used to disable IEEE 802.11b rates (1, 2, 5.5, and
-        * 11 Mbps) as TX rates for data and management frames. This can be
-        * used to optimize channel use when there is no need to support IEEE
-        * 802.11b-only devices.
-        */
-       int (*disable_11b_rates)(void *priv, int disabled);
-
-       /**
         * deinit_ap - Deinitialize AP mode
         * @priv: Private driver interface data
         * Returns: 0 on success, -1 on failure (or if not supported)
@@ -1765,26 +2029,480 @@ struct wpa_driver_ops {
         */
        int (*send_frame)(void *priv, const u8 *data, size_t data_len,
                          int encrypt);
-};
 
-
-/**
- * enum wpa_event_type - Event type for wpa_supplicant_event() calls
- */
-enum wpa_event_type {
        /**
-        * EVENT_ASSOC - Association completed
+        * shared_freq - Get operating frequency of shared interface(s)
+        * @priv: Private driver interface data
+        * Returns: Operating frequency in MHz, 0 if no shared operation in
+        * use, or -1 on failure
         *
-        * This event needs to be delivered when the driver completes IEEE
-        * 802.11 association or reassociation successfully.
-        * wpa_driver_ops::get_bssid() is expected to provide the current BSSID
-        * after this event has been generated. In addition, optional
-        * EVENT_ASSOCINFO may be generated just before EVENT_ASSOC to provide
-        * more information about the association. If the driver interface gets
-        * both of these events at the same time, it can also include the
-        * assoc_info data in EVENT_ASSOC call.
+        * This command can be used to request the current operating frequency
+        * of any virtual interface that shares the same radio to provide
+        * information for channel selection for other virtual interfaces.
         */
-       EVENT_ASSOC,
+       int (*shared_freq)(void *priv);
+
+       /**
+        * get_noa - Get current Notice of Absence attribute payload
+        * @priv: Private driver interface data
+        * @buf: Buffer for returning NoA
+        * @buf_len: Buffer length in octets
+        * Returns: Number of octets used in buf, 0 to indicate no NoA is being
+        * advertized, or -1 on failure
+        *
+        * This function is used to fetch the current Notice of Absence
+        * attribute value from GO.
+        */
+       int (*get_noa)(void *priv, u8 *buf, size_t buf_len);
+
+       /**
+        * set_noa - Set Notice of Absence parameters for GO (testing)
+        * @priv: Private driver interface data
+        * @count: Count
+        * @start: Start time in ms from next TBTT
+        * @duration: Duration in ms
+        * Returns: 0 on success or -1 on failure
+        *
+        * This function is used to set Notice of Absence parameters for GO. It
+        * is used only for testing. To disable NoA, all parameters are set to
+        * 0.
+        */
+       int (*set_noa)(void *priv, u8 count, int start, int duration);
+
+       /**
+        * set_p2p_powersave - Set P2P power save options
+        * @priv: Private driver interface data
+        * @legacy_ps: 0 = disable, 1 = enable, 2 = maximum PS, -1 = no change
+        * @opp_ps: 0 = disable, 1 = enable, -1 = no change
+        * @ctwindow: 0.. = change (msec), -1 = no change
+        * Returns: 0 on success or -1 on failure
+        */
+       int (*set_p2p_powersave)(void *priv, int legacy_ps, int opp_ps,
+                                int ctwindow);
+
+       /**
+        * ampdu - Enable/disable aggregation
+        * @priv: Private driver interface data
+        * @ampdu: 1/0 = enable/disable A-MPDU aggregation
+        * Returns: 0 on success or -1 on failure
+        */
+       int (*ampdu)(void *priv, int ampdu);
+
+       /**
+        * get_radio_name - Get physical radio name for the device
+        * @priv: Private driver interface data
+        * Returns: Radio name or %NULL if not known
+        *
+        * The returned data must not be modified by the caller. It is assumed
+        * that any interface that has the same radio name as another is
+        * sharing the same physical radio. This information can be used to
+        * share scan results etc. information between the virtual interfaces
+        * to speed up various operations.
+        */
+       const char * (*get_radio_name)(void *priv);
+
+       /**
+        * p2p_find - Start P2P Device Discovery
+        * @priv: Private driver interface data
+        * @timeout: Timeout for find operation in seconds or 0 for no timeout
+        * @type: Device Discovery type (enum p2p_discovery_type)
+        * Returns: 0 on success, -1 on failure
+        *
+        * This function is only used if the driver implements P2P management,
+        * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+        * struct wpa_driver_capa.
+        */
+       int (*p2p_find)(void *priv, unsigned int timeout, int type);
+
+       /**
+        * p2p_stop_find - Stop P2P Device Discovery
+        * @priv: Private driver interface data
+        * Returns: 0 on success, -1 on failure
+        *
+        * This function is only used if the driver implements P2P management,
+        * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+        * struct wpa_driver_capa.
+        */
+       int (*p2p_stop_find)(void *priv);
+
+       /**
+        * p2p_listen - Start P2P Listen state for specified duration
+        * @priv: Private driver interface data
+        * @timeout: Listen state duration in milliseconds
+        * Returns: 0 on success, -1 on failure
+        *
+        * This function can be used to request the P2P module to keep the
+        * device discoverable on the listen channel for an extended set of
+        * time. At least in its current form, this is mainly used for testing
+        * purposes and may not be of much use for normal P2P operations.
+        *
+        * This function is only used if the driver implements P2P management,
+        * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+        * struct wpa_driver_capa.
+        */
+       int (*p2p_listen)(void *priv, unsigned int timeout);
+
+       /**
+        * p2p_connect - Start P2P group formation (GO negotiation)
+        * @priv: Private driver interface data
+        * @peer_addr: MAC address of the peer P2P client
+        * @wps_method: enum p2p_wps_method value indicating config method
+        * @go_intent: Local GO intent value (1..15)
+        * @own_interface_addr: Intended interface address to use with the
+        *      group
+        * @force_freq: The only allowed channel frequency in MHz or 0
+        * @persistent_group: Whether to create persistent group
+        * Returns: 0 on success, -1 on failure
+        *
+        * This function is only used if the driver implements P2P management,
+        * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+        * struct wpa_driver_capa.
+        */
+       int (*p2p_connect)(void *priv, const u8 *peer_addr, int wps_method,
+                          int go_intent, const u8 *own_interface_addr,
+                          unsigned int force_freq, int persistent_group);
+
+       /**
+        * wps_success_cb - Report successfully completed WPS provisioning
+        * @priv: Private driver interface data
+        * @peer_addr: Peer address
+        * Returns: 0 on success, -1 on failure
+        *
+        * This function is used to report successfully completed WPS
+        * provisioning during group formation in both GO/Registrar and
+        * client/Enrollee roles.
+        *
+        * This function is only used if the driver implements P2P management,
+        * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+        * struct wpa_driver_capa.
+        */
+       int (*wps_success_cb)(void *priv, const u8 *peer_addr);
+
+       /**
+        * p2p_group_formation_failed - Report failed WPS provisioning
+        * @priv: Private driver interface data
+        * Returns: 0 on success, -1 on failure
+        *
+        * This function is used to report failed group formation. This can
+        * happen either due to failed WPS provisioning or due to 15 second
+        * timeout during the provisioning phase.
+        *
+        * This function is only used if the driver implements P2P management,
+        * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+        * struct wpa_driver_capa.
+        */
+       int (*p2p_group_formation_failed)(void *priv);
+
+       /**
+        * p2p_set_params - Set P2P parameters
+        * @priv: Private driver interface data
+        * @params: P2P parameters
+        * Returns: 0 on success, -1 on failure
+        *
+        * This function is only used if the driver implements P2P management,
+        * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+        * struct wpa_driver_capa.
+        */
+       int (*p2p_set_params)(void *priv, const struct p2p_params *params);
+
+       /**
+        * p2p_prov_disc_req - Send Provision Discovery Request
+        * @priv: Private driver interface data
+        * @peer_addr: MAC address of the peer P2P client
+        * @config_methods: WPS Config Methods value (only one bit set)
+        * Returns: 0 on success, -1 on failure
+        *
+        * This function can be used to request a discovered P2P peer to
+        * display a PIN (config_methods = WPS_CONFIG_DISPLAY) or be prepared
+        * to enter a PIN from us (config_methods = WPS_CONFIG_KEYPAD). The
+        * Provision Discovery Request frame is transmitted once immediately
+        * and if no response is received, the frame will be sent again
+        * whenever the target device is discovered during device dsicovery
+        * (start with a p2p_find() call). Response from the peer is indicated
+        * with the EVENT_P2P_PROV_DISC_RESPONSE event.
+        *
+        * This function is only used if the driver implements P2P management,
+        * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+        * struct wpa_driver_capa.
+        */
+       int (*p2p_prov_disc_req)(void *priv, const u8 *peer_addr,
+                                u16 config_methods, int join);
+
+       /**
+        * p2p_sd_request - Schedule a service discovery query
+        * @priv: Private driver interface data
+        * @dst: Destination peer or %NULL to apply for all peers
+        * @tlvs: P2P Service Query TLV(s)
+        * Returns: Reference to the query or 0 on failure
+        *
+        * Response to the query is indicated with the
+        * EVENT_P2P_SD_RESPONSE driver event.
+        *
+        * This function is only used if the driver implements P2P management,
+        * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+        * struct wpa_driver_capa.
+        */
+       u64 (*p2p_sd_request)(void *priv, const u8 *dst,
+                             const struct wpabuf *tlvs);
+
+       /**
+        * p2p_sd_cancel_request - Cancel a pending service discovery query
+        * @priv: Private driver interface data
+        * @req: Query reference from p2p_sd_request()
+        * Returns: 0 on success, -1 on failure
+        *
+        * This function is only used if the driver implements P2P management,
+        * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+        * struct wpa_driver_capa.
+        */
+       int (*p2p_sd_cancel_request)(void *priv, u64 req);
+
+       /**
+        * p2p_sd_response - Send response to a service discovery query
+        * @priv: Private driver interface data
+        * @freq: Frequency from EVENT_P2P_SD_REQUEST event
+        * @dst: Destination address from EVENT_P2P_SD_REQUEST event
+        * @dialog_token: Dialog token from EVENT_P2P_SD_REQUEST event
+        * @resp_tlvs: P2P Service Response TLV(s)
+        * Returns: 0 on success, -1 on failure
+        *
+        * This function is called as a response to the request indicated with
+        * the EVENT_P2P_SD_REQUEST driver event.
+        *
+        * This function is only used if the driver implements P2P management,
+        * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+        * struct wpa_driver_capa.
+        */
+       int (*p2p_sd_response)(void *priv, int freq, const u8 *dst,
+                              u8 dialog_token,
+                              const struct wpabuf *resp_tlvs);
+
+       /**
+        * p2p_service_update - Indicate a change in local services
+        * @priv: Private driver interface data
+        * Returns: 0 on success, -1 on failure
+        *
+        * This function needs to be called whenever there is a change in
+        * availability of the local services. This will increment the
+        * Service Update Indicator value which will be used in SD Request and
+        * Response frames.
+        *
+        * This function is only used if the driver implements P2P management,
+        * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+        * struct wpa_driver_capa.
+        */
+       int (*p2p_service_update)(void *priv);
+
+       /**
+        * p2p_reject - Reject peer device (explicitly block connections)
+        * @priv: Private driver interface data
+        * @addr: MAC address of the peer
+        * Returns: 0 on success, -1 on failure
+        */
+       int (*p2p_reject)(void *priv, const u8 *addr);
+
+       /**
+        * p2p_invite - Invite a P2P Device into a group
+        * @priv: Private driver interface data
+        * @peer: Device Address of the peer P2P Device
+        * @role: Local role in the group
+        * @bssid: Group BSSID or %NULL if not known
+        * @ssid: Group SSID
+        * @ssid_len: Length of ssid in octets
+        * @go_dev_addr: Forced GO Device Address or %NULL if none
+        * @persistent_group: Whether this is to reinvoke a persistent group
+        * Returns: 0 on success, -1 on failure
+        */
+       int (*p2p_invite)(void *priv, const u8 *peer, int role,
+                         const u8 *bssid, const u8 *ssid, size_t ssid_len,
+                         const u8 *go_dev_addr, int persistent_group);
+
+       /**
+        * send_tdls_mgmt - for sending TDLS management packets
+        * @priv: private driver interface data
+        * @dst: Destination (peer) MAC address
+        * @action_code: TDLS action code for the mssage
+        * @dialog_token: Dialog Token to use in the message (if needed)
+        * @status_code: Status Code or Reason Code to use (if needed)
+        * @buf: TDLS IEs to add to the message
+        * @len: Length of buf in octets
+        * Returns: 0 on success, negative (<0) on failure
+        *
+        * This optional function can be used to send packet to driver which is
+        * responsible for receiving and sending all TDLS packets.
+        */
+       int (*send_tdls_mgmt)(void *priv, const u8 *dst, u8 action_code,
+                             u8 dialog_token, u16 status_code,
+                             const u8 *buf, size_t len);
+
+       /**
+        * tdls_oper - Ask the driver to perform high-level TDLS operations
+        * @priv: Private driver interface data
+        * @oper: TDLS high-level operation. See %enum tdls_oper
+        * @peer: Destination (peer) MAC address
+        * Returns: 0 on success, negative (<0) on failure
+        *
+        * This optional function can be used to send high-level TDLS commands
+        * to the driver.
+        */
+       int (*tdls_oper)(void *priv, enum tdls_oper oper, const u8 *peer);
+
+       /**
+        * signal_poll - Get current connection information
+        * @priv: Private driver interface data
+        * @signal_info: Connection info structure
+         */
+       int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info);
+
+       /**
+        * set_authmode - Set authentication algorithm(s) for static WEP
+        * @priv: Private driver interface data
+        * @authmode: 1=Open System, 2=Shared Key, 3=both
+        * Returns: 0 on success, -1 on failure
+        *
+        * This function can be used to set authentication algorithms for AP
+        * mode when static WEP is used. If the driver uses user space MLME/SME
+        * implementation, there is no need to implement this function.
+        *
+        * DEPRECATED - use set_ap() instead
+        */
+       int (*set_authmode)(void *priv, int authmode);
+
+       /**
+        * set_rekey_info - Set rekey information
+        * @priv: Private driver interface data
+        * @kek: Current KEK
+        * @kck: Current KCK
+        * @replay_ctr: Current EAPOL-Key Replay Counter
+        *
+        * This optional function can be used to provide information for the
+        * driver/firmware to process EAPOL-Key frames in Group Key Handshake
+        * while the host (including wpa_supplicant) is sleeping.
+        */
+       void (*set_rekey_info)(void *priv, const u8 *kek, const u8 *kck,
+                              const u8 *replay_ctr);
+
+       /**
+        * sta_assoc - Station association indication
+        * @priv: Private driver interface data
+        * @own_addr: Source address and BSSID for association frame
+        * @addr: MAC address of the station to associate
+        * @reassoc: flag to indicate re-association
+        * @status: association response status code
+        * @ie: assoc response ie buffer
+        * @len: ie buffer length
+        * Returns: 0 on success, -1 on failure
+        *
+        * This function indicates the driver to send (Re)Association
+        * Response frame to the station.
+        */
+        int (*sta_assoc)(void *priv, const u8 *own_addr, const u8 *addr,
+                         int reassoc, u16 status, const u8 *ie, size_t len);
+
+       /**
+        * sta_auth - Station authentication indication
+        * @priv: Private driver interface data
+        * @own_addr: Source address and BSSID for authentication frame
+        * @addr: MAC address of the station to associate
+        * @seq: authentication sequence number
+        * @status: authentication response status code
+        * @ie: authentication frame ie buffer
+        * @len: ie buffer length
+        *
+        * This function indicates the driver to send Authentication frame
+        * to the station.
+        */
+        int (*sta_auth)(void *priv, const u8 *own_addr, const u8 *addr,
+                        u16 seq, u16 status, const u8 *ie, size_t len);
+
+       /**
+        * add_tspec - Add traffic stream
+        * @priv: Private driver interface data
+        * @addr: MAC address of the station to associate
+        * @tspec_ie: tspec ie buffer
+        * @tspec_ielen: tspec ie length
+        * Returns: 0 on success, -1 on failure
+        *
+        * This function adds the traffic steam for the station
+        * and fills the medium_time in tspec_ie.
+        */
+        int (*add_tspec)(void *priv, const u8 *addr, u8 *tspec_ie,
+                         size_t tspec_ielen);
+
+       /**
+        * add_sta_node - Add a station node in the driver
+        * @priv: Private driver interface data
+        * @addr: MAC address of the station to add
+        * @auth_alg: authentication algorithm used by the station
+        * Returns: 0 on success, -1 on failure
+        *
+        * This function adds the station node in the driver, when
+        * the station gets added by FT-over-DS.
+        */
+       int (*add_sta_node)(void *priv, const u8 *addr, u16 auth_alg);
+
+       /**
+        * sched_scan - Request the driver to initiate scheduled scan
+        * @priv: Private driver interface data
+        * @params: Scan parameters
+        * @interval: Interval between scan cycles in milliseconds
+        * Returns: 0 on success, -1 on failure
+        *
+        * This operation should be used for scheduled scan offload to
+        * the hardware. Every time scan results are available, the
+        * driver should report scan results event for wpa_supplicant
+        * which will eventually request the results with
+        * wpa_driver_get_scan_results2(). This operation is optional
+        * and if not provided or if it returns -1, we fall back to
+        * normal host-scheduled scans.
+        */
+       int (*sched_scan)(void *priv, struct wpa_driver_scan_params *params,
+                         u32 interval);
+
+       /**
+        * stop_sched_scan - Request the driver to stop a scheduled scan
+        * @priv: Private driver interface data
+        * Returns: 0 on success, -1 on failure
+        *
+        * This should cause the scheduled scan to be stopped and
+        * results should stop being sent. Must be supported if
+        * sched_scan is supported.
+        */
+       int (*stop_sched_scan)(void *priv);
+
+       /**
+        * poll_client - Probe (null data or such) the given station
+        * @priv: Private driver interface data
+        * @own_addr: MAC address of sending interface
+        * @addr: MAC address of the station to probe
+        * @qos: Indicates whether station is QoS station
+        *
+        * This function is used to verify whether an associated station is
+        * still present. This function does not need to be implemented if the
+        * driver provides such inactivity polling mechanism.
+        */
+       void (*poll_client)(void *priv, const u8 *own_addr,
+                           const u8 *addr, int qos);
+};
+
+
+/**
+ * enum wpa_event_type - Event type for wpa_supplicant_event() calls
+ */
+enum wpa_event_type {
+       /**
+        * EVENT_ASSOC - Association completed
+        *
+        * This event needs to be delivered when the driver completes IEEE
+        * 802.11 association or reassociation successfully.
+        * wpa_driver_ops::get_bssid() is expected to provide the current BSSID
+        * after this event has been generated. In addition, optional
+        * EVENT_ASSOCINFO may be generated just before EVENT_ASSOC to provide
+        * more information about the association. If the driver interface gets
+        * both of these events at the same time, it can also include the
+        * assoc_info data in EVENT_ASSOC call.
+        */
+       EVENT_ASSOC,
 
        /**
         * EVENT_DISASSOC - Association lost
@@ -1887,6 +2605,13 @@ enum wpa_event_type {
        EVENT_STKSTART,
 
        /**
+        * EVENT_TDLS - Request TDLS operation
+        *
+        * This event can be used to request a TDLS operation to be performed.
+        */
+       EVENT_TDLS,
+
+       /**
         * EVENT_FT_RESPONSE - Report FT (IEEE 802.11r) response IEs
         *
         * The driver is expected to report the received FT IEs from
@@ -1930,7 +2655,7 @@ enum wpa_event_type {
         * EVENT_ASSOC_REJECT - Association rejected
         *
         * This event should be called when (re)association attempt has been
-        * rejected by the AP. Information about authentication result is
+        * rejected by the AP. Information about the association response is
         * included in union wpa_event_data::assoc_reject.
         */
        EVENT_ASSOC_REJECT,
@@ -2046,7 +2771,149 @@ enum wpa_event_type {
         * observed in frames received from the current AP if signal strength
         * monitoring has been enabled with signal_monitor().
         */
-       EVENT_SIGNAL_CHANGE
+       EVENT_SIGNAL_CHANGE,
+
+       /**
+        * EVENT_INTERFACE_ENABLED - Notify that interface was enabled
+        *
+        * This event is used to indicate that the interface was enabled after
+        * having been previously disabled, e.g., due to rfkill.
+        */
+       EVENT_INTERFACE_ENABLED,
+
+       /**
+        * EVENT_INTERFACE_DISABLED - Notify that interface was disabled
+        *
+        * This event is used to indicate that the interface was disabled,
+        * e.g., due to rfkill.
+        */
+       EVENT_INTERFACE_DISABLED,
+
+       /**
+        * EVENT_CHANNEL_LIST_CHANGED - Channel list changed
+        *
+        * This event is used to indicate that the channel list has changed,
+        * e.g., because of a regulatory domain change triggered by scan
+        * results including an AP advertising a country code.
+        */
+       EVENT_CHANNEL_LIST_CHANGED,
+
+       /**
+        * EVENT_INTERFACE_UNAVAILABLE - Notify that interface is unavailable
+        *
+        * This event is used to indicate that the driver cannot maintain this
+        * interface in its operation mode anymore. The most likely use for
+        * this is to indicate that AP mode operation is not available due to
+        * operating channel would need to be changed to a DFS channel when
+        * the driver does not support radar detection and another virtual
+        * interfaces caused the operating channel to change. Other similar
+        * resource conflicts could also trigger this for station mode
+        * interfaces.
+        */
+       EVENT_INTERFACE_UNAVAILABLE,
+
+       /**
+        * EVENT_BEST_CHANNEL
+        *
+        * Driver generates this event whenever it detects a better channel
+        * (e.g., based on RSSI or channel use). This information can be used
+        * to improve channel selection for a new AP/P2P group.
+        */
+       EVENT_BEST_CHANNEL,
+
+       /**
+        * EVENT_UNPROT_DEAUTH - Unprotected Deauthentication frame received
+        *
+        * This event should be called when a Deauthentication frame is dropped
+        * due to it not being protected (MFP/IEEE 802.11w).
+        * union wpa_event_data::unprot_deauth is required to provide more
+        * details of the frame.
+        */
+       EVENT_UNPROT_DEAUTH,
+
+       /**
+        * EVENT_UNPROT_DISASSOC - Unprotected Disassociation frame received
+        *
+        * This event should be called when a Disassociation frame is dropped
+        * due to it not being protected (MFP/IEEE 802.11w).
+        * union wpa_event_data::unprot_disassoc is required to provide more
+        * details of the frame.
+        */
+       EVENT_UNPROT_DISASSOC,
+
+       /**
+        * EVENT_STATION_LOW_ACK
+        *
+        * Driver generates this event whenever it detected that a particular
+        * station was lost. Detection can be through massive transmission
+        * failures for example.
+        */
+       EVENT_STATION_LOW_ACK,
+
+       /**
+        * EVENT_P2P_DEV_FOUND - Report a discovered P2P device
+        *
+        * This event is used only if the driver implements P2P management
+        * internally. Event data is stored in
+        * union wpa_event_data::p2p_dev_found.
+        */
+       EVENT_P2P_DEV_FOUND,
+
+       /**
+        * EVENT_P2P_GO_NEG_REQ_RX - Report reception of GO Negotiation Request
+        *
+        * This event is used only if the driver implements P2P management
+        * internally. Event data is stored in
+        * union wpa_event_data::p2p_go_neg_req_rx.
+        */
+       EVENT_P2P_GO_NEG_REQ_RX,
+
+       /**
+        * EVENT_P2P_GO_NEG_COMPLETED - Report completion of GO Negotiation
+        *
+        * This event is used only if the driver implements P2P management
+        * internally. Event data is stored in
+        * union wpa_event_data::p2p_go_neg_completed.
+        */
+       EVENT_P2P_GO_NEG_COMPLETED,
+
+       EVENT_P2P_PROV_DISC_REQUEST,
+       EVENT_P2P_PROV_DISC_RESPONSE,
+       EVENT_P2P_SD_REQUEST,
+       EVENT_P2P_SD_RESPONSE,
+
+       /**
+        * EVENT_IBSS_PEER_LOST - IBSS peer not reachable anymore
+        */
+       EVENT_IBSS_PEER_LOST,
+
+       /**
+        * EVENT_DRIVER_GTK_REKEY - Device/driver did GTK rekey
+        *
+        * This event carries the new replay counter to notify wpa_supplicant
+        * of the current EAPOL-Key Replay Counter in case the driver/firmware
+        * completed Group Key Handshake while the host (including
+        * wpa_supplicant was sleeping).
+        */
+       EVENT_DRIVER_GTK_REKEY,
+
+       /**
+        * EVENT_SCHED_SCAN_STOPPED - Scheduled scan was stopped
+        */
+       EVENT_SCHED_SCAN_STOPPED,
+
+       /**
+        * EVENT_DRIVER_CLIENT_POLL_OK - Station responded to poll
+        *
+        * This event indicates that the station responded to the poll
+        * initiated with @poll_client.
+        */
+       EVENT_DRIVER_CLIENT_POLL_OK,
+
+       /**
+        * EVENT_EAPOL_TX_STATUS - notify of EAPOL TX status
+        */
+       EVENT_EAPOL_TX_STATUS
 };
 
 
@@ -2064,6 +2931,11 @@ union wpa_event_data {
         */
        struct assoc_info {
                /**
+                * reassoc - Flag to indicate association or reassociation
+                */
+               int reassoc;
+
+               /**
                 * req_ies - (Re)Association Request IEs
                 *
                 * If the driver generates WPA/RSN IE, this event data must be
@@ -2146,6 +3018,16 @@ union wpa_event_data {
                 *      Deauthentication frame
                 */
                u16 reason_code;
+
+               /**
+                * ie - Optional IE(s) in Disassociation frame
+                */
+               const u8 *ie;
+
+               /**
+                * ie_len - Length of ie buffer in octets
+                */
+               size_t ie_len;
        } disassoc_info;
 
        /**
@@ -2162,6 +3044,16 @@ union wpa_event_data {
                 *      Deauthentication frame
                 */
                u16 reason_code;
+
+               /**
+                * ie - Optional IE(s) in Deauthentication frame
+                */
+               const u8 *ie;
+
+               /**
+                * ie_len - Length of ie buffer in octets
+                */
+               size_t ie_len;
        } deauth_info;
 
        /**
@@ -2202,6 +3094,18 @@ union wpa_event_data {
        } stkstart;
 
        /**
+        * struct tdls - Data for EVENT_TDLS
+        */
+       struct tdls {
+               u8 peer[ETH_ALEN];
+               enum {
+                       TDLS_REQUEST_SETUP,
+                       TDLS_REQUEST_TEARDOWN
+               } oper;
+               u16 reason_code; /* for teardown */
+       } tdls;
+
+       /**
         * struct ft_ies - FT information elements (EVENT_FT_RESPONSE)
         *
         * During FT (IEEE 802.11r) authentication sequence, the driver is
@@ -2233,7 +3137,9 @@ union wpa_event_data {
         */
        struct auth_info {
                u8 peer[ETH_ALEN];
+               u8 bssid[ETH_ALEN];
                u16 auth_type;
+               u16 auth_transaction;
                u16 status_code;
                const u8 *ies;
                size_t ies_len;
@@ -2244,6 +3150,11 @@ union wpa_event_data {
         */
        struct assoc_reject {
                /**
+                * bssid - BSSID of the AP that rejected association
+                */
+               const u8 *bssid;
+
+               /**
                 * resp_ies - (Re)Association Response IEs
                 *
                 * Optional association data from the driver. This data is not
@@ -2254,7 +3165,7 @@ union wpa_event_data {
                 * This should start with the first IE (fixed fields before IEs
                 * are not included).
                 */
-               u8 *resp_ies;
+               const u8 *resp_ies;
 
                /**
                 * resp_ies_len - Length of resp_ies in bytes
@@ -2296,8 +3207,9 @@ union wpa_event_data {
         * struct rx_from_unknown - Data for EVENT_RX_FROM_UNKNOWN events
         */
        struct rx_from_unknown {
-               const u8 *frame;
-               size_t len;
+               const u8 *bssid;
+               const u8 *addr;
+               int wds;
        } rx_from_unknown;
 
        /**
@@ -2405,6 +3317,18 @@ union wpa_event_data {
                const u8 *sa;
 
                /**
+                * da - Destination address of the received Probe Request frame
+                *      or %NULL if not available
+                */
+               const u8 *da;
+
+               /**
+                * bssid - BSSID of the received Probe Request frame or %NULL
+                *      if not available
+                */
+               const u8 *bssid;
+
+               /**
                 * ie - IEs from the Probe Request body
                 */
                const u8 *ie;
@@ -2432,11 +3356,143 @@ union wpa_event_data {
        } eapol_rx;
 
        /**
-        * struct signal_change - Data for EVENT_SIGNAL_CHANGE events
+        * signal_change - Data for EVENT_SIGNAL_CHANGE events
+        */
+       struct wpa_signal_info signal_change;
+
+       /**
+        * struct best_channel - Data for EVENT_BEST_CHANNEL events
+        * @freq_24: Best 2.4 GHz band channel frequency in MHz
+        * @freq_5: Best 5 GHz band channel frequency in MHz
+        * @freq_overall: Best channel frequency in MHz
+        *
+        * 0 can be used to indicate no preference in either band.
+        */
+       struct best_channel {
+               int freq_24;
+               int freq_5;
+               int freq_overall;
+       } best_chan;
+
+       struct unprot_deauth {
+               const u8 *sa;
+               const u8 *da;
+               u16 reason_code;
+       } unprot_deauth;
+
+       struct unprot_disassoc {
+               const u8 *sa;
+               const u8 *da;
+               u16 reason_code;
+       } unprot_disassoc;
+
+       /**
+        * struct low_ack - Data for EVENT_STATION_LOW_ACK events
+        * @addr: station address
+        */
+       struct low_ack {
+               u8 addr[ETH_ALEN];
+       } low_ack;
+
+       /**
+        * struct p2p_dev_found - Data for EVENT_P2P_DEV_FOUND
         */
-       struct signal_change {
-               int above_threshold;
-       } signal_change;
+       struct p2p_dev_found {
+               const u8 *addr;
+               const u8 *dev_addr;
+               const u8 *pri_dev_type;
+               const char *dev_name;
+               u16 config_methods;
+               u8 dev_capab;
+               u8 group_capab;
+       } p2p_dev_found;
+
+       /**
+        * struct p2p_go_neg_req_rx - Data for EVENT_P2P_GO_NEG_REQ_RX
+        */
+       struct p2p_go_neg_req_rx {
+               const u8 *src;
+               u16 dev_passwd_id;
+       } p2p_go_neg_req_rx;
+
+       /**
+        * struct p2p_go_neg_completed - Data for EVENT_P2P_GO_NEG_COMPLETED
+        */
+       struct p2p_go_neg_completed {
+               struct p2p_go_neg_results *res;
+       } p2p_go_neg_completed;
+
+       struct p2p_prov_disc_req {
+               const u8 *peer;
+               u16 config_methods;
+               const u8 *dev_addr;
+               const u8 *pri_dev_type;
+               const char *dev_name;
+               u16 supp_config_methods;
+               u8 dev_capab;
+               u8 group_capab;
+       } p2p_prov_disc_req;
+
+       struct p2p_prov_disc_resp {
+               const u8 *peer;
+               u16 config_methods;
+       } p2p_prov_disc_resp;
+
+       struct p2p_sd_req {
+               int freq;
+               const u8 *sa;
+               u8 dialog_token;
+               u16 update_indic;
+               const u8 *tlvs;
+               size_t tlvs_len;
+       } p2p_sd_req;
+
+       struct p2p_sd_resp {
+               const u8 *sa;
+               u16 update_indic;
+               const u8 *tlvs;
+               size_t tlvs_len;
+       } p2p_sd_resp;
+
+       /**
+        * struct ibss_peer_lost - Data for EVENT_IBSS_PEER_LOST
+        */
+       struct ibss_peer_lost {
+               u8 peer[ETH_ALEN];
+       } ibss_peer_lost;
+
+       /**
+        * struct driver_gtk_rekey - Data for EVENT_DRIVER_GTK_REKEY
+        */
+       struct driver_gtk_rekey {
+               const u8 *bssid;
+               const u8 *replay_ctr;
+       } driver_gtk_rekey;
+
+       /**
+        * struct client_poll - Data for EVENT_DRIVER_CLIENT_POLL_OK events
+        * @addr: station address
+        */
+       struct client_poll {
+               u8 addr[ETH_ALEN];
+       } client_poll;
+
+       /**
+        * struct eapol_tx_status
+        * @dst: Original destination
+        * @data: Data starting with IEEE 802.1X header (!)
+        * @data_len: Length of data
+        * @ack: Indicates ack or lost frame
+        *
+        * This corresponds to hapd_send_eapol if the frame sent
+        * there isn't just reported as EVENT_TX_STATUS.
+        */
+       struct eapol_tx_status {
+               const u8 *dst;
+               const u8 *data;
+               int data_len;
+               int ack;
+       } eapol_tx_status;
 };
 
 /**
@@ -2459,10 +3515,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
  */
 
 static inline void drv_event_assoc(void *ctx, const u8 *addr, const u8 *ie,
-                                  size_t ielen)
+                                  size_t ielen, int reassoc)
 {
        union wpa_event_data event;
        os_memset(&event, 0, sizeof(event));
+       event.assoc_info.reassoc = reassoc;
        event.assoc_info.req_ies = ie;
        event.assoc_info.req_ies_len = ielen;
        event.assoc_info.addr = addr;
@@ -2488,4 +3545,10 @@ static inline void drv_event_eapol_rx(void *ctx, const u8 *src, const u8 *data,
        wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event);
 }
 
+/* driver_common.c */
+void wpa_scan_results_free(struct wpa_scan_results *res);
+
+/* Convert wpa_event_type to a string for logging */
+const char * event_to_string(enum wpa_event_type event);
+
 #endif /* DRIVER_H */
index 5c25f00..b17d1a6 100644 (file)
@@ -34,7 +34,7 @@
  */
 #define ATH_WPS_IE
 
-#include "os/linux/include/ieee80211_external.h"
+#include "ieee80211_external.h"
 
 
 #ifdef CONFIG_WPS
@@ -45,7 +45,7 @@
 #endif
 #endif /* CONFIG_WPS */
 
-#include "wireless_copy.h"
+#include "linux_wext.h"
 
 #include "driver.h"
 #include "eloop.h"
@@ -56,7 +56,7 @@
 #include "linux_ioctl.h"
 
 
-struct madwifi_driver_data {
+struct atheros_driver_data {
        struct hostapd_data *hapd;              /* back pointer */
 
        char    iface[IFNAMSIZ + 1];
@@ -70,11 +70,14 @@ struct madwifi_driver_data {
        struct hostap_sta_driver_data acct_data;
 
        struct l2_packet_data *sock_raw; /* raw 802.11 management frames */
+       struct wpabuf *wpa_ie;
+       struct wpabuf *wps_beacon_ie;
+       struct wpabuf *wps_probe_resp_ie;
 };
 
-static int madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
+static int atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
                              int reason_code);
-static int madwifi_set_privacy(void *priv, int enabled);
+static int atheros_set_privacy(void *priv, int enabled);
 
 static const char * athr_get_ioctl_name(int op)
 {
@@ -125,16 +128,8 @@ static const char * athr_get_ioctl_name(int op)
                return "FILTERFRAME";
        case IEEE80211_IOCTL_SET_RTPARAMS:
                return "SET_RTPARAMS";
-       case IEEE80211_IOCTL_SENDADDBA:
-               return "SENDADDBA";
-       case IEEE80211_IOCTL_GETADDBASTATUS:
-               return "GETADDBASTATUS";
-       case IEEE80211_IOCTL_SENDDELBA:
-               return "SENDDELBA";
        case IEEE80211_IOCTL_SET_MEDENYENTRY:
                return "SET_MEDENYENTRY";
-       case IEEE80211_IOCTL_SET_ADDBARESP:
-               return "SET_ADDBARESP";
        case IEEE80211_IOCTL_GET_MACADDR:
                return "GET_MACADDR";
        case IEEE80211_IOCTL_SET_HBRPARAMS:
@@ -179,7 +174,7 @@ static const char * athr_get_param_name(int op)
 
 
 static int
-set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len)
+set80211priv(struct atheros_driver_data *drv, int op, void *data, int len)
 {
        struct iwreq iwr;
        int do_inline = len < IFNAMSIZ;
@@ -218,7 +213,7 @@ set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len)
 }
 
 static int
-set80211param(struct madwifi_driver_data *drv, int op, int arg)
+set80211param(struct atheros_driver_data *drv, int op, int arg)
 {
        struct iwreq iwr;
 
@@ -255,7 +250,7 @@ ether_sprintf(const u8 *addr)
  * Configure WPA parameters.
  */
 static int
-madwifi_configure_wpa(struct madwifi_driver_data *drv,
+atheros_configure_wpa(struct atheros_driver_data *drv,
                      struct wpa_bss_params *params)
 {
        int v;
@@ -320,6 +315,14 @@ madwifi_configure_wpa(struct madwifi_driver_data *drv,
        v = 0;
        if (params->rsn_preauth)
                v |= BIT(0);
+#ifdef CONFIG_IEEE80211W
+       if (params->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+               v |= BIT(7);
+               if (params->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
+                       v |= BIT(6);
+       }
+#endif /* CONFIG_IEEE80211W */
+
        wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
                   __func__, params->rsn_preauth);
        if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
@@ -336,9 +339,9 @@ madwifi_configure_wpa(struct madwifi_driver_data *drv,
 }
 
 static int
-madwifi_set_ieee8021x(void *priv, struct wpa_bss_params *params)
+atheros_set_ieee8021x(void *priv, struct wpa_bss_params *params)
 {
-       struct madwifi_driver_data *drv = priv;
+       struct atheros_driver_data *drv = priv;
 
        wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled);
 
@@ -348,14 +351,14 @@ madwifi_set_ieee8021x(void *priv, struct wpa_bss_params *params)
                                  IEEE80211_AUTH_AUTO) < 0)
                        return -1;
                /* IEEE80211_AUTH_AUTO ends up enabling Privacy; clear that */
-               return madwifi_set_privacy(drv, 0);
+               return atheros_set_privacy(drv, 0);
        }
        if (!params->wpa && !params->ieee802_1x) {
                hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
                        HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");
                return -1;
        }
-       if (params->wpa && madwifi_configure_wpa(drv, params) != 0) {
+       if (params->wpa && atheros_configure_wpa(drv, params) != 0) {
                hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
                        HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");
                return -1;
@@ -371,9 +374,9 @@ madwifi_set_ieee8021x(void *priv, struct wpa_bss_params *params)
 }
 
 static int
-madwifi_set_privacy(void *priv, int enabled)
+atheros_set_privacy(void *priv, int enabled)
 {
-       struct madwifi_driver_data *drv = priv;
+       struct atheros_driver_data *drv = priv;
 
        wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
 
@@ -381,9 +384,9 @@ madwifi_set_privacy(void *priv, int enabled)
 }
 
 static int
-madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized)
+atheros_set_sta_authorized(void *priv, const u8 *addr, int authorized)
 {
-       struct madwifi_driver_data *drv = priv;
+       struct atheros_driver_data *drv = priv;
        struct ieee80211req_mlme mlme;
        int ret;
 
@@ -406,21 +409,21 @@ madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized)
 }
 
 static int
-madwifi_sta_set_flags(void *priv, const u8 *addr,
+atheros_sta_set_flags(void *priv, const u8 *addr,
                      int total_flags, int flags_or, int flags_and)
 {
        /* For now, only support setting Authorized flag */
        if (flags_or & WPA_STA_AUTHORIZED)
-               return madwifi_set_sta_authorized(priv, addr, 1);
+               return atheros_set_sta_authorized(priv, addr, 1);
        if (!(flags_and & WPA_STA_AUTHORIZED))
-               return madwifi_set_sta_authorized(priv, addr, 0);
+               return atheros_set_sta_authorized(priv, addr, 0);
        return 0;
 }
 
 static int
-madwifi_del_key(void *priv, const u8 *addr, int key_idx)
+atheros_del_key(void *priv, const u8 *addr, int key_idx)
 {
-       struct madwifi_driver_data *drv = priv;
+       struct atheros_driver_data *drv = priv;
        struct ieee80211req_del_key wk;
        int ret;
 
@@ -446,17 +449,17 @@ madwifi_del_key(void *priv, const u8 *addr, int key_idx)
 }
 
 static int
-madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg,
+atheros_set_key(const char *ifname, void *priv, enum wpa_alg alg,
                const u8 *addr, int key_idx, int set_tx, const u8 *seq,
                size_t seq_len, const u8 *key, size_t key_len)
 {
-       struct madwifi_driver_data *drv = priv;
+       struct atheros_driver_data *drv = priv;
        struct ieee80211req_key wk;
        u_int8_t cipher;
        int ret;
 
        if (alg == WPA_ALG_NONE)
-               return madwifi_del_key(drv, addr, key_idx);
+               return atheros_del_key(drv, addr, key_idx);
 
        wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d",
                   __func__, alg, ether_sprintf(addr), key_idx);
@@ -471,6 +474,11 @@ madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg,
        case WPA_ALG_CCMP:
                cipher = IEEE80211_CIPHER_AES_CCM;
                break;
+#ifdef CONFIG_IEEE80211W
+       case WPA_ALG_IGTK:
+               cipher = IEEE80211_CIPHER_AES_CMAC;
+               break;
+#endif /* CONFIG_IEEE80211W */
        default:
                printf("%s: unknown/unsupported algorithm %d\n",
                        __func__, alg);
@@ -486,10 +494,11 @@ madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg,
        memset(&wk, 0, sizeof(wk));
        wk.ik_type = cipher;
        wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;
-       if (addr == NULL) {
+       if (addr == NULL || is_broadcast_ether_addr(addr)) {
                memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
                wk.ik_keyix = key_idx;
-               wk.ik_flags |= IEEE80211_KEY_DEFAULT;
+               if (set_tx)
+                       wk.ik_flags |= IEEE80211_KEY_DEFAULT;
        } else {
                memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
                wk.ik_keyix = IEEE80211_KEYIX_NONE;
@@ -510,10 +519,10 @@ madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg,
 
 
 static int
-madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
+atheros_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
                   u8 *seq)
 {
-       struct madwifi_driver_data *drv = priv;
+       struct atheros_driver_data *drv = priv;
        struct ieee80211req_key wk;
 
        wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
@@ -557,20 +566,20 @@ madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
 
 
 static int
-madwifi_flush(void *priv)
+atheros_flush(void *priv)
 {
        u8 allsta[IEEE80211_ADDR_LEN];
        memset(allsta, 0xff, IEEE80211_ADDR_LEN);
-       return madwifi_sta_deauth(priv, NULL, allsta,
+       return atheros_sta_deauth(priv, NULL, allsta,
                                  IEEE80211_REASON_AUTH_LEAVE);
 }
 
 
 static int
-madwifi_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
+atheros_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
                             const u8 *addr)
 {
-       struct madwifi_driver_data *drv = priv;
+       struct atheros_driver_data *drv = priv;
        struct ieee80211req_sta_stats stats;
 
        memset(data, 0, sizeof(*data));
@@ -602,9 +611,9 @@ madwifi_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
 
 
 static int
-madwifi_sta_clear_stats(void *priv, const u8 *addr)
+atheros_sta_clear_stats(void *priv, const u8 *addr)
 {
-       struct madwifi_driver_data *drv = priv;
+       struct atheros_driver_data *drv = priv;
        struct ieee80211req_mlme mlme;
        int ret;
 
@@ -624,20 +633,61 @@ madwifi_sta_clear_stats(void *priv, const u8 *addr)
 
 
 static int
-madwifi_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
+atheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
 {
-       /*
-        * Do nothing; we setup parameters at startup that define the
-        * contents of the beacon information element.
-        */
+       struct atheros_driver_data *drv = priv;
+       u8 buf[512];
+       struct ieee80211req_getset_appiebuf *app_ie;
+
+       wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
+                  (unsigned long) ie_len);
+       wpa_hexdump(MSG_DEBUG, "atheros: set_generic_elem", ie, ie_len);
+
+       wpabuf_free(drv->wpa_ie);
+       drv->wpa_ie = wpabuf_alloc_copy(ie, ie_len);
+
+       app_ie = (struct ieee80211req_getset_appiebuf *) buf;
+       os_memcpy(&(app_ie->app_buf[0]), ie, ie_len);
+       app_ie->app_buflen = ie_len;
+
+       app_ie->app_frmtype = IEEE80211_APPIE_FRAME_BEACON;
+
+       /* append WPS IE for Beacon */
+       if (drv->wps_beacon_ie != NULL) {
+               os_memcpy(&(app_ie->app_buf[ie_len]),
+                         wpabuf_head(drv->wps_beacon_ie),
+                         wpabuf_len(drv->wps_beacon_ie));
+               app_ie->app_buflen = ie_len + wpabuf_len(drv->wps_beacon_ie);
+       }
+       wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(Beacon)",
+                   app_ie->app_buf, app_ie->app_buflen);
+       set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie,
+                    sizeof(struct ieee80211req_getset_appiebuf) +
+                    app_ie->app_buflen);
+
+       /* append WPS IE for Probe Response */
+       app_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_RESP;
+       if (drv->wps_probe_resp_ie != NULL) {
+               os_memcpy(&(app_ie->app_buf[ie_len]),
+                         wpabuf_head(drv->wps_probe_resp_ie),
+                         wpabuf_len(drv->wps_probe_resp_ie));
+               app_ie->app_buflen = ie_len +
+                       wpabuf_len(drv->wps_probe_resp_ie);
+       } else
+               app_ie->app_buflen = ie_len;
+       wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(ProbeResp)",
+                   app_ie->app_buf, app_ie->app_buflen);
+       set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie,
+                    sizeof(struct ieee80211req_getset_appiebuf) +
+                    app_ie->app_buflen);
        return 0;
 }
 
 static int
-madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
+atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
                   int reason_code)
 {
-       struct madwifi_driver_data *drv = priv;
+       struct atheros_driver_data *drv = priv;
        struct ieee80211req_mlme mlme;
        int ret;
 
@@ -658,10 +708,10 @@ madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
 }
 
 static int
-madwifi_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
+atheros_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
                     int reason_code)
 {
-       struct madwifi_driver_data *drv = priv;
+       struct atheros_driver_data *drv = priv;
        struct ieee80211req_mlme mlme;
        int ret;
 
@@ -682,10 +732,10 @@ madwifi_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
 }
 
 #ifdef CONFIG_WPS
-static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
+static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
                                size_t len)
 {
-       struct madwifi_driver_data *drv = ctx;
+       struct atheros_driver_data *drv = ctx;
        const struct ieee80211_mgmt *mgmt;
        u16 fc;
        union wpa_event_data event;
@@ -703,6 +753,8 @@ static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
 
        os_memset(&event, 0, sizeof(event));
        event.rx_probe_req.sa = mgmt->sa;
+       event.rx_probe_req.da = mgmt->da;
+       event.rx_probe_req.bssid = mgmt->bssid;
        event.rx_probe_req.ie = mgmt->u.probe_req.variable;
        event.rx_probe_req.ie_len =
                len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
@@ -710,7 +762,7 @@ static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
 }
 #endif /* CONFIG_WPS */
 
-static int madwifi_receive_probe_req(struct madwifi_driver_data *drv)
+static int atheros_receive_probe_req(struct atheros_driver_data *drv)
 {
        int ret = 0;
 #ifdef CONFIG_WPS
@@ -725,7 +777,7 @@ static int madwifi_receive_probe_req(struct madwifi_driver_data *drv)
                return ret;
 
        drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW,
-                                      madwifi_raw_receive, drv, 1);
+                                      atheros_raw_receive, drv, 1);
        if (drv->sock_raw == NULL)
                return -1;
 #endif /* CONFIG_WPS */
@@ -734,43 +786,74 @@ static int madwifi_receive_probe_req(struct madwifi_driver_data *drv)
 
 #ifdef CONFIG_WPS
 static int
-madwifi_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
+atheros_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
 {
-       struct madwifi_driver_data *drv = priv;
-       u8 buf[256];
+       struct atheros_driver_data *drv = priv;
+       u8 buf[512];
        struct ieee80211req_getset_appiebuf *beac_ie;
 
-       wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
-                  (unsigned long) len);
+       wpa_printf(MSG_DEBUG, "%s buflen = %lu frametype=%u", __func__,
+                  (unsigned long) len, frametype);
+       wpa_hexdump(MSG_DEBUG, "atheros: IE", ie, len);
 
        beac_ie = (struct ieee80211req_getset_appiebuf *) buf;
        beac_ie->app_frmtype = frametype;
        beac_ie->app_buflen = len;
-       memcpy(&(beac_ie->app_buf[0]), ie, len);
+       os_memcpy(&(beac_ie->app_buf[0]), ie, len);
+
+       /* append the WPA/RSN IE if it is set already */
+       if (((frametype == IEEE80211_APPIE_FRAME_BEACON) ||
+            (frametype == IEEE80211_APPIE_FRAME_PROBE_RESP)) &&
+           (drv->wpa_ie != NULL)) {
+               wpa_hexdump_buf(MSG_DEBUG, "atheros: Append WPA/RSN IE",
+                               drv->wpa_ie);
+               os_memcpy(&(beac_ie->app_buf[len]), wpabuf_head(drv->wpa_ie),
+                         wpabuf_len(drv->wpa_ie));
+               beac_ie->app_buflen += wpabuf_len(drv->wpa_ie);
+       }
 
+       wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF",
+                   beac_ie->app_buf, beac_ie->app_buflen);
        return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie,
-                           sizeof(struct ieee80211req_getset_appiebuf) + len);
+                           sizeof(struct ieee80211req_getset_appiebuf) +
+                           beac_ie->app_buflen);
 }
 
 static int
-madwifi_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
-                     const struct wpabuf *proberesp)
+atheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
+                     const struct wpabuf *proberesp,
+                     const struct wpabuf *assocresp)
 {
-       if (madwifi_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL,
+       struct atheros_driver_data *drv = priv;
+
+       wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - beacon", beacon);
+       wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - proberesp",
+                       proberesp);
+       wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - assocresp",
+                       assocresp);
+       wpabuf_free(drv->wps_beacon_ie);
+       drv->wps_beacon_ie = beacon ? wpabuf_dup(beacon) : NULL;
+       wpabuf_free(drv->wps_probe_resp_ie);
+       drv->wps_probe_resp_ie = proberesp ? wpabuf_dup(proberesp) : NULL;
+
+       atheros_set_wps_ie(priv, assocresp ? wpabuf_head(assocresp) : NULL,
+                          assocresp ? wpabuf_len(assocresp) : 0,
+                          IEEE80211_APPIE_FRAME_ASSOC_RESP);
+       if (atheros_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL,
                               beacon ? wpabuf_len(beacon) : 0,
                               IEEE80211_APPIE_FRAME_BEACON))
                return -1;
-       return madwifi_set_wps_ie(priv,
+       return atheros_set_wps_ie(priv,
                                  proberesp ? wpabuf_head(proberesp) : NULL,
                                  proberesp ? wpabuf_len(proberesp): 0,
                                  IEEE80211_APPIE_FRAME_PROBE_RESP);
 }
 #else /* CONFIG_WPS */
-#define madwifi_set_ap_wps_ie NULL
+#define atheros_set_ap_wps_ie NULL
 #endif /* CONFIG_WPS */
 
 static void
-madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
+atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
 {
        struct hostapd_data *hapd = drv->hapd;
        struct ieee80211req_wpaie ie;
@@ -791,17 +874,21 @@ madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
                           __func__, strerror(errno));
                goto no_ie;
        }
-       wpa_hexdump(MSG_MSGDUMP, "madwifi req WPA IE",
+       wpa_hexdump(MSG_MSGDUMP, "atheros req WPA IE",
                    ie.wpa_ie, IEEE80211_MAX_OPT_IE);
-       wpa_hexdump(MSG_MSGDUMP, "madwifi req RSN IE",
+       wpa_hexdump(MSG_MSGDUMP, "atheros req RSN IE",
                    ie.rsn_ie, IEEE80211_MAX_OPT_IE);
+#ifdef ATH_WPS_IE
+       wpa_hexdump(MSG_MSGDUMP, "atheros req WPS IE",
+                   ie.wps_ie, IEEE80211_MAX_OPT_IE);
+#endif /* ATH_WPS_IE */
        iebuf = ie.wpa_ie;
-       /* madwifi seems to return some random data if WPA/RSN IE is not set.
+       /* atheros seems to return some random data if WPA/RSN IE is not set.
         * Assume the IE was not included if the IE type is unknown. */
        if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC)
                iebuf[1] = 0;
        if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) {
-               /* madwifi-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not
+               /* atheros-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not
                 * set. This is needed for WPA2. */
                iebuf = ie.rsn_ie;
                if (iebuf[0] != WLAN_EID_RSN)
@@ -809,13 +896,23 @@ madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
        }
 
        ielen = iebuf[1];
+
+#ifdef ATH_WPS_IE
+       /* if WPS IE is present, preference is given to WPS */
+       if (ie.wps_ie &&
+           (ie.wps_ie[1] > 0 && (ie.wps_ie[0] == WLAN_EID_VENDOR_SPECIFIC))) {
+               iebuf = ie.wps_ie;
+               ielen = ie.wps_ie[1];
+       }
+#endif /* ATH_WPS_IE */
+
        if (ielen == 0)
                iebuf = NULL;
        else
                ielen += 2;
 
 no_ie:
-       drv_event_assoc(hapd, addr, iebuf, ielen);
+       drv_event_assoc(hapd, addr, iebuf, ielen, 0);
 
        if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
                /* Cached accounting data is not valid anymore. */
@@ -825,7 +922,7 @@ no_ie:
 }
 
 static void
-madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv,
+atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
                                       char *custom, char *end)
 {
        wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
@@ -897,14 +994,14 @@ madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv,
                                   "length %d", len);
                        return;
                }
-               madwifi_raw_receive(drv, NULL,
+               atheros_raw_receive(drv, NULL,
                                    (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
 #endif /* CONFIG_WPS */
        }
 }
 
 static void
-madwifi_wireless_event_wireless(struct madwifi_driver_data *drv,
+atheros_wireless_event_wireless(struct atheros_driver_data *drv,
                                char *data, int len)
 {
        struct iw_event iwe_buf, *iwe = &iwe_buf;
@@ -943,7 +1040,7 @@ madwifi_wireless_event_wireless(struct madwifi_driver_data *drv,
                                           (u8 *) iwe->u.addr.sa_data);
                        break;
                case IWEVREGISTERED:
-                       madwifi_new_sta(drv, (u8 *) iwe->u.addr.sa_data);
+                       atheros_new_sta(drv, (u8 *) iwe->u.addr.sa_data);
                        break;
                case IWEVASSOCREQIE:
                        /* Driver hack.. Use IWEVASSOCREQIE to bypass
@@ -958,7 +1055,7 @@ madwifi_wireless_event_wireless(struct madwifi_driver_data *drv,
                                return;         /* XXX */
                        memcpy(buf, custom, iwe->u.data.length);
                        buf[iwe->u.data.length] = '\0';
-                       madwifi_wireless_event_wireless_custom(
+                       atheros_wireless_event_wireless_custom(
                                drv, buf, buf + iwe->u.data.length);
                        free(buf);
                        break;
@@ -970,10 +1067,10 @@ madwifi_wireless_event_wireless(struct madwifi_driver_data *drv,
 
 
 static void
-madwifi_wireless_event_rtm_newlink(void *ctx,
+atheros_wireless_event_rtm_newlink(void *ctx,
                                   struct ifinfomsg *ifi, u8 *buf, size_t len)
 {
-       struct madwifi_driver_data *drv = ctx;
+       struct atheros_driver_data *drv = ctx;
        int attrlen, rta_len;
        struct rtattr *attr;
 
@@ -986,7 +1083,7 @@ madwifi_wireless_event_rtm_newlink(void *ctx,
        rta_len = RTA_ALIGN(sizeof(struct rtattr));
        while (RTA_OK(attr, attrlen)) {
                if (attr->rta_type == IFLA_WIRELESS) {
-                       madwifi_wireless_event_wireless(
+                       atheros_wireless_event_wireless(
                                drv, ((char *) attr) + rta_len,
                                attr->rta_len - rta_len);
                }
@@ -996,7 +1093,7 @@ madwifi_wireless_event_rtm_newlink(void *ctx,
 
 
 static int
-madwifi_get_we_version(struct madwifi_driver_data *drv)
+atheros_get_we_version(struct atheros_driver_data *drv)
 {
        struct iw_range *range;
        struct iwreq iwr;
@@ -1036,23 +1133,23 @@ madwifi_get_we_version(struct madwifi_driver_data *drv)
                drv->we_version = range->we_version_compiled;
        }
 
-       free(range);
+       os_free(range);
        return 0;
 }
 
 
 static int
-madwifi_wireless_event_init(struct madwifi_driver_data *drv)
+atheros_wireless_event_init(struct atheros_driver_data *drv)
 {
        struct netlink_config *cfg;
 
-       madwifi_get_we_version(drv);
+       atheros_get_we_version(drv);
 
        cfg = os_zalloc(sizeof(*cfg));
        if (cfg == NULL)
                return -1;
        cfg->ctx = drv;
-       cfg->newlink_cb = madwifi_wireless_event_rtm_newlink;
+       cfg->newlink_cb = atheros_wireless_event_rtm_newlink;
        drv->netlink = netlink_init(cfg);
        if (drv->netlink == NULL) {
                os_free(cfg);
@@ -1064,10 +1161,10 @@ madwifi_wireless_event_init(struct madwifi_driver_data *drv)
 
 
 static int
-madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
-                  int encrypt, const u8 *own_addr)
+atheros_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
+                  int encrypt, const u8 *own_addr, u32 flags)
 {
-       struct madwifi_driver_data *drv = priv;
+       struct atheros_driver_data *drv = priv;
        unsigned char buf[3000];
        unsigned char *bp = buf;
        struct l2_ethhdr *eth;
@@ -1107,22 +1204,22 @@ madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
 static void
 handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
 {
-       struct madwifi_driver_data *drv = ctx;
+       struct atheros_driver_data *drv = ctx;
        drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr),
                           len - sizeof(struct l2_ethhdr));
 }
 
 static void *
-madwifi_init(struct hostapd_data *hapd, struct wpa_init_params *params)
+atheros_init(struct hostapd_data *hapd, struct wpa_init_params *params)
 {
-       struct madwifi_driver_data *drv;
+       struct atheros_driver_data *drv;
        struct ifreq ifr;
        struct iwreq iwr;
        char brname[IFNAMSIZ];
 
-       drv = os_zalloc(sizeof(struct madwifi_driver_data));
+       drv = os_zalloc(sizeof(struct atheros_driver_data));
        if (drv == NULL) {
-               printf("Could not allocate memory for madwifi driver data\n");
+               printf("Could not allocate memory for atheros driver data\n");
                return NULL;
        }
 
@@ -1179,11 +1276,11 @@ madwifi_init(struct hostapd_data *hapd, struct wpa_init_params *params)
 
        /* mark down during setup */
        linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
-       madwifi_set_privacy(drv, 0); /* default to no privacy */
+       atheros_set_privacy(drv, 0); /* default to no privacy */
 
-       madwifi_receive_probe_req(drv);
+       atheros_receive_probe_req(drv);
 
-       if (madwifi_wireless_event_init(drv))
+       if (atheros_wireless_event_init(drv))
                goto bad;
 
        return drv;
@@ -1201,9 +1298,9 @@ bad:
 
 
 static void
-madwifi_deinit(void *priv)
+atheros_deinit(void *priv)
 {
-       struct madwifi_driver_data *drv = priv;
+       struct atheros_driver_data *drv = priv;
 
        netlink_deinit(drv->netlink);
        (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
@@ -1215,13 +1312,16 @@ madwifi_deinit(void *priv)
                l2_packet_deinit(drv->sock_xmit);
        if (drv->sock_raw)
                l2_packet_deinit(drv->sock_raw);
+       wpabuf_free(drv->wpa_ie);
+       wpabuf_free(drv->wps_beacon_ie);
+       wpabuf_free(drv->wps_probe_resp_ie);
        free(drv);
 }
 
 static int
-madwifi_set_ssid(void *priv, const u8 *buf, int len)
+atheros_set_ssid(void *priv, const u8 *buf, int len)
 {
-       struct madwifi_driver_data *drv = priv;
+       struct atheros_driver_data *drv = priv;
        struct iwreq iwr;
 
        memset(&iwr, 0, sizeof(iwr));
@@ -1239,9 +1339,9 @@ madwifi_set_ssid(void *priv, const u8 *buf, int len)
 }
 
 static int
-madwifi_get_ssid(void *priv, u8 *buf, int len)
+atheros_get_ssid(void *priv, u8 *buf, int len)
 {
-       struct madwifi_driver_data *drv = priv;
+       struct atheros_driver_data *drv = priv;
        struct iwreq iwr;
        int ret = 0;
 
@@ -1249,6 +1349,8 @@ madwifi_get_ssid(void *priv, u8 *buf, int len)
        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;
 
        if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
                perror("ioctl[SIOCGIWESSID]");
@@ -1260,39 +1362,86 @@ madwifi_get_ssid(void *priv, u8 *buf, int len)
 }
 
 static int
-madwifi_set_countermeasures(void *priv, int enabled)
+atheros_set_countermeasures(void *priv, int enabled)
 {
-       struct madwifi_driver_data *drv = priv;
+       struct atheros_driver_data *drv = priv;
        wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
        return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled);
 }
 
 static int
-madwifi_commit(void *priv)
+atheros_commit(void *priv)
 {
-       struct madwifi_driver_data *drv = priv;
+       struct atheros_driver_data *drv = priv;
        return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);
 }
 
+static int atheros_set_authmode(void *priv, int auth_algs)
+{
+       int authmode;
+
+       if ((auth_algs & WPA_AUTH_ALG_OPEN) &&
+           (auth_algs & WPA_AUTH_ALG_SHARED))
+               authmode = IEEE80211_AUTH_AUTO;
+       else if (auth_algs & WPA_AUTH_ALG_OPEN)
+               authmode = IEEE80211_AUTH_OPEN;
+       else if (auth_algs & WPA_AUTH_ALG_SHARED)
+               authmode = IEEE80211_AUTH_SHARED;
+       else
+               return -1;
+
+       return set80211param(priv, IEEE80211_PARAM_AUTHMODE, authmode);
+}
+
+static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params)
+{
+       /*
+        * TODO: Use this to replace set_authmode, set_privacy, set_ieee8021x,
+        * set_generic_elem, and hapd_set_ssid.
+        */
+
+       wpa_printf(MSG_DEBUG, "atheros: set_ap - pairwise_ciphers=0x%x "
+                  "group_cipher=0x%x key_mgmt_suites=0x%x auth_algs=0x%x "
+                  "wpa_version=0x%x privacy=%d interworking=%d",
+                  params->pairwise_ciphers, params->group_cipher,
+                  params->key_mgmt_suites, params->auth_algs,
+                  params->wpa_version, params->privacy, params->interworking);
+       wpa_hexdump_ascii(MSG_DEBUG, "atheros: SSID",
+                         params->ssid, params->ssid_len);
+       if (params->hessid)
+               wpa_printf(MSG_DEBUG, "atheros: HESSID " MACSTR,
+                          MAC2STR(params->hessid));
+       wpa_hexdump_buf(MSG_DEBUG, "atheros: beacon_ies",
+                       params->beacon_ies);
+       wpa_hexdump_buf(MSG_DEBUG, "atheros: proberesp_ies",
+                       params->proberesp_ies);
+       wpa_hexdump_buf(MSG_DEBUG, "atheros: assocresp_ies",
+                       params->assocresp_ies);
+
+       return 0;
+}
+
 const struct wpa_driver_ops wpa_driver_atheros_ops = {
        .name                   = "atheros",
-       .hapd_init              = madwifi_init,
-       .hapd_deinit            = madwifi_deinit,
-       .set_ieee8021x          = madwifi_set_ieee8021x,
-       .set_privacy            = madwifi_set_privacy,
-       .set_key                = madwifi_set_key,
-       .get_seqnum             = madwifi_get_seqnum,
-       .flush                  = madwifi_flush,
-       .set_generic_elem       = madwifi_set_opt_ie,
-       .sta_set_flags          = madwifi_sta_set_flags,
-       .read_sta_data          = madwifi_read_sta_driver_data,
-       .hapd_send_eapol        = madwifi_send_eapol,
-       .sta_disassoc           = madwifi_sta_disassoc,
-       .sta_deauth             = madwifi_sta_deauth,
-       .hapd_set_ssid          = madwifi_set_ssid,
-       .hapd_get_ssid          = madwifi_get_ssid,
-       .set_countermeasures    = madwifi_set_countermeasures,
-       .sta_clear_stats        = madwifi_sta_clear_stats,
-       .commit                 = madwifi_commit,
-       .set_ap_wps_ie          = madwifi_set_ap_wps_ie,
+       .hapd_init              = atheros_init,
+       .hapd_deinit            = atheros_deinit,
+       .set_ieee8021x          = atheros_set_ieee8021x,
+       .set_privacy            = atheros_set_privacy,
+       .set_key                = atheros_set_key,
+       .get_seqnum             = atheros_get_seqnum,
+       .flush                  = atheros_flush,
+       .set_generic_elem       = atheros_set_opt_ie,
+       .sta_set_flags          = atheros_sta_set_flags,
+       .read_sta_data          = atheros_read_sta_driver_data,
+       .hapd_send_eapol        = atheros_send_eapol,
+       .sta_disassoc           = atheros_sta_disassoc,
+       .sta_deauth             = atheros_sta_deauth,
+       .hapd_set_ssid          = atheros_set_ssid,
+       .hapd_get_ssid          = atheros_get_ssid,
+       .set_countermeasures    = atheros_set_countermeasures,
+       .sta_clear_stats        = atheros_sta_clear_stats,
+       .commit                 = atheros_commit,
+       .set_ap_wps_ie          = atheros_set_ap_wps_ie,
+       .set_authmode           = atheros_set_authmode,
+       .set_ap                 = atheros_set_ap,
 };
diff --git a/src/drivers/driver_atmel.c b/src/drivers/driver_atmel.c
deleted file mode 100644 (file)
index cbec6c3..0000000
+++ /dev/null
@@ -1,499 +0,0 @@
-/*
- * WPA Supplicant - Driver interaction with Atmel Wireless LAN drivers
- * Copyright (c) 2000-2005, ATMEL Corporation
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-/******************************************************************************
-       Copyright 2000-2001 ATMEL Corporation.
-       
-    WPA Supplicant - driver interaction with Atmel Wireless lan drivers.
-    
-    This is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with Atmel wireless lan drivers; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-
-******************************************************************************/
-
-/*
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-
-#include "wireless_copy.h"
-#include "common.h"
-#include "driver.h"
-#include "driver_wext.h"
-
-struct wpa_driver_atmel_data {
-       void *wext; /* private data for driver_wext */
-       void *ctx;
-       char ifname[IFNAMSIZ + 1];
-       int sock;
-};
-
-
-#define ATMEL_WPA_IOCTL                (SIOCIWFIRSTPRIV + 2)
-#define ATMEL_WPA_IOCTL_PARAM          (SIOCIWFIRSTPRIV + 3)
-#define ATMEL_WPA_IOCTL_GET_PARAM      (SIOCIWFIRSTPRIV + 4)
-
-
-/* ATMEL_WPA_IOCTL ioctl() cmd: */
-enum {
-    SET_WPA_ENCRYPTION  = 1,
-    SET_CIPHER_SUITES   = 2,
-    MLME_STA_DEAUTH     = 3,
-    MLME_STA_DISASSOC   = 4
-};
-
-/* ATMEL_WPA_IOCTL_PARAM ioctl() cmd: */
-enum {
-            ATMEL_PARAM_WPA = 1,
-            ATMEL_PARAM_PRIVACY_INVOKED = 2,
-            ATMEL_PARAM_WPA_TYPE = 3
-};
-
-#define MAX_KEY_LENGTH      40
-
-struct atmel_param{
-    unsigned char sta_addr[6];
-        int     cmd;
-        u8      alg;
-        u8      key_idx;
-        u8      set_tx;
-        u8      seq[8];
-        u8      seq_len;
-        u16     key_len;
-        u8      key[MAX_KEY_LENGTH];
-    struct{
-        int     reason_code;
-        u8      state;
-    }mlme;
-    u8          pairwise_suite;
-    u8          group_suite;
-    u8          key_mgmt_suite;
-};
-
-    
-    
-static int atmel_ioctl(struct wpa_driver_atmel_data *drv,
-                      struct atmel_param *param,
-                      int len, int show_err)
-{
-       struct iwreq iwr;
-
-       os_memset(&iwr, 0, sizeof(iwr));
-       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-       iwr.u.data.pointer = (caddr_t) param;
-       iwr.u.data.length = len;
-
-       if (ioctl(drv->sock, ATMEL_WPA_IOCTL, &iwr) < 0) {
-               int ret;
-               ret = errno;
-               if (show_err) 
-                       perror("ioctl[ATMEL_WPA_IOCTL]");
-               return ret;
-       }
-
-       return 0;
-}
-
-
-static int atmel2param(struct wpa_driver_atmel_data *drv, int param, int value)
-{
-       struct iwreq iwr;
-       int *i, ret = 0;
-
-       os_memset(&iwr, 0, sizeof(iwr));
-       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-       i = (int *) iwr.u.name;
-       *i++ = param;
-       *i++ = value;
-
-       if (ioctl(drv->sock, ATMEL_WPA_IOCTL_PARAM, &iwr) < 0) {
-               perror("ioctl[ATMEL_WPA_IOCTL_PARAM]");
-               ret = -1;
-       }
-       return ret;
-}
-
-
-#if 0
-static int wpa_driver_atmel_set_wpa_ie(struct wpa_driver_atmel_data *drv,
-                                      const char *wpa_ie, size_t wpa_ie_len)
-{
-       struct atmel_param *param;
-       int res;
-       size_t blen = ATMEL_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
-       if (blen < sizeof(*param))
-               blen = sizeof(*param);
-
-       param = os_zalloc(blen);
-       if (param == NULL)
-               return -1;
-
-       param->cmd = ATMEL_SET_GENERIC_ELEMENT;
-       param->u.generic_elem.len = wpa_ie_len;
-       os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
-       res = atmel_ioctl(drv, param, blen, 1);
-
-       os_free(param);
-
-       return res;
-}
-#endif
-
-
-static int wpa_driver_atmel_set_wpa(void *priv, int enabled)
-{
-       struct wpa_driver_atmel_data *drv = priv;
-        int ret = 0;
-       
-        printf("wpa_driver_atmel_set_wpa %s\n", drv->ifname);
-
-       wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-
-#if 0
-       if (!enabled && wpa_driver_atmel_set_wpa_ie(drv, NULL, 0) < 0)
-               ret = -1;
-#endif
-       if (atmel2param(drv, ATMEL_PARAM_PRIVACY_INVOKED, enabled) < 0)
-               ret = -1;
-       if (atmel2param(drv, ATMEL_PARAM_WPA, enabled) < 0)
-               ret = -1;
-
-       return ret;
-}
-
-
-static int wpa_driver_atmel_set_key(const char *ifname, void *priv,
-                                   enum wpa_alg alg, const u8 *addr,
-                                   int key_idx, int set_tx,
-                                   const u8 *seq, size_t seq_len,
-                                   const u8 *key, size_t key_len)
-{
-       struct wpa_driver_atmel_data *drv = priv;
-       int ret = 0;
-        struct atmel_param *param;
-       u8 *buf;
-        u8 alg_type;
-        
-       size_t blen;
-       char *alg_name;
-
-       switch (alg) {
-       case WPA_ALG_NONE:
-               alg_name = "none";
-                alg_type = 0;
-               break;
-       case WPA_ALG_WEP:
-               alg_name = "WEP";
-               alg_type = 1;
-                break;
-       case WPA_ALG_TKIP:
-               alg_name = "TKIP";
-               alg_type = 2;
-                break;
-       case WPA_ALG_CCMP:
-               alg_name = "CCMP";
-               alg_type = 3;
-                break;
-       default:
-               return -1;
-       }
-
-       wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
-                  "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
-                  (unsigned long) seq_len, (unsigned long) key_len);
-
-       if (seq_len > 8)
-               return -2;
-
-       blen = sizeof(*param) + key_len;
-       buf = os_zalloc(blen);
-       if (buf == NULL)
-               return -1;
-
-       param = (struct atmel_param *) buf;
-        
-        param->cmd = SET_WPA_ENCRYPTION; 
-        
-        if (addr == NULL)
-               os_memset(param->sta_addr, 0xff, ETH_ALEN);
-       else
-               os_memcpy(param->sta_addr, addr, ETH_ALEN);
-        
-        param->alg = alg_type;
-        param->key_idx = key_idx;
-        param->set_tx = set_tx;
-        os_memcpy(param->seq, seq, seq_len);
-        param->seq_len = seq_len;
-        param->key_len = key_len;
-       os_memcpy((u8 *)param->key, key, key_len);
-       
-        if (atmel_ioctl(drv, param, blen, 1)) {
-               wpa_printf(MSG_WARNING, "Failed to set encryption.");
-               /* TODO: show key error*/
-               ret = -1;
-       }
-       os_free(buf);
-
-       return ret;
-}
-
-
-static int wpa_driver_atmel_set_countermeasures(void *priv,
-                                                int enabled)
-{
-       /* FIX */
-       printf("wpa_driver_atmel_set_countermeasures - not yet "
-              "implemented\n");
-       return 0;
-}
-
-
-static int wpa_driver_atmel_mlme(void *priv, const u8 *addr, int cmd,
-                                int reason_code)
-{
-       struct wpa_driver_atmel_data *drv = priv;
-       struct atmel_param param;
-       int ret;
-        int mgmt_error = 0xaa;
-        
-       os_memset(&param, 0, sizeof(param));
-       os_memcpy(param.sta_addr, addr, ETH_ALEN);
-       param.cmd = cmd;
-       param.mlme.reason_code = reason_code;
-        param.mlme.state = mgmt_error;
-       ret = atmel_ioctl(drv, &param, sizeof(param), 1);
-       return ret;
-}
-
-
-#if 0
-static int wpa_driver_atmel_set_suites(struct wpa_driver_atmel_data *drv,
-                                      u8 pairwise_suite, u8 group_suite,
-                                      u8 key_mgmt_suite)
-{
-       struct atmel_param param;
-       int ret;
-        
-       os_memset(&param, 0, sizeof(param));
-        param.cmd = SET_CIPHER_SUITES;
-        param.pairwise_suite = pairwise_suite;
-        param.group_suite = group_suite;
-        param.key_mgmt_suite = key_mgmt_suite;
-               
-       ret = atmel_ioctl(drv, &param, sizeof(param), 1);
-       return ret;
-}
-#endif
-
-
-static int wpa_driver_atmel_deauthenticate(void *priv, const u8 *addr,
-                                          int reason_code)
-{
-       struct wpa_driver_atmel_data *drv = priv;
-       printf("wpa_driver_atmel_deauthenticate\n");
-        wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-       return wpa_driver_atmel_mlme(drv, addr, MLME_STA_DEAUTH,
-                                    reason_code);
-
-}
-
-
-static int wpa_driver_atmel_disassociate(void *priv, const u8 *addr,
-                                        int reason_code)
-{
-       struct wpa_driver_atmel_data *drv = priv;
-       printf("wpa_driver_atmel_disassociate\n");
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-       return wpa_driver_atmel_mlme(drv, addr, MLME_STA_DISASSOC,
-                                    reason_code);
-
-}
-
-
-#if 0
-/* Atmel driver uses specific values for each cipher suite */
-static int convertSuiteToDriver(enum wpa_cipher suite)
-{
-    u8 suite_type;
-    
-    switch(suite) {
-        case CIPHER_NONE:
-                suite_type =  0;
-                break;
-        case CIPHER_WEP40:
-                suite_type =  1;
-                break;
-        case CIPHER_TKIP:
-                suite_type = 2;
-                break;
-        case CIPHER_WEP104:
-                suite_type = 5;
-                break;
-        case CIPHER_CCMP:
-                suite_type = 3;
-                break;
-        default:
-                suite_type = 2;
-    }
-    
-    return suite_type;
-
-}
-#endif
-    
-static int
-wpa_driver_atmel_associate(void *priv,
-                          struct wpa_driver_associate_params *params)
-{
-       struct wpa_driver_atmel_data *drv = priv;
-       int ret = 0;
-#if 0
-        u8 pairwise_suite_driver;
-        u8 group_suite_driver;
-        u8 key_mgmt_suite_driver;
-
-        pairwise_suite_driver = convertSuiteToDriver(params->pairwise_suite);
-        group_suite_driver    = convertSuiteToDriver(params->group_suite);
-        key_mgmt_suite_driver = convertSuiteToDriver(params->key_mgmt_suite);
-
-        if (wpa_driver_atmel_set_suites(drv, pairwise_suite_driver,
-                                       group_suite_driver,
-                                       key_mgmt_suite_driver) < 0){
-               printf("wpa_driver_atmel_set_suites.\n");
-                ret = -1;
-        }
-        if (wpa_driver_wext_set_freq(drv->wext, params->freq) < 0) {
-               printf("wpa_driver_atmel_set_freq.\n");
-               ret = -1;
-        }
-#endif
-       if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, params->ssid_len)
-           < 0) {
-               printf("FAILED : wpa_driver_atmel_set_ssid.\n");
-               ret = -1;
-        }
-       if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0) {
-               printf("FAILED : wpa_driver_atmel_set_bssid.\n");
-               ret = -1;
-        }
-
-       return ret;
-}
-
-
-static int wpa_driver_atmel_get_bssid(void *priv, u8 *bssid)
-{
-       struct wpa_driver_atmel_data *drv = priv;
-       return wpa_driver_wext_get_bssid(drv->wext, bssid);
-}
-
-
-static int wpa_driver_atmel_get_ssid(void *priv, u8 *ssid)
-{
-       struct wpa_driver_atmel_data *drv = priv;
-       return wpa_driver_wext_get_ssid(drv->wext, ssid);
-}
-
-
-static int wpa_driver_atmel_scan(void *priv,
-                                struct wpa_driver_scan_params *params)
-{
-       struct wpa_driver_atmel_data *drv = priv;
-       return wpa_driver_wext_scan(drv->wext, params);
-}
-
-
-static struct wpa_scan_results * wpa_driver_atmel_get_scan_results(void *priv)
-{
-       struct wpa_driver_atmel_data *drv = priv;
-       return wpa_driver_wext_get_scan_results(drv->wext);
-}
-
-
-static int wpa_driver_atmel_set_operstate(void *priv, int state)
-{
-       struct wpa_driver_atmel_data *drv = priv;
-       return wpa_driver_wext_set_operstate(drv->wext, state);
-}
-
-
-static void * wpa_driver_atmel_init(void *ctx, const char *ifname)
-{
-       struct wpa_driver_atmel_data *drv;
-
-       drv = os_zalloc(sizeof(*drv));
-       if (drv == NULL)
-               return NULL;
-       drv->wext = wpa_driver_wext_init(ctx, ifname);
-       if (drv->wext == NULL) {
-               os_free(drv);
-               return NULL;
-       }
-
-       drv->ctx = ctx;
-       os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-       drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-       if (drv->sock < 0) {
-               wpa_driver_wext_deinit(drv->wext);
-               os_free(drv);
-               return NULL;
-       }
-
-       wpa_driver_atmel_set_wpa(drv, 1);
-
-       return drv;
-}
-
-
-static void wpa_driver_atmel_deinit(void *priv)
-{
-       struct wpa_driver_atmel_data *drv = priv;
-       wpa_driver_atmel_set_wpa(drv, 0);
-       wpa_driver_wext_deinit(drv->wext);
-       close(drv->sock);
-       os_free(drv);
-}
-
-
-const struct wpa_driver_ops wpa_driver_atmel_ops = {
-       .name = "atmel",
-       .desc = "ATMEL AT76C5XXx (USB, PCMCIA)",
-       .get_bssid = wpa_driver_atmel_get_bssid,
-       .get_ssid = wpa_driver_atmel_get_ssid,
-       .set_key = wpa_driver_atmel_set_key,
-       .init = wpa_driver_atmel_init,
-       .deinit = wpa_driver_atmel_deinit,
-       .set_countermeasures = wpa_driver_atmel_set_countermeasures,
-       .scan2 = wpa_driver_atmel_scan,
-       .get_scan_results2 = wpa_driver_atmel_get_scan_results,
-       .deauthenticate = wpa_driver_atmel_deauthenticate,
-       .disassociate = wpa_driver_atmel_disassociate,
-       .associate = wpa_driver_atmel_associate,
-       .set_operstate = wpa_driver_atmel_set_operstate,
-};
diff --git a/src/drivers/driver_broadcom.c b/src/drivers/driver_broadcom.c
deleted file mode 100644 (file)
index cb88543..0000000
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
- * WPA Supplicant - driver interaction with old Broadcom wl.o driver
- * Copyright (c) 2004, Nikki Chumkov <nikki@gattaca.ru>
- * 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.
- *
- * Please note that the newer Broadcom driver ("hybrid Linux driver") supports
- * Linux wireless extensions and does not need (or even work) with this old
- * driver wrapper. Use driver_wext.c with that driver.
- */
-
-#include "includes.h"
-
-#include <sys/ioctl.h>
-
-#include "common.h"
-
-#if 0
-#include <netpacket/packet.h>
-#include <net/ethernet.h>     /* the L2 protocols */
-#else
-#include <linux/if_packet.h>
-#include <linux/if_ether.h>   /* The L2 protocols */
-#endif
-#include <net/if.h>
-#include <typedefs.h>
-
-/* wlioctl.h is a Broadcom header file and it is available, e.g., from Linksys
- * WRT54G GPL tarball. */
-#include <wlioctl.h>
-
-#include "driver.h"
-#include "eloop.h"
-
-struct wpa_driver_broadcom_data {
-       void *ctx;
-       int ioctl_sock;
-       int event_sock;
-       char ifname[IFNAMSIZ + 1];
-};
-
-
-#ifndef WLC_DEAUTHENTICATE
-#define WLC_DEAUTHENTICATE 143
-#endif
-#ifndef WLC_DEAUTHENTICATE_WITH_REASON
-#define WLC_DEAUTHENTICATE_WITH_REASON 201
-#endif
-#ifndef WLC_SET_TKIP_COUNTERMEASURES
-#define WLC_SET_TKIP_COUNTERMEASURES 202
-#endif
-
-#if !defined(PSK_ENABLED) /* NEW driver interface */
-#define WL_VERSION 360130
-/* wireless authentication bit vector */
-#define WPA_ENABLED 1
-#define PSK_ENABLED 2
-                                                                                
-#define WAUTH_WPA_ENABLED(wauth)  ((wauth) & WPA_ENABLED)
-#define WAUTH_PSK_ENABLED(wauth)  ((wauth) & PSK_ENABLED)
-#define WAUTH_ENABLED(wauth)    ((wauth) & (WPA_ENABLED | PSK_ENABLED))
-
-#define WSEC_PRIMARY_KEY WL_PRIMARY_KEY
-
-typedef wl_wsec_key_t wsec_key_t;
-#endif
-
-typedef struct {
-       uint32 val;
-       struct ether_addr ea;
-       uint16 res;
-} wlc_deauth_t;
-
-
-static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
-                                            void *timeout_ctx);
-
-static int broadcom_ioctl(struct wpa_driver_broadcom_data *drv, int cmd,
-                         void *buf, int len)
-{
-       struct ifreq ifr;
-       wl_ioctl_t ioc;
-       int ret = 0;
-
-       wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl(%s,%d,len=%d,val=%p)",
-                  drv->ifname, cmd, len, buf);
-       /* wpa_hexdump(MSG_MSGDUMP, "BROADCOM: wlioctl buf", buf, len); */
-
-       ioc.cmd = cmd;
-       ioc.buf = buf;
-       ioc.len = len;
-       os_strlcpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
-       ifr.ifr_data = (caddr_t) &ioc;
-       if ((ret = ioctl(drv->ioctl_sock, SIOCDEVPRIVATE, &ifr)) < 0) {
-               if (cmd != WLC_GET_MAGIC)
-                       perror(ifr.ifr_name);
-               wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl cmd=%d res=%d",
-                          cmd, ret);
-       }
-
-       return ret;
-}
-
-static int wpa_driver_broadcom_get_bssid(void *priv, u8 *bssid)
-{
-       struct wpa_driver_broadcom_data *drv = priv;
-       if (broadcom_ioctl(drv, WLC_GET_BSSID, bssid, ETH_ALEN) == 0)
-               return 0;
-       
-       os_memset(bssid, 0, ETH_ALEN);
-       return -1;
-}
-
-static int wpa_driver_broadcom_get_ssid(void *priv, u8 *ssid)
-{
-       struct wpa_driver_broadcom_data *drv = priv;
-       wlc_ssid_t s;
-       
-       if (broadcom_ioctl(drv, WLC_GET_SSID, &s, sizeof(s)) == -1)
-               return -1;
-
-       os_memcpy(ssid, s.SSID, s.SSID_len);
-       return s.SSID_len;
-}
-
-static int wpa_driver_broadcom_set_wpa(void *priv, int enable)
-{
-       struct wpa_driver_broadcom_data *drv = priv;
-       unsigned int wauth, wsec;
-       struct ether_addr ea;
-
-       os_memset(&ea, enable ? 0xff : 0, sizeof(ea));
-       if (broadcom_ioctl(drv, WLC_GET_WPA_AUTH, &wauth, sizeof(wauth)) ==
-           -1 ||
-           broadcom_ioctl(drv, WLC_GET_WSEC, &wsec, sizeof(wsec)) == -1)
-               return -1;
-
-       if (enable) {
-               wauth = PSK_ENABLED;
-               wsec = TKIP_ENABLED;
-       } else {
-               wauth = 255;
-               wsec &= ~(TKIP_ENABLED | AES_ENABLED);
-       }
-
-       if (broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wauth, sizeof(wauth)) ==
-           -1 ||
-           broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) == -1)
-               return -1;
-
-       /* FIX: magic number / error handling? */
-       broadcom_ioctl(drv, 122, &ea, sizeof(ea));
-
-       return 0;
-}
-
-static int wpa_driver_broadcom_set_key(const char *ifname, void *priv,
-                                      enum wpa_alg alg,
-                                      const u8 *addr, int key_idx, int set_tx,
-                                      const u8 *seq, size_t seq_len,
-                                      const u8 *key, size_t key_len)
-{
-       struct wpa_driver_broadcom_data *drv = priv;
-       int ret;
-       wsec_key_t wkt;
-
-       os_memset(&wkt, 0, sizeof wkt);
-       wpa_printf(MSG_MSGDUMP, "BROADCOM: SET %sKEY[%d] alg=%d",
-                  set_tx ? "PRIMARY " : "", key_idx, alg);
-       if (key && key_len > 0)
-               wpa_hexdump_key(MSG_MSGDUMP, "BROADCOM: key", key, key_len);
-
-       switch (alg) {
-       case WPA_ALG_NONE:
-               wkt.algo = CRYPTO_ALGO_OFF;
-               break;
-       case WPA_ALG_WEP:
-               wkt.algo = CRYPTO_ALGO_WEP128; /* CRYPTO_ALGO_WEP1? */
-               break;
-       case WPA_ALG_TKIP:
-               wkt.algo = 0; /* CRYPTO_ALGO_TKIP? */
-               break;
-       case WPA_ALG_CCMP:
-               wkt.algo = 0; /* CRYPTO_ALGO_AES_CCM;
-                              * AES_OCB_MSDU, AES_OCB_MPDU? */
-               break;
-       default:
-               wkt.algo = CRYPTO_ALGO_NALG;
-               break;
-       }
-
-       if (seq && seq_len > 0)
-               wpa_hexdump(MSG_MSGDUMP, "BROADCOM: SEQ", seq, seq_len);
-
-       if (addr)
-               wpa_hexdump(MSG_MSGDUMP, "BROADCOM: addr", addr, ETH_ALEN);
-
-       wkt.index = key_idx;
-       wkt.len = key_len;
-       if (key && key_len > 0) {
-               os_memcpy(wkt.data, key, key_len);
-               if (key_len == 32) {
-                       /* hack hack hack XXX */
-                       os_memcpy(&wkt.data[16], &key[24], 8);
-                       os_memcpy(&wkt.data[24], &key[16], 8);
-               }
-       }
-       /* wkt.algo = CRYPTO_ALGO_...; */
-       wkt.flags = set_tx ? 0 : WSEC_PRIMARY_KEY;
-       if (addr && set_tx)
-               os_memcpy(&wkt.ea, addr, sizeof(wkt.ea));
-       ret = broadcom_ioctl(drv, WLC_SET_KEY, &wkt, sizeof(wkt));
-       if (addr && set_tx) {
-               /* FIX: magic number / error handling? */
-               broadcom_ioctl(drv, 121, &wkt.ea, sizeof(wkt.ea));
-       }
-       return ret;
-}
-
-
-static void wpa_driver_broadcom_event_receive(int sock, void *ctx,
-                                             void *sock_ctx)
-{
-       char buf[8192];
-       int left;
-       wl_wpa_header_t *wwh;
-       union wpa_event_data data;
-       u8 *resp_ies = NULL;
-
-       if ((left = recv(sock, buf, sizeof buf, 0)) < 0)
-               return;
-
-       wpa_hexdump(MSG_DEBUG, "RECEIVE EVENT", (u8 *) buf, left);
-
-       if ((size_t) left < sizeof(wl_wpa_header_t))
-               return;
-
-       wwh = (wl_wpa_header_t *) buf;
-
-       if (wwh->snap.type != WL_WPA_ETHER_TYPE)
-               return;
-       if (os_memcmp(&wwh->snap, wl_wpa_snap_template, 6) != 0)
-               return;
-
-       os_memset(&data, 0, sizeof(data));
-
-       switch (wwh->type) {
-       case WLC_ASSOC_MSG:
-               left -= WL_WPA_HEADER_LEN;
-               wpa_printf(MSG_DEBUG, "BROADCOM: ASSOC MESSAGE (left: %d)",
-                          left);
-               if (left > 0) {
-                       resp_ies = os_malloc(left);
-                       if (resp_ies == NULL)
-                               return;
-                       os_memcpy(resp_ies, buf + WL_WPA_HEADER_LEN, left);
-                       data.assoc_info.resp_ies = resp_ies;
-                       data.assoc_info.resp_ies_len = left;
-               }
-
-               wpa_supplicant_event(ctx, EVENT_ASSOC, &data);
-               os_free(resp_ies);
-               break;
-       case WLC_DISASSOC_MSG:
-               wpa_printf(MSG_DEBUG, "BROADCOM: DISASSOC MESSAGE");
-               wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
-               break;
-       case WLC_PTK_MIC_MSG:
-               wpa_printf(MSG_DEBUG, "BROADCOM: PTK MIC MSG MESSAGE");
-               data.michael_mic_failure.unicast = 1;
-               wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
-               break;
-       case WLC_GTK_MIC_MSG:
-               wpa_printf(MSG_DEBUG, "BROADCOM: GTK MIC MSG MESSAGE");
-               data.michael_mic_failure.unicast = 0;
-               wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
-               break;
-       default:
-               wpa_printf(MSG_DEBUG, "BROADCOM: UNKNOWN MESSAGE (%d)",
-                          wwh->type);
-               break;
-       }
-}      
-
-static void * wpa_driver_broadcom_init(void *ctx, const char *ifname)
-{
-       int s;
-       struct sockaddr_ll ll;
-       struct wpa_driver_broadcom_data *drv;
-       struct ifreq ifr;
-
-       /* open socket to kernel */
-       if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-               perror("socket");
-               return NULL;
-       }
-       /* do it */
-       os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-       if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
-               perror(ifr.ifr_name);
-               return NULL;
-       }
-
-
-       drv = os_zalloc(sizeof(*drv));
-       if (drv == NULL)
-               return NULL;
-       drv->ctx = ctx;
-       os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-       drv->ioctl_sock = s;
-
-       s = socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2));
-       if (s < 0) {
-               perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
-               close(drv->ioctl_sock);
-               os_free(drv);
-               return NULL;
-       }
-
-       os_memset(&ll, 0, sizeof(ll));
-       ll.sll_family = AF_PACKET;
-       ll.sll_protocol = ntohs(ETH_P_802_2);
-       ll.sll_ifindex = ifr.ifr_ifindex;
-       ll.sll_hatype = 0;
-       ll.sll_pkttype = PACKET_HOST;
-       ll.sll_halen = 0;
-
-       if (bind(s, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
-               perror("bind(netlink)");
-               close(s);
-               close(drv->ioctl_sock);
-               os_free(drv);
-               return NULL;
-       }
-
-       eloop_register_read_sock(s, wpa_driver_broadcom_event_receive, ctx,
-                                NULL);
-       drv->event_sock = s;
-       wpa_driver_broadcom_set_wpa(drv, 1);
-
-       return drv;
-}
-
-static void wpa_driver_broadcom_deinit(void *priv)
-{
-       struct wpa_driver_broadcom_data *drv = priv;
-       wpa_driver_broadcom_set_wpa(drv, 0);
-       eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
-       eloop_unregister_read_sock(drv->event_sock);
-       close(drv->event_sock);
-       close(drv->ioctl_sock);
-       os_free(drv);
-}
-
-static int wpa_driver_broadcom_set_countermeasures(void *priv,
-                                                  int enabled)
-{
-#if 0
-       struct wpa_driver_broadcom_data *drv = priv;
-       /* FIX: ? */
-       return broadcom_ioctl(drv, WLC_SET_TKIP_COUNTERMEASURES, &enabled,
-                             sizeof(enabled));
-#else
-       return 0;
-#endif
-}
-
-static int wpa_driver_broadcom_set_drop_unencrypted(void *priv, int enabled)
-{
-       struct wpa_driver_broadcom_data *drv = priv;
-       /* SET_EAP_RESTRICT, SET_WEP_RESTRICT */
-       int _restrict = (enabled ? 1 : 0);
-       
-       if (broadcom_ioctl(drv, WLC_SET_WEP_RESTRICT, 
-                          &_restrict, sizeof(_restrict)) < 0 ||
-           broadcom_ioctl(drv, WLC_SET_EAP_RESTRICT,
-                          &_restrict, sizeof(_restrict)) < 0)
-               return -1;
-
-       return 0;
-}
-
-static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
-                                            void *timeout_ctx)
-{
-       wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
-       wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-static int wpa_driver_broadcom_scan(void *priv,
-                                   struct wpa_driver_scan_params *params)
-{
-       struct wpa_driver_broadcom_data *drv = priv;
-       wlc_ssid_t wst = { 0, "" };
-       const u8 *ssid = params->ssids[0].ssid;
-       size_t ssid_len = params->ssids[0].ssid_len;
-
-       if (ssid && ssid_len > 0 && ssid_len <= sizeof(wst.SSID)) {
-               wst.SSID_len = ssid_len;
-               os_memcpy(wst.SSID, ssid, ssid_len);
-       }
-       
-       if (broadcom_ioctl(drv, WLC_SCAN, &wst, sizeof(wst)) < 0)
-               return -1;
-
-       eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
-       eloop_register_timeout(3, 0, wpa_driver_broadcom_scan_timeout, drv,
-                              drv->ctx);
-       return 0;
-}
-
-
-static const int frequency_list[] = { 
-       2412, 2417, 2422, 2427, 2432, 2437, 2442,
-       2447, 2452, 2457, 2462, 2467, 2472, 2484 
-};
-
-struct bss_ie_hdr {
-       u8 elem_id;
-       u8 len;
-       u8 oui[3];
-       /* u8 oui_type; */
-       /* u16 version; */
-} __attribute__ ((packed));
-
-static struct wpa_scan_results *
-wpa_driver_broadcom_get_scan_results(void *priv)
-{
-       struct wpa_driver_broadcom_data *drv = priv;
-       char *buf;
-       wl_scan_results_t *wsr;
-       wl_bss_info_t *wbi;
-       size_t ap_num;
-       struct wpa_scan_results *res;
-
-       buf = os_malloc(WLC_IOCTL_MAXLEN);
-       if (buf == NULL)
-               return NULL;
-
-       wsr = (wl_scan_results_t *) buf;
-
-       wsr->buflen = WLC_IOCTL_MAXLEN - sizeof(wsr);
-       wsr->version = 107;
-       wsr->count = 0;
-
-       if (broadcom_ioctl(drv, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0) {
-               os_free(buf);
-               return NULL;
-       }
-
-       res = os_zalloc(sizeof(*res));
-       if (res == NULL) {
-               os_free(buf);
-               return NULL;
-       }
-
-       res->res = os_zalloc(wsr->count * sizeof(struct wpa_scan_res *));
-       if (res->res == NULL) {
-               os_free(res);
-               os_free(buf);
-               return NULL;
-       }
-
-       for (ap_num = 0, wbi = wsr->bss_info; ap_num < wsr->count; ++ap_num) {
-               struct wpa_scan_res *r;
-               r = os_malloc(sizeof(*r) + wbi->ie_length);
-               if (r == NULL)
-                       break;
-               res->res[res->num++] = r;
-
-               os_memcpy(r->bssid, &wbi->BSSID, ETH_ALEN);
-               r->freq = frequency_list[wbi->channel - 1];
-               /* get ie's */
-               os_memcpy(r + 1, wbi + 1, wbi->ie_length);
-               r->ie_len = wbi->ie_length;
-
-               wbi = (wl_bss_info_t *) ((u8 *) wbi + wbi->length);
-       }
-
-       wpa_printf(MSG_MSGDUMP, "Received %d bytes of scan results (%lu "
-                  "BSSes)",
-                  wsr->buflen, (unsigned long) ap_num);
-       
-       os_free(buf);
-       return res;
-       }
-
-static int wpa_driver_broadcom_deauthenticate(void *priv, const u8 *addr,
-                                             int reason_code)
-{
-       struct wpa_driver_broadcom_data *drv = priv;
-       wlc_deauth_t wdt;
-       wdt.val = reason_code;
-       os_memcpy(&wdt.ea, addr, sizeof wdt.ea);
-       wdt.res = 0x7fff;
-       return broadcom_ioctl(drv, WLC_DEAUTHENTICATE_WITH_REASON, &wdt,
-                             sizeof(wdt));
-}
-
-static int wpa_driver_broadcom_disassociate(void *priv, const u8 *addr,
-                                           int reason_code)
-{
-       struct wpa_driver_broadcom_data *drv = priv;
-       return broadcom_ioctl(drv, WLC_DISASSOC, NULL, 0);
-}
-
-static int
-wpa_driver_broadcom_associate(void *priv,
-                             struct wpa_driver_associate_params *params)
-{
-       struct wpa_driver_broadcom_data *drv = priv;
-       wlc_ssid_t s;
-       int infra = 1;
-       int auth = 0;
-       int wsec = 4;
-       int dummy;
-       int wpa_auth;
-       int ret;
-
-       ret = wpa_driver_broadcom_set_drop_unencrypted(
-               drv, params->drop_unencrypted);
-
-       s.SSID_len = params->ssid_len;
-       os_memcpy(s.SSID, params->ssid, params->ssid_len);
-
-       switch (params->pairwise_suite) {
-       case CIPHER_WEP40:
-       case CIPHER_WEP104:
-               wsec = 1;
-               break;
-
-       case CIPHER_TKIP:
-               wsec = 2;
-               break;
-
-       case CIPHER_CCMP:
-               wsec = 4;
-               break;
-
-       default:
-               wsec = 0;
-               break;
-       }
-
-       switch (params->key_mgmt_suite) {
-       case KEY_MGMT_802_1X:
-               wpa_auth = 1;
-               break;
-
-       case KEY_MGMT_PSK:
-               wpa_auth = 2;
-               break;
-
-       default:
-               wpa_auth = 255;
-               break;
-       }
-
-       /* printf("broadcom_associate: %u %u %u\n", pairwise_suite,
-        * group_suite, key_mgmt_suite);
-        * broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec));
-        * wl join uses wlc_sec_wep here, not wlc_set_wsec */
-
-       if (broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) < 0 ||
-           broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wpa_auth,
-                          sizeof(wpa_auth)) < 0 ||
-           broadcom_ioctl(drv, WLC_GET_WEP, &dummy, sizeof(dummy)) < 0 ||
-           broadcom_ioctl(drv, WLC_SET_INFRA, &infra, sizeof(infra)) < 0 ||
-           broadcom_ioctl(drv, WLC_SET_AUTH, &auth, sizeof(auth)) < 0 ||
-           broadcom_ioctl(drv, WLC_SET_WEP, &wsec, sizeof(wsec)) < 0 ||
-           broadcom_ioctl(drv, WLC_SET_SSID, &s, sizeof(s)) < 0)
-               return -1;
-
-       return ret;
-}
-
-const struct wpa_driver_ops wpa_driver_broadcom_ops = {
-       .name = "broadcom",
-       .desc = "Broadcom wl.o driver",
-       .get_bssid = wpa_driver_broadcom_get_bssid,
-       .get_ssid = wpa_driver_broadcom_get_ssid,
-       .set_key = wpa_driver_broadcom_set_key,
-       .init = wpa_driver_broadcom_init,
-       .deinit = wpa_driver_broadcom_deinit,
-       .set_countermeasures = wpa_driver_broadcom_set_countermeasures,
-       .scan2 = wpa_driver_broadcom_scan,
-       .get_scan_results2 = wpa_driver_broadcom_get_scan_results,
-       .deauthenticate = wpa_driver_broadcom_deauthenticate,
-       .disassociate = wpa_driver_broadcom_disassociate,
-       .associate = wpa_driver_broadcom_associate,
-};
index 99de6c7..4596a51 100644 (file)
 
 #include "includes.h"
 #include <sys/ioctl.h>
+#include <sys/sysctl.h>
 
 #include "common.h"
 #include "driver.h"
 #include "eloop.h"
 #include "common/ieee802_11_defs.h"
+#include "common/wpa_common.h"
 
 #include <net/if.h>
 #include <net/if_media.h>
@@ -295,9 +297,7 @@ bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
 
        if (alg == WPA_ALG_NONE) {
 #ifndef HOSTAPD
-               if (addr == NULL ||
-                   os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
-                             IEEE80211_ADDR_LEN) == 0)
+               if (addr == NULL || is_broadcast_ether_addr(addr))
                        return bsd_del_key(priv, NULL, key_idx);
                else
 #endif /* HOSTAPD */
@@ -334,8 +334,7 @@ bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
                 * the address (yech).  Note also that we can only mark global
                 * keys default; doing this for a unicast key is an error.
                 */
-               if (os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
-                             IEEE80211_ADDR_LEN) == 0) {
+               if (is_broadcast_ether_addr(addr)) {
                        wk.ik_flags |= IEEE80211_KEY_GROUP;
                        wk.ik_keyix = key_idx;
                } else {
@@ -346,7 +345,20 @@ bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
        if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
                wk.ik_flags |= IEEE80211_KEY_DEFAULT;
        wk.ik_keylen = key_len;
-       os_memcpy(&wk.ik_keyrsc, seq, seq_len);
+       if (seq) {
+#ifdef WORDS_BIGENDIAN
+               /*
+                * wk.ik_keyrsc is in host byte order (big endian), need to
+                * swap it to match with the byte order used in WPA.
+                */
+               int i;
+               u8 *keyrsc = (u8 *) &wk.ik_keyrsc;
+               for (i = 0; i < seq_len; i++)
+                       keyrsc[WPA_KEY_RSC_LEN - i - 1] = seq[i];
+#else /* WORDS_BIGENDIAN */
+               os_memcpy(&wk.ik_keyrsc, seq, seq_len);
+#endif /* WORDS_BIGENDIAN */
+       }
        os_memcpy(wk.ik_keydata, key, key_len);
 
        return set80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
@@ -511,12 +523,12 @@ bsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN])
                ielen += 2;
 
 no_ie:
-       drv_event_assoc(ctx, addr, iebuf, ielen);
+       drv_event_assoc(ctx, addr, iebuf, ielen, 0);
 }
 
 static int
 bsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
-              int encrypt, const u8 *own_addr)
+              int encrypt, const u8 *own_addr, u32 flags)
 {
        struct bsd_driver_data *drv = priv;
 
@@ -527,20 +539,30 @@ bsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
 }
 
 static int
-bsd_set_freq(void *priv, u16 channel)
+bsd_set_freq(void *priv, struct hostapd_freq_params *freq)
 {
        struct bsd_driver_data *drv = priv;
 #ifdef SIOCS80211CHANNEL
        struct ieee80211chanreq creq;
 #endif /* SIOCS80211CHANNEL */
        u32 mode;
-
-       if (channel < 14)
-               mode = IFM_IEEE80211_11G;
-       else if (channel == 14)
+       int channel = freq->channel;
+
+       if (channel < 14) {
+               mode =
+#ifdef CONFIG_IEEE80211N
+                       freq->ht_enabled ? IFM_IEEE80211_11NG :
+#endif /* CONFIG_IEEE80211N */
+                       IFM_IEEE80211_11G;
+       } else if (channel == 14) {
                mode = IFM_IEEE80211_11B;
-       else
-               mode = IFM_IEEE80211_11A;
+       } else {
+               mode =
+#ifdef CONFIG_IEEE80211N
+                       freq->ht_enabled ? IFM_IEEE80211_11NA :
+#endif /* CONFIG_IEEE80211N */
+                       IFM_IEEE80211_11A;
+       }
        if (bsd_set_mediaopt(drv, IFM_MMASK, mode) < 0) {
                wpa_printf(MSG_ERROR, "%s: failed to set modulation mode",
                           __func__);
@@ -550,7 +572,7 @@ bsd_set_freq(void *priv, u16 channel)
 #ifdef SIOCS80211CHANNEL
        os_memset(&creq, 0, sizeof(creq));
        os_strlcpy(creq.i_name, drv->ifname, sizeof(creq.i_name));
-       creq.i_channel = channel;
+       creq.i_channel = (u_int16_t)channel;
        return ioctl(drv->sock, SIOCS80211CHANNEL, &creq);
 #else /* SIOCS80211CHANNEL */
        return set80211param(priv, IEEE80211_IOC_CHANNEL, channel);
@@ -569,6 +591,21 @@ bsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
        return 0;
 }
 
+static int
+rtbuf_len(void)
+{
+       size_t len;
+
+       int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0};
+
+       if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
+               wpa_printf(MSG_WARNING, "%s failed: %s\n", __func__,
+                          strerror(errno));
+               len = 2048;
+       }
+
+       return len;
+}
 
 #ifdef HOSTAPD
 
@@ -691,26 +728,37 @@ static void
 bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
 {
        struct bsd_driver_data *drv = ctx;
-       char buf[2048];
+       char *buf;
        struct if_announcemsghdr *ifan;
        struct rt_msghdr *rtm;
        struct ieee80211_michael_event *mic;
        struct ieee80211_join_event *join;
        struct ieee80211_leave_event *leave;
-       int n;
+       int n, len;
        union wpa_event_data data;
 
-       n = read(sock, buf, sizeof(buf));
+       len = rtbuf_len();
+
+       buf = os_malloc(len);
+       if (buf == NULL) {
+               wpa_printf(MSG_ERROR, "%s os_malloc() failed\n", __func__);
+               return;
+       }
+
+       n = read(sock, buf, len);
        if (n < 0) {
                if (errno != EINTR && errno != EAGAIN)
-                       perror("read(PF_ROUTE)");
+                       wpa_printf(MSG_ERROR, "%s read() failed: %s\n",
+                                  __func__, strerror(errno));
+               os_free(buf);
                return;
        }
 
        rtm = (struct rt_msghdr *) buf;
        if (rtm->rtm_version != RTM_VERSION) {
-               wpa_printf(MSG_DEBUG, "Routing message version %d not "
-                       "understood\n", rtm->rtm_version);
+               wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
+                          rtm->rtm_version);
+               os_free(buf);
                return;
        }
        ifan = (struct if_announcemsghdr *) rtm;
@@ -751,6 +799,7 @@ bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
                }
                break;
        }
+       os_free(buf);
 }
 
 static void
@@ -760,12 +809,6 @@ handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
        drv_event_eapol_rx(drv->hapd, src_addr, buf, len);
 }
 
-static int
-hostapd_bsd_set_freq(void *priv, struct hostapd_freq_params *freq)
-{
-       return bsd_set_freq(priv, freq->channel);
-}
-
 static void *
 bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params)
 {
@@ -972,7 +1015,6 @@ wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
        struct bsd_driver_data *drv = priv;
        struct ieee80211req_mlme mlme;
        u32 mode;
-       u16 channel;
        int privacy;
        int ret = 0;
 
@@ -1007,18 +1049,6 @@ wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
        }
 
        if (params->mode == IEEE80211_MODE_AP) {
-               if (params->freq >= 2412 && params->freq <= 2472)
-                       channel = (params->freq - 2407) / 5;
-               else if (params->freq == 2484)
-                       channel = 14;
-               else if ((params->freq >= 5180 && params->freq <= 5240) ||
-                        (params->freq >= 5745 && params->freq <= 5825))
-                       channel = (params->freq - 5000) / 5;
-               else
-                       channel = 0;
-               if (bsd_set_freq(drv, channel) < 0)
-                       return -1;
-
                drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL,
                                                handle_read, drv, 0);
                if (drv->sock_xmit == NULL)
@@ -1134,7 +1164,7 @@ static void
 wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
 {
        struct bsd_driver_data *drv = sock_ctx;
-       char buf[2048];
+       char *buf;
        struct if_announcemsghdr *ifan;
        struct if_msghdr *ifm;
        struct rt_msghdr *rtm;
@@ -1142,19 +1172,30 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
        struct ieee80211_michael_event *mic;
        struct ieee80211_leave_event *leave;
        struct ieee80211_join_event *join;
-       int n;
+       int n, len;
+
+       len = rtbuf_len();
+
+       buf = os_malloc(len);
+       if (buf == NULL) {
+               wpa_printf(MSG_ERROR, "%s os_malloc() failed\n", __func__);
+               return;
+       }
 
-       n = read(sock, buf, sizeof(buf));
+       n = read(sock, buf, len);
        if (n < 0) {
                if (errno != EINTR && errno != EAGAIN)
-                       perror("read(PF_ROUTE)");
+                       wpa_printf(MSG_ERROR, "%s read() failed: %s\n",
+                                  __func__, strerror(errno));
+               os_free(buf);
                return;
        }
 
        rtm = (struct rt_msghdr *) buf;
        if (rtm->rtm_version != RTM_VERSION) {
-               wpa_printf(MSG_DEBUG, "Routing message version %d not "
-                       "understood\n", rtm->rtm_version);
+               wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
+                          rtm->rtm_version);
+               os_free(buf);
                return;
        }
        os_memset(&event, 0, sizeof(event));
@@ -1169,6 +1210,7 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
                case IFAN_DEPARTURE:
                        event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
                default:
+                       os_free(buf);
                        return;
                }
                wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
@@ -1241,6 +1283,7 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
                }
                break;
        }
+       os_free(buf);
 }
 
 static void
@@ -1518,7 +1561,6 @@ const struct wpa_driver_ops wpa_driver_bsd_ops = {
        .read_sta_data          = bsd_read_sta_driver_data,
        .sta_disassoc           = bsd_sta_disassoc,
        .sta_deauth             = bsd_sta_deauth,
-       .set_freq               = hostapd_bsd_set_freq,
 #else /* HOSTAPD */
        .init                   = wpa_driver_bsd_init,
        .deinit                 = wpa_driver_bsd_deinit,
@@ -1532,6 +1574,7 @@ const struct wpa_driver_ops wpa_driver_bsd_ops = {
        .associate              = wpa_driver_bsd_associate,
        .get_capa               = wpa_driver_bsd_get_capa,
 #endif /* HOSTAPD */
+       .set_freq               = bsd_set_freq,
        .set_key                = bsd_set_key,
        .set_ieee8021x          = bsd_set_ieee8021x,
        .hapd_set_ssid          = bsd_set_ssid,
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
new file mode 100644 (file)
index 0000000..26ca8d6
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+#include "utils/common.h"
+#include "driver.h"
+
+void wpa_scan_results_free(struct wpa_scan_results *res)
+{
+       size_t i;
+
+       if (res == NULL)
+               return;
+
+       for (i = 0; i < res->num; i++)
+               os_free(res->res[i]);
+       os_free(res->res);
+       os_free(res);
+}
+
+
+const char * event_to_string(enum wpa_event_type event)
+{
+#define E2S(n) case EVENT_ ## n: return #n
+       switch (event) {
+       E2S(ASSOC);
+       E2S(DISASSOC);
+       E2S(MICHAEL_MIC_FAILURE);
+       E2S(SCAN_RESULTS);
+       E2S(ASSOCINFO);
+       E2S(INTERFACE_STATUS);
+       E2S(PMKID_CANDIDATE);
+       E2S(STKSTART);
+       E2S(TDLS);
+       E2S(FT_RESPONSE);
+       E2S(IBSS_RSN_START);
+       E2S(AUTH);
+       E2S(DEAUTH);
+       E2S(ASSOC_REJECT);
+       E2S(AUTH_TIMED_OUT);
+       E2S(ASSOC_TIMED_OUT);
+       E2S(FT_RRB_RX);
+       E2S(WPS_BUTTON_PUSHED);
+       E2S(TX_STATUS);
+       E2S(RX_FROM_UNKNOWN);
+       E2S(RX_MGMT);
+       E2S(RX_ACTION);
+       E2S(REMAIN_ON_CHANNEL);
+       E2S(CANCEL_REMAIN_ON_CHANNEL);
+       E2S(MLME_RX);
+       E2S(RX_PROBE_REQ);
+       E2S(NEW_STA);
+       E2S(EAPOL_RX);
+       E2S(SIGNAL_CHANGE);
+       E2S(INTERFACE_ENABLED);
+       E2S(INTERFACE_DISABLED);
+       E2S(CHANNEL_LIST_CHANGED);
+       E2S(INTERFACE_UNAVAILABLE);
+       E2S(BEST_CHANNEL);
+       E2S(UNPROT_DEAUTH);
+       E2S(UNPROT_DISASSOC);
+       E2S(STATION_LOW_ACK);
+       E2S(P2P_DEV_FOUND);
+       E2S(P2P_GO_NEG_REQ_RX);
+       E2S(P2P_GO_NEG_COMPLETED);
+       E2S(P2P_PROV_DISC_REQUEST);
+       E2S(P2P_PROV_DISC_RESPONSE);
+       E2S(P2P_SD_REQUEST);
+       E2S(P2P_SD_RESPONSE);
+       E2S(IBSS_PEER_LOST);
+       E2S(DRIVER_GTK_REKEY);
+       E2S(SCHED_SCAN_STOPPED);
+       E2S(DRIVER_CLIENT_POLL_OK);
+       E2S(EAPOL_TX_STATUS);
+       }
+
+       return "UNKNOWN";
+#undef E2S
+}
index 952f389..8fc0efd 100644 (file)
@@ -15,7 +15,7 @@
 #include "includes.h"
 #include <sys/ioctl.h>
 
-#include "wireless_copy.h"
+#include "linux_wext.h"
 #include "common.h"
 #include "driver.h"
 #include "driver_wext.h"
@@ -23,8 +23,6 @@
 #include "driver_hostap.h"
 
 
-#ifdef HOSTAPD
-
 #include <net/if_arp.h>
 #include <netpacket/packet.h>
 
@@ -32,6 +30,7 @@
 #include "netlink.h"
 #include "linux_ioctl.h"
 #include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
 
 
 /* MTU to be set for the wlan#ap device; this is mainly needed for IEEE 802.1X
@@ -84,8 +83,8 @@ static void handle_data(struct hostap_driver_data *drv, u8 *buf, size_t len,
 
        sa = hdr->addr2;
        os_memset(&event, 0, sizeof(event));
-       event.rx_from_unknown.frame = buf;
-       event.rx_from_unknown.len = len;
+       event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
+       event.rx_from_unknown.addr = sa;
        wpa_supplicant_event(drv->hapd, EVENT_RX_FROM_UNKNOWN, &event);
 
        pos = (u8 *) (hdr + 1);
@@ -148,7 +147,6 @@ static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len)
 {
        struct ieee80211_hdr *hdr;
        u16 fc, extra_len, type, stype;
-       unsigned char *extra = NULL;
        size_t data_len = len;
        int ver;
        union wpa_event_data event;
@@ -185,7 +183,6 @@ static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len)
                        return;
                }
                len -= extra_len + 2;
-               extra = buf + len;
        } else if (ver == 1 || ver == 2) {
                handle_tx_callback(drv, buf, data_len, ver == 2 ? 1 : 0);
                return;
@@ -273,7 +270,7 @@ static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr)
 }
 
 
-static int hostap_send_mlme(void *priv, const u8 *msg, size_t len)
+static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack)
 {
        struct hostap_driver_data *drv = priv;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
@@ -289,7 +286,8 @@ static int hostap_send_mlme(void *priv, const u8 *msg, size_t len)
 
 
 static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data,
-                            size_t data_len, int encrypt, const u8 *own_addr)
+                            size_t data_len, int encrypt, const u8 *own_addr,
+                            u32 flags)
 {
        struct hostap_driver_data *drv = priv;
        struct ieee80211_hdr *hdr;
@@ -321,7 +319,7 @@ static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data,
        pos += 2;
        memcpy(pos, data, data_len);
 
-       res = hostap_send_mlme(drv, (u8 *) hdr, len);
+       res = hostap_send_mlme(drv, (u8 *) hdr, len, 0);
        if (res < 0) {
                wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - "
                           "failed: %d (%s)",
@@ -763,7 +761,8 @@ static int hostap_set_generic_elem(void *priv,
 
 
 static int hostap_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
-                               const struct wpabuf *proberesp)
+                               const struct wpabuf *proberesp,
+                               const struct wpabuf *assocresp)
 {
        struct hostap_driver_data *drv = priv;
 
@@ -1034,6 +1033,16 @@ static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
        struct hostap_driver_data *drv = priv;
        struct ieee80211_mgmt mgmt;
 
+       if (is_broadcast_ether_addr(addr)) {
+               /*
+                * New Prism2.5/3 STA firmware versions seem to have issues
+                * with this broadcast deauth frame. This gets the firmware in
+                * odd state where nothing works correctly, so let's skip
+                * sending this for the hostap driver.
+                */
+               return 0;
+       }
+
        memset(&mgmt, 0, sizeof(mgmt));
        mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
                                          WLAN_FC_STYPE_DEAUTH);
@@ -1042,7 +1051,26 @@ static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
        memcpy(mgmt.bssid, own_addr, ETH_ALEN);
        mgmt.u.deauth.reason_code = host_to_le16(reason);
        return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
-                               sizeof(mgmt.u.deauth));
+                               sizeof(mgmt.u.deauth), 0);
+}
+
+
+static int hostap_set_freq(void *priv, struct hostapd_freq_params *freq)
+{
+       struct hostap_driver_data *drv = priv;
+       struct iwreq iwr;
+
+       os_memset(&iwr, 0, sizeof(iwr));
+       os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+       iwr.u.freq.m = freq->channel;
+       iwr.u.freq.e = 0;
+
+       if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
+               perror("ioctl[SIOCSIWFREQ]");
+               return -1;
+       }
+
+       return 0;
 }
 
 
@@ -1060,7 +1088,7 @@ static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
        memcpy(mgmt.bssid, own_addr, ETH_ALEN);
        mgmt.u.disassoc.reason_code = host_to_le16(reason);
        return  hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
-                                sizeof(mgmt.u.disassoc));
+                                sizeof(mgmt.u.disassoc), 0);
 }
 
 
@@ -1114,491 +1142,38 @@ static struct hostapd_hw_modes * hostap_get_hw_feature_data(void *priv,
        return mode;
 }
 
-#else /* HOSTAPD */
-
-struct wpa_driver_hostap_data {
-       void *wext; /* private data for driver_wext */
-       void *ctx;
-       char ifname[IFNAMSIZ + 1];
-       int sock;
-       int current_mode; /* infra/adhoc */
-};
-
-
-static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg);
-
-
-static int hostapd_ioctl(struct wpa_driver_hostap_data *drv,
-                        struct prism2_hostapd_param *param,
-                        int len, int show_err)
-{
-       struct iwreq iwr;
-
-       os_memset(&iwr, 0, sizeof(iwr));
-       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-       iwr.u.data.pointer = (caddr_t) param;
-       iwr.u.data.length = len;
-
-       if (ioctl(drv->sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
-               int ret = errno;
-               if (show_err)
-                       perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
-               return ret;
-       }
-
-       return 0;
-}
-
-
-static int wpa_driver_hostap_set_wpa_ie(struct wpa_driver_hostap_data *drv,
-                                       const u8 *wpa_ie, size_t wpa_ie_len)
-{
-       struct prism2_hostapd_param *param;
-       int res;
-       size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
-       if (blen < sizeof(*param))
-               blen = sizeof(*param);
-
-       param = os_zalloc(blen);
-       if (param == NULL)
-               return -1;
-
-       param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT;
-       param->u.generic_elem.len = wpa_ie_len;
-       os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
-       res = hostapd_ioctl(drv, param, blen, 1);
-
-       os_free(param);
-
-       return res;
-}
-
-
-static int prism2param(struct wpa_driver_hostap_data *drv, int param,
-                      int value)
-{
-       struct iwreq iwr;
-       int *i, ret = 0;
-
-       os_memset(&iwr, 0, sizeof(iwr));
-       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-       i = (int *) iwr.u.name;
-       *i++ = param;
-       *i++ = value;
-
-       if (ioctl(drv->sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
-               perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
-               ret = -1;
-       }
-       return ret;
-}
-
 
-static int wpa_driver_hostap_set_wpa(void *priv, int enabled)
+static void wpa_driver_hostap_poll_client(void *priv, const u8 *own_addr,
+                                         const u8 *addr, int qos)
 {
-       struct wpa_driver_hostap_data *drv = priv;
-       int ret = 0;
-
-       wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-
-       if (!enabled && wpa_driver_hostap_set_wpa_ie(drv, NULL, 0) < 0)
-               ret = -1;
-       if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING, enabled ? 2 : 0) < 0)
-               ret = -1;
-       if (prism2param(drv, PRISM2_PARAM_WPA, enabled) < 0)
-               ret = -1;
-
-       return ret;
-}
-
-
-static void show_set_key_error(struct prism2_hostapd_param *param)
-{
-       switch (param->u.crypt.err) {
-       case HOSTAP_CRYPT_ERR_UNKNOWN_ALG:
-               wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
-                          param->u.crypt.alg);
-               wpa_printf(MSG_INFO, "You may need to load kernel module to "
-                          "register that algorithm.");
-               wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for "
-                          "WEP.");
-               break;
-       case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR:
-               wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
-                          MAC2STR(param->sta_addr));
-               break;
-       case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED:
-               wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
-               break;
-       case HOSTAP_CRYPT_ERR_KEY_SET_FAILED:
-               wpa_printf(MSG_INFO, "Key setting failed.");
-               break;
-       case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED:
-               wpa_printf(MSG_INFO, "TX key index setting failed.");
-               break;
-       case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED:
-               wpa_printf(MSG_INFO, "Card configuration failed.");
-               break;
-       }
-}
-
+       struct ieee80211_hdr hdr;
 
-static int wpa_driver_hostap_set_key(const char *ifname, void *priv,
-                                    enum wpa_alg alg, const u8 *addr,
-                                    int key_idx, int set_tx,
-                                    const u8 *seq, size_t seq_len,
-                                    const u8 *key, size_t key_len)
-{
-       struct wpa_driver_hostap_data *drv = priv;
-       struct prism2_hostapd_param *param;
-       u8 *buf;
-       size_t blen;
-       int ret = 0;
-       char *alg_name;
-
-       switch (alg) {
-       case WPA_ALG_NONE:
-               alg_name = "none";
-               break;
-       case WPA_ALG_WEP:
-               alg_name = "WEP";
-               break;
-       case WPA_ALG_TKIP:
-               alg_name = "TKIP";
-               break;
-       case WPA_ALG_CCMP:
-               alg_name = "CCMP";
-               break;
-       default:
-               return -1;
-       }
-
-       wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
-                  "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
-                  (unsigned long) seq_len, (unsigned long) key_len);
-
-       if (seq_len > 8)
-               return -2;
-
-       blen = sizeof(*param) + key_len;
-       buf = os_zalloc(blen);
-       if (buf == NULL)
-               return -1;
+       os_memset(&hdr, 0, sizeof(hdr));
 
-       param = (struct prism2_hostapd_param *) buf;
-       param->cmd = PRISM2_SET_ENCRYPTION;
-       /* TODO: In theory, STA in client mode can use five keys; four default
-        * keys for receiving (with keyidx 0..3) and one individual key for
-        * both transmitting and receiving (keyidx 0) _unicast_ packets. Now,
-        * keyidx 0 is reserved for this unicast use and default keys can only
-        * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported).
-        * This should be fine for more or less all cases, but for completeness
-        * sake, the driver could be enhanced to support the missing key. */
-#if 0
-       if (addr == NULL)
-               os_memset(param->sta_addr, 0xff, ETH_ALEN);
-       else
-               os_memcpy(param->sta_addr, addr, ETH_ALEN);
-#else
-       os_memset(param->sta_addr, 0xff, ETH_ALEN);
-#endif
-       os_strlcpy((char *) param->u.crypt.alg, alg_name,
-                  HOSTAP_CRYPT_ALG_NAME_LEN);
-       param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
-       param->u.crypt.idx = key_idx;
-       os_memcpy(param->u.crypt.seq, seq, seq_len);
-       param->u.crypt.key_len = key_len;
-       os_memcpy((u8 *) (param + 1), key, key_len);
-
-       if (hostapd_ioctl(drv, param, blen, 1)) {
-               wpa_printf(MSG_WARNING, "Failed to set encryption.");
-               show_set_key_error(param);
-               ret = -1;
-       }
-       os_free(buf);
-
-       return ret;
-}
-
-
-static int wpa_driver_hostap_set_countermeasures(void *priv, int enabled)
-{
-       struct wpa_driver_hostap_data *drv = priv;
-       wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-       return prism2param(drv, PRISM2_PARAM_TKIP_COUNTERMEASURES, enabled);
-}
-
-
-static int wpa_driver_hostap_reset(struct wpa_driver_hostap_data *drv,
-                                  int type)
-{
-       struct iwreq iwr;
-       int *i, ret = 0;
-
-       wpa_printf(MSG_DEBUG, "%s: type=%d", __FUNCTION__, type);
-
-       os_memset(&iwr, 0, sizeof(iwr));
-       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-       i = (int *) iwr.u.name;
-       *i++ = type;
-
-       if (ioctl(drv->sock, PRISM2_IOCTL_RESET, &iwr) < 0) {
-               perror("ioctl[PRISM2_IOCTL_RESET]");
-               ret = -1;
-       }
-       return ret;
-}
-
-
-static int wpa_driver_hostap_mlme(struct wpa_driver_hostap_data *drv,
-                                 const u8 *addr, int cmd, int reason_code)
-{
-       struct prism2_hostapd_param param;
-       int ret;
-
-       /* There does not seem to be a better way of deauthenticating or
-        * disassociating with Prism2/2.5/3 than sending the management frame
-        * and then resetting the Port0 to make sure both the AP and the STA
-        * end up in disconnected state. */
-       os_memset(&param, 0, sizeof(param));
-       param.cmd = PRISM2_HOSTAPD_MLME;
-       os_memcpy(param.sta_addr, addr, ETH_ALEN);
-       param.u.mlme.cmd = cmd;
-       param.u.mlme.reason_code = reason_code;
-       ret = hostapd_ioctl(drv, &param, sizeof(param), 1);
-       if (ret == 0) {
-               os_sleep(0, 100000);
-               ret = wpa_driver_hostap_reset(drv, 2);
-       }
-       return ret;
-}
-
-
-static int wpa_driver_hostap_deauthenticate(void *priv, const u8 *addr,
-                                           int reason_code)
-{
-       struct wpa_driver_hostap_data *drv = priv;
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-       return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DEAUTH,
-                                     reason_code);
-}
-
-
-static int wpa_driver_hostap_disassociate(void *priv, const u8 *addr,
-                                         int reason_code)
-{
-       struct wpa_driver_hostap_data *drv = priv;
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-       return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DISASSOC,
-                                     reason_code);
-}
-
-
-static int
-wpa_driver_hostap_associate(void *priv,
-                           struct wpa_driver_associate_params *params)
-{
-       struct wpa_driver_hostap_data *drv = priv;
-       int ret = 0;
-       int allow_unencrypted_eapol;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       if (prism2param(drv, PRISM2_PARAM_DROP_UNENCRYPTED,
-                       params->drop_unencrypted) < 0)
-               ret = -1;
-       if (wpa_driver_hostap_set_auth_alg(drv, params->auth_alg) < 0)
-               ret = -1;
-       if (params->mode != drv->current_mode) {
-               /* At the moment, Host AP driver requires host_roaming=2 for
-                * infrastructure mode and host_roaming=0 for adhoc. */
-               if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING,
-                               params->mode == IEEE80211_MODE_IBSS ? 0 : 2) <
-                   0) {
-                       wpa_printf(MSG_DEBUG, "%s: failed to set host_roaming",
-                                  __func__);
-               }
-               drv->current_mode = params->mode;
-       }
-
-       if (prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED,
-                       params->key_mgmt_suite != KEY_MGMT_NONE) < 0)
-               ret = -1;
-       if (wpa_driver_hostap_set_wpa_ie(drv, params->wpa_ie,
-                                        params->wpa_ie_len) < 0)
-               ret = -1;
-       if (wpa_driver_wext_set_mode(drv->wext, params->mode) < 0)
-               ret = -1;
-       if (params->freq &&
-           wpa_driver_wext_set_freq(drv->wext, params->freq) < 0)
-               ret = -1;
-       if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, params->ssid_len)
-           < 0)
-               ret = -1;
-       if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
-               ret = -1;
-
-       /* Allow unencrypted EAPOL messages even if pairwise keys are set when
-        * not using WPA. IEEE 802.1X specifies that these frames are not
-        * encrypted, but WPA encrypts them when pairwise keys are in use. */
-       if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
-           params->key_mgmt_suite == KEY_MGMT_PSK)
-               allow_unencrypted_eapol = 0;
-       else
-               allow_unencrypted_eapol = 1;
-       
-       if (prism2param(drv, PRISM2_PARAM_IEEE_802_1X,
-                       allow_unencrypted_eapol) < 0) {
-               wpa_printf(MSG_DEBUG, "hostap: Failed to configure "
-                          "ieee_802_1x param");
-               /* Ignore this error.. driver_hostap.c can also be used with
-                * other drivers that do not support this prism2_param. */
-       }
-
-       return ret;
-}
-
-
-static int wpa_driver_hostap_scan(void *priv,
-                                 struct wpa_driver_scan_params *params)
-{
-       struct wpa_driver_hostap_data *drv = priv;
-       struct prism2_hostapd_param param;
-       int ret;
-       const u8 *ssid = params->ssids[0].ssid;
-       size_t ssid_len = params->ssids[0].ssid_len;
-
-       if (ssid == NULL) {
-               /* Use standard Linux Wireless Extensions ioctl if possible
-                * because some drivers using hostap code in wpa_supplicant
-                * might not support Host AP specific scan request (with SSID
-                * info). */
-               return wpa_driver_wext_scan(drv->wext, params);
-       }
-
-       if (ssid_len > 32)
-               ssid_len = 32;
-
-       os_memset(&param, 0, sizeof(param));
-       param.cmd = PRISM2_HOSTAPD_SCAN_REQ;
-       param.u.scan_req.ssid_len = ssid_len;
-       os_memcpy(param.u.scan_req.ssid, ssid, ssid_len);
-       ret = hostapd_ioctl(drv, &param, sizeof(param), 1);
-
-       /* Not all drivers generate "scan completed" wireless event, so try to
-        * read results after a timeout. */
-       eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
-                            drv->ctx);
-       eloop_register_timeout(3, 0, wpa_driver_wext_scan_timeout, drv->wext,
-                              drv->ctx);
-
-       return ret;
-}
-
-
-static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg)
-{
-       struct wpa_driver_hostap_data *drv = priv;
-       int algs = 0;
-
-       if (auth_alg & WPA_AUTH_ALG_OPEN)
-               algs |= 1;
-       if (auth_alg & WPA_AUTH_ALG_SHARED)
-               algs |= 2;
-       if (auth_alg & WPA_AUTH_ALG_LEAP)
-               algs |= 4;
-       if (algs == 0)
-               algs = 1; /* at least one algorithm should be set */
-
-       return prism2param(drv, PRISM2_PARAM_AP_AUTH_ALGS, algs);
-}
-
-
-static int wpa_driver_hostap_get_bssid(void *priv, u8 *bssid)
-{
-       struct wpa_driver_hostap_data *drv = priv;
-       return wpa_driver_wext_get_bssid(drv->wext, bssid);
-}
-
-
-static int wpa_driver_hostap_get_ssid(void *priv, u8 *ssid)
-{
-       struct wpa_driver_hostap_data *drv = priv;
-       return wpa_driver_wext_get_ssid(drv->wext, ssid);
-}
-
-
-static struct wpa_scan_results * wpa_driver_hostap_get_scan_results(void *priv)
-{
-       struct wpa_driver_hostap_data *drv = priv;
-       return wpa_driver_wext_get_scan_results(drv->wext);
-}
-
-
-static int wpa_driver_hostap_set_operstate(void *priv, int state)
-{
-       struct wpa_driver_hostap_data *drv = priv;
-       return wpa_driver_wext_set_operstate(drv->wext, state);
-}
-
-
-static void * wpa_driver_hostap_init(void *ctx, const char *ifname)
-{
-       struct wpa_driver_hostap_data *drv;
-
-       drv = os_zalloc(sizeof(*drv));
-       if (drv == NULL)
-               return NULL;
-       drv->wext = wpa_driver_wext_init(ctx, ifname);
-       if (drv->wext == NULL) {
-               os_free(drv);
-               return NULL;
-       }
-
-       drv->ctx = ctx;
-       os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-       drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-       if (drv->sock < 0) {
-               perror("socket");
-               wpa_driver_wext_deinit(drv->wext);
-               os_free(drv);
-               return NULL;
-       }
-
-       if (os_strncmp(ifname, "wlan", 4) == 0) {
-               /*
-                * Host AP driver may use both wlan# and wifi# interface in
-                * wireless events.
-                */
-               char ifname2[IFNAMSIZ + 1];
-               os_strlcpy(ifname2, ifname, sizeof(ifname2));
-               os_memcpy(ifname2, "wifi", 4);
-               wpa_driver_wext_alternative_ifindex(drv->wext, ifname2);
-       }
-
-       wpa_driver_hostap_set_wpa(drv, 1);
-
-       return drv;
-}
+       /*
+        * WLAN_FC_STYPE_NULLFUNC would be more appropriate,
+        * but it is apparently not retried so TX Exc events
+        * are not received for it.
+        * This is the reason the driver overrides the default
+        * handling.
+        */
+       hdr.frame_control = IEEE80211_FC(WLAN_FC_TYPE_DATA,
+                                        WLAN_FC_STYPE_DATA);
 
+       hdr.frame_control |=
+               host_to_le16(WLAN_FC_FROMDS);
+       os_memcpy(hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+       os_memcpy(hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+       os_memcpy(hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
 
-static void wpa_driver_hostap_deinit(void *priv)
-{
-       struct wpa_driver_hostap_data *drv = priv;
-       wpa_driver_hostap_set_wpa(drv, 0);
-       wpa_driver_wext_deinit(drv->wext);
-       close(drv->sock);
-       os_free(drv);
+       hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0);
 }
 
-#endif /* HOSTAPD */
-
 
 const struct wpa_driver_ops wpa_driver_hostap_ops = {
        .name = "hostap",
        .desc = "Host AP driver (Intersil Prism2/2.5/3)",
        .set_key = wpa_driver_hostap_set_key,
-#ifdef HOSTAPD
        .hapd_init = hostap_init,
        .hapd_deinit = hostap_driver_deinit,
        .set_ieee8021x = hostap_set_ieee8021x,
@@ -1619,17 +1194,6 @@ const struct wpa_driver_ops wpa_driver_hostap_ops = {
        .sta_clear_stats = hostap_sta_clear_stats,
        .get_hw_feature_data = hostap_get_hw_feature_data,
        .set_ap_wps_ie = hostap_set_ap_wps_ie,
-#else /* HOSTAPD */
-       .get_bssid = wpa_driver_hostap_get_bssid,
-       .get_ssid = wpa_driver_hostap_get_ssid,
-       .set_countermeasures = wpa_driver_hostap_set_countermeasures,
-       .scan2 = wpa_driver_hostap_scan,
-       .get_scan_results2 = wpa_driver_hostap_get_scan_results,
-       .deauthenticate = wpa_driver_hostap_deauthenticate,
-       .disassociate = wpa_driver_hostap_disassociate,
-       .associate = wpa_driver_hostap_associate,
-       .init = wpa_driver_hostap_init,
-       .deinit = wpa_driver_hostap_deinit,
-       .set_operstate = wpa_driver_hostap_set_operstate,
-#endif /* HOSTAPD */
+       .set_freq = hostap_set_freq,
+       .poll_client = wpa_driver_hostap_poll_client,
 };
diff --git a/src/drivers/driver_iphone.m b/src/drivers/driver_iphone.m
deleted file mode 100644 (file)
index 8213fda..0000000
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
- * WPA Supplicant - iPhone/iPod touch Apple80211 driver interface
- * 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.
- */
-
-#include "includes.h"
-#define Boolean __DummyBoolean
-#include <CoreFoundation/CoreFoundation.h>
-#undef Boolean
-
-#include "common.h"
-#include "driver.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-
-#include "MobileApple80211.h"
-
-struct wpa_driver_iphone_data {
-       void *ctx;
-       Apple80211Ref wireless_ctx;
-       CFArrayRef scan_results;
-       int ctrl_power;
-};
-
-
-static const void * cfdict_get_key_str(CFDictionaryRef dict, const char *key)
-{
-       const void *res;
-       CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, key,
-                                                   kCFStringEncodingMacRoman);
-       if (str == NULL)
-               return NULL;
-
-       res = CFDictionaryGetValue(dict, str);
-       CFRelease(str);
-       return res;
-}
-
-
-static int wpa_driver_iphone_get_ssid(void *priv, u8 *ssid)
-{
-       struct wpa_driver_iphone_data *drv = priv;
-       CFDataRef data;
-       int err, len;
-
-       err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_SSID, 0,
-                                 &data);
-       if (err != 0) {
-               wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(SSID) "
-                          "failed: %d", err);
-               return -1;
-       }
-
-       len = CFDataGetLength(data);
-       if (len > 32) {
-               CFRelease(data);
-               return -1;
-       }
-       os_memcpy(ssid, CFDataGetBytePtr(data), len);
-       CFRelease(data);
-
-       return len;
-}
-
-
-static int wpa_driver_iphone_get_bssid(void *priv, u8 *bssid)
-{
-       struct wpa_driver_iphone_data *drv = priv;
-       CFStringRef data;
-       int err;
-       int a1, a2, a3, a4, a5, a6;
-
-       err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_BSSID, 0,
-                                 &data);
-       if (err != 0) {
-               wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(BSSID) "
-                          "failed: %d", err);
-               return -1;
-       }
-
-       sscanf(CFStringGetCStringPtr(data, kCFStringEncodingMacRoman),
-              "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6);
-       bssid[0] = a1;
-       bssid[1] = a2;
-       bssid[2] = a3;
-       bssid[3] = a4;
-       bssid[4] = a5;
-       bssid[5] = a6;
-
-       CFRelease(data);
-
-       return 0;
-}
-
-
-static void wpa_driver_iphone_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-       wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-static int wpa_driver_iphone_scan(void *priv, const u8 *ssid, size_t ssid_len)
-{
-       struct wpa_driver_iphone_data *drv = priv;
-       int err;
-
-       if (drv->scan_results) {
-               CFRelease(drv->scan_results);
-               drv->scan_results = NULL;
-       }
-
-       err = Apple80211Scan(drv->wireless_ctx, &drv->scan_results, NULL);
-       if (err) {
-               wpa_printf(MSG_DEBUG, "iPhone: Apple80211Scan failed: %d",
-                          err);
-               return -1;
-       }
-
-       eloop_register_timeout(0, 0, wpa_driver_iphone_scan_timeout, drv,
-                              drv->ctx);
-       return 0;
-}
-
-
-static int wpa_driver_iphone_get_scan_results(void *priv,
-                                             struct wpa_scan_result *results,
-                                             size_t max_size)
-{
-       struct wpa_driver_iphone_data *drv = priv;
-       size_t i, num;
-
-       if (drv->scan_results == NULL)
-               return 0;
-
-       num = CFArrayGetCount(drv->scan_results);
-       if (num > max_size)
-               num = max_size;
-       os_memset(results, 0, num * sizeof(struct wpa_scan_result));
-
-       for (i = 0; i < num; i++) {
-               struct wpa_scan_result *res = &results[i];
-               CFDictionaryRef dict =
-                       CFArrayGetValueAtIndex(drv->scan_results, i);
-               CFDataRef data;
-               CFStringRef str;
-               CFNumberRef num;
-               int val;
-
-               data = cfdict_get_key_str(dict, "SSID");
-               if (data) {
-                       res->ssid_len = CFDataGetLength(data);
-                       if (res->ssid_len > 32)
-                               res->ssid_len = 32;
-                       os_memcpy(res->ssid, CFDataGetBytePtr(data),
-                                 res->ssid_len);
-               }
-
-               str = cfdict_get_key_str(dict, "BSSID");
-               if (str) {
-                       int a1, a2, a3, a4, a5, a6;
-                       sscanf(CFStringGetCStringPtr(
-                                      str, kCFStringEncodingMacRoman),
-                              "%x:%x:%x:%x:%x:%x",
-                              &a1, &a2, &a3, &a4, &a5, &a6);
-                       res->bssid[0] = a1;
-                       res->bssid[1] = a2;
-                       res->bssid[2] = a3;
-                       res->bssid[3] = a4;
-                       res->bssid[4] = a5;
-                       res->bssid[5] = a6;
-               }
-
-               num = cfdict_get_key_str(dict, "CAPABILITIES");
-               if (num) {
-                       if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
-                               res->caps = val;
-               }
-
-               num = cfdict_get_key_str(dict, "CHANNEL");
-               if (num) {
-                       if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
-                               res->freq = 2407 + val * 5;
-               }
-
-               num = cfdict_get_key_str(dict, "RSSI");
-               if (num) {
-                       if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
-                               res->level = val;
-               }
-
-               num = cfdict_get_key_str(dict, "NOISE");
-               if (num) {
-                       if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
-                               res->noise = val;
-               }
-
-               data = cfdict_get_key_str(dict, "IE");
-               if (data) {
-                       u8 *ptr = (u8 *) CFDataGetBytePtr(data);
-                       int len = CFDataGetLength(data);
-                       u8 *pos = ptr, *end = ptr + len;
-
-                       while (pos + 2 < end) {
-                               if (pos + 2 + pos[1] > end)
-                                       break;
-                               if (pos[0] == WLAN_EID_RSN &&
-                                   pos[1] <= SSID_MAX_WPA_IE_LEN) {
-                                       os_memcpy(res->rsn_ie, pos,
-                                                 2 + pos[1]);
-                                       res->rsn_ie_len = 2 + pos[1];
-                               }
-                               if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
-                                   pos[1] > 4 && pos[2] == 0x00 &&
-                                   pos[3] == 0x50 && pos[4] == 0xf2 &&
-                                   pos[5] == 0x01) {
-                                       os_memcpy(res->wpa_ie, pos,
-                                                 2 + pos[1]);
-                                       res->wpa_ie_len = 2 + pos[1];
-                               }
-
-                               pos = pos + 2 + pos[1];
-                       }
-               }
-       }
-
-       return num;
-}
-
-
-static void wpa_driver_iphone_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-       struct wpa_driver_iphone_data *drv = eloop_ctx;
-       u8 bssid[ETH_ALEN];
-
-       if (wpa_driver_iphone_get_bssid(drv, bssid) != 0) {
-               eloop_register_timeout(1, 0, wpa_driver_iphone_assoc_timeout,
-                                      drv, drv->ctx);
-               return;
-       }
-
-       wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
-}
-
-
-static int wpa_driver_iphone_associate(
-       void *priv, struct wpa_driver_associate_params *params)
-{
-       struct wpa_driver_iphone_data *drv = priv;
-       int i, num, err;
-       size_t ssid_len;
-       CFDictionaryRef bss = NULL;
-
-       /*
-        * TODO: Consider generating parameters instead of just using an entry
-        * from scan results in order to support ap_scan=2.
-        */
-
-       if (drv->scan_results == NULL) {
-               wpa_printf(MSG_DEBUG, "iPhone: No scan results - cannot "
-                          "associate");
-               return -1;
-       }
-
-       num = CFArrayGetCount(drv->scan_results);
-
-       for (i = 0; i < num; i++) {
-               CFDictionaryRef dict =
-                       CFArrayGetValueAtIndex(drv->scan_results, i);
-               CFDataRef data;
-
-               data = cfdict_get_key_str(dict, "SSID");
-               if (data == NULL)
-                       continue;
-
-               ssid_len = CFDataGetLength(data);
-               if (ssid_len != params->ssid_len ||
-                   os_memcmp(CFDataGetBytePtr(data), params->ssid, ssid_len)
-                   != 0)
-                       continue;
-
-               bss = dict;
-               break;
-       }
-
-       if (bss == NULL) {
-               wpa_printf(MSG_DEBUG, "iPhone: Could not find SSID from scan "
-                          "results - cannot associate");
-               return -1;
-       }
-
-       wpa_printf(MSG_DEBUG, "iPhone: Trying to associate with a BSS found "
-                  "from scan results");
-
-       err = Apple80211Associate(drv->wireless_ctx, bss, NULL);
-       if (err) {
-               wpa_printf(MSG_DEBUG, "iPhone: Apple80211Associate() failed: "
-                          "%d", err);
-               return -1;
-       }
-
-       /*
-        * Driver is actually already associated; report association from an
-        * eloop callback.
-        */
-       eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
-       eloop_register_timeout(0, 0, wpa_driver_iphone_assoc_timeout, drv,
-                              drv->ctx);
-
-       return 0;
-}
-
-
-static int wpa_driver_iphone_set_key(void *priv, wpa_alg alg, const u8 *addr,
-                                    int key_idx, int set_tx, const u8 *seq,
-                                    size_t seq_len, const u8 *key,
-                                    size_t key_len)
-{
-       /*
-        * TODO: Need to either support configuring PMK for 4-way handshake or
-        * PTK for TKIP/CCMP.
-        */
-       return -1;
-}
-
-
-static int wpa_driver_iphone_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
-       os_memset(capa, 0, sizeof(*capa));
-
-       capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-               WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-               WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
-               WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
-       capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
-               WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
-       capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
-               WPA_DRIVER_AUTH_LEAP;
-       capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
-
-       return 0;
-}
-
-
-static void * wpa_driver_iphone_init(void *ctx, const char *ifname)
-{
-       struct wpa_driver_iphone_data *drv;
-       int err;
-       char power;
-       CFStringRef name;
-       CFDictionaryRef dict;
-
-       drv = os_zalloc(sizeof(*drv));
-       if (drv == NULL)
-               return NULL;
-       drv->ctx = ctx;
-       err = Apple80211Open(&drv->wireless_ctx);
-       if (err) {
-               wpa_printf(MSG_ERROR, "iPhone: Apple80211Open failed: %d",
-                          err);
-               os_free(drv);
-               return NULL;
-       }
-
-       name = CFStringCreateWithCString(kCFAllocatorDefault, ifname,
-                                        kCFStringEncodingISOLatin1);
-       if (name == NULL) {
-               wpa_printf(MSG_ERROR, "iPhone: ifname -> CFString failed");
-               Apple80211Close(drv->wireless_ctx);
-               os_free(drv);
-               return NULL;
-       }
-
-       err = Apple80211BindToInterface(drv->wireless_ctx, name);
-       CFRelease(name);
-
-       if (err) {
-               wpa_printf(MSG_ERROR, "iPhone: Apple80211BindToInterface "
-                          "failed: %d", err);
-               Apple80211Close(drv->wireless_ctx);
-               os_free(drv);
-               return NULL;
-       }
-
-       err = Apple80211GetPower(drv->wireless_ctx, &power);
-       if (err)
-               wpa_printf(MSG_DEBUG, "iPhone: Apple80211GetPower failed: %d",
-                          err);
-
-       wpa_printf(MSG_DEBUG, "iPhone: Power=%d", power);
-
-       if (!power) {
-               drv->ctrl_power = 1;
-               err = Apple80211SetPower(drv->wireless_ctx, 1);
-               if (err) {
-                       wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower "
-                                  "failed: %d", err);
-                       Apple80211Close(drv->wireless_ctx);
-                       os_free(drv);
-                       return NULL;
-               }
-       }
-
-       err = Apple80211GetInfoCopy(drv->wireless_ctx, &dict);
-       if (err == 0) {
-               CFShow(dict);
-               CFRelease(dict);
-       } else {
-               printf("Apple80211GetInfoCopy: %d\n", err);
-       }
-
-       return drv;
-}
-
-
-static void wpa_driver_iphone_deinit(void *priv)
-{
-       struct wpa_driver_iphone_data *drv = priv;
-       int err;
-
-       eloop_cancel_timeout(wpa_driver_iphone_scan_timeout, drv, drv->ctx);
-       eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
-
-       if (drv->ctrl_power) {
-               wpa_printf(MSG_DEBUG, "iPhone: Power down the interface");
-               err = Apple80211SetPower(drv->wireless_ctx, 0);
-               if (err) {
-                       wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower(0) "
-                                  "failed: %d", err);
-               }
-       }
-
-       err = Apple80211Close(drv->wireless_ctx);
-       if (err) {
-               wpa_printf(MSG_DEBUG, "iPhone: Apple80211Close failed: %d",
-                          err);
-       }
-
-       if (drv->scan_results)
-               CFRelease(drv->scan_results);
-
-       os_free(drv);
-}
-
-
-const struct wpa_driver_ops wpa_driver_iphone_ops = {
-       .name = "iphone",
-       .desc = "iPhone/iPod touch Apple80211 driver",
-       .get_ssid = wpa_driver_iphone_get_ssid,
-       .get_bssid = wpa_driver_iphone_get_bssid,
-       .init = wpa_driver_iphone_init,
-       .deinit = wpa_driver_iphone_deinit,
-       .scan = wpa_driver_iphone_scan,
-       .get_scan_results = wpa_driver_iphone_get_scan_results,
-       .associate = wpa_driver_iphone_associate,
-       .set_key = wpa_driver_iphone_set_key,
-       .get_capa = wpa_driver_iphone_get_capa,
-};
diff --git a/src/drivers/driver_ipw.c b/src/drivers/driver_ipw.c
deleted file mode 100644 (file)
index 77984f9..0000000
+++ /dev/null
@@ -1,472 +0,0 @@
-/*
- * WPA Supplicant - driver interaction with Linux ipw2100/2200 drivers
- * Copyright (c) 2005 Zhu Yi <yi.zhu@intel.com>
- * Copyright (c) 2004 Lubomir Gelo <lgelo@cnc.sk>
- * Copyright (c) 2003-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.
- *
- * Please note that ipw2100/2200 drivers change to use generic Linux wireless
- * extensions if the kernel includes support for WE-18 or newer (Linux 2.6.13
- * or newer). driver_wext.c should be used in those cases.
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-
-#include "wireless_copy.h"
-#include "common.h"
-#include "driver.h"
-#include "driver_wext.h"
-
-struct wpa_driver_ipw_data {
-       void *wext; /* private data for driver_wext */
-       void *ctx;
-       char ifname[IFNAMSIZ + 1];
-       int sock;
-};
-
-/* following definitions must be kept in sync with ipw2100.c and ipw2200.c */
-
-#define IPW_IOCTL_WPA_SUPPLICANT               SIOCIWFIRSTPRIV+30
-
-#define IPW_CMD_SET_WPA_PARAM                  1
-#define        IPW_CMD_SET_WPA_IE                      2
-#define IPW_CMD_SET_ENCRYPTION                 3
-#define IPW_CMD_MLME                           4
-
-#define IPW_PARAM_WPA_ENABLED                  1
-#define IPW_PARAM_TKIP_COUNTERMEASURES         2
-#define IPW_PARAM_DROP_UNENCRYPTED             3
-#define IPW_PARAM_PRIVACY_INVOKED              4
-#define IPW_PARAM_AUTH_ALGS                    5
-#define IPW_PARAM_IEEE_802_1X                  6
-
-#define IPW_MLME_STA_DEAUTH                    1
-#define IPW_MLME_STA_DISASSOC                  2
-
-#define IPW_CRYPT_ERR_UNKNOWN_ALG              2
-#define IPW_CRYPT_ERR_UNKNOWN_ADDR             3
-#define IPW_CRYPT_ERR_CRYPT_INIT_FAILED                4
-#define IPW_CRYPT_ERR_KEY_SET_FAILED           5
-#define IPW_CRYPT_ERR_TX_KEY_SET_FAILED                6
-#define IPW_CRYPT_ERR_CARD_CONF_FAILED         7
-
-#define        IPW_CRYPT_ALG_NAME_LEN                  16
-
-struct ipw_param {
-       u32 cmd;
-       u8 sta_addr[ETH_ALEN];
-        union {
-               struct {
-                       u8 name;
-                       u32 value;
-               } wpa_param;
-               struct {
-                       u32 len;
-                       u8 reserved[32];
-                       u8 data[0];
-               } wpa_ie;
-               struct{
-                       u32 command;
-                       u32 reason_code;
-               } mlme;
-               struct {
-                       u8 alg[IPW_CRYPT_ALG_NAME_LEN];
-                       u8 set_tx;
-                       u32 err;
-                       u8 idx;
-                       u8 seq[8];
-                       u16 key_len;
-                       u8 key[0];
-               } crypt;
-
-       } u;
-};
-
-/* end of ipw2100.c and ipw2200.c code */
-
-static int wpa_driver_ipw_set_auth_alg(void *priv, int auth_alg);
-
-static int ipw_ioctl(struct wpa_driver_ipw_data *drv,
-                    struct ipw_param *param, int len, int show_err)
-{
-       struct iwreq iwr;
-
-       os_memset(&iwr, 0, sizeof(iwr));
-       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-       iwr.u.data.pointer = (caddr_t) param;
-       iwr.u.data.length = len;
-
-       if (ioctl(drv->sock, IPW_IOCTL_WPA_SUPPLICANT, &iwr) < 0) {
-               int ret = errno;
-               if (show_err) 
-                       perror("ioctl[IPW_IOCTL_WPA_SUPPLICANT]");
-               return ret;
-       }
-
-       return 0;
-}
-
-
-static void ipw_show_set_key_error(struct ipw_param *param)
-{
-       switch (param->u.crypt.err) {
-       case IPW_CRYPT_ERR_UNKNOWN_ALG:
-               wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
-                          param->u.crypt.alg);
-               wpa_printf(MSG_INFO, "You may need to load kernel module to "
-                          "register that algorithm.");
-               wpa_printf(MSG_INFO, "E.g., 'modprobe ieee80211_crypt_wep' for"
-                          " WEP.");
-               break;
-       case IPW_CRYPT_ERR_UNKNOWN_ADDR:
-               wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
-                          MAC2STR(param->sta_addr));
-               break;
-       case IPW_CRYPT_ERR_CRYPT_INIT_FAILED:
-               wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
-               break;
-       case IPW_CRYPT_ERR_KEY_SET_FAILED:
-               wpa_printf(MSG_INFO, "Key setting failed.");
-               break;
-       case IPW_CRYPT_ERR_TX_KEY_SET_FAILED:
-               wpa_printf(MSG_INFO, "TX key index setting failed.");
-               break;
-       case IPW_CRYPT_ERR_CARD_CONF_FAILED:
-               wpa_printf(MSG_INFO, "Card configuration failed.");
-               break;
-       }
-}
-
-
-static int ipw_set_wpa_ie(struct wpa_driver_ipw_data *drv,
-                         const u8 *wpa_ie, size_t wpa_ie_len)
-{
-       struct ipw_param *param;
-       int ret;
-       size_t blen = sizeof(*param) + wpa_ie_len;
-
-       param = os_zalloc(blen);
-       if (param == NULL)
-               return -1;
-
-       param->cmd = IPW_CMD_SET_WPA_IE;
-       param->u.wpa_ie.len = wpa_ie_len;
-       os_memcpy(param->u.wpa_ie.data, wpa_ie, wpa_ie_len);
-       
-       ret = ipw_ioctl(drv, param, blen, 1);
-
-       os_free(param);
-       return ret;
-}
-
-
-static int ipw_set_wpa_param(struct wpa_driver_ipw_data *drv, u8 name,
-                            u32 value)
-{
-       struct ipw_param param;
-
-       os_memset(&param, 0, sizeof(param));
-       param.cmd = IPW_CMD_SET_WPA_PARAM;
-       param.u.wpa_param.name = name;
-       param.u.wpa_param.value = value;
-
-       return ipw_ioctl(drv, &param, sizeof(param), 1);
-}
-
-
-static int ipw_mlme(struct wpa_driver_ipw_data *drv, const u8 *addr,
-                   int cmd, int reason)
-{
-       struct ipw_param param;
-
-       os_memset(&param, 0, sizeof(param));
-       os_memcpy(param.sta_addr, addr, ETH_ALEN);      
-       param.cmd = IPW_CMD_MLME;
-       param.u.mlme.command = cmd;
-       param.u.mlme.reason_code = reason;
-
-       return ipw_ioctl(drv, &param, sizeof(param), 1);
-}
-
-
-static int wpa_driver_ipw_set_wpa(void *priv, int enabled)
-{
-       struct wpa_driver_ipw_data *drv = priv;
-       int ret = 0;
-
-       wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-
-       if (!enabled && ipw_set_wpa_ie(drv, NULL, 0) < 0)
-               ret = -1;
-
-       if (ipw_set_wpa_param(drv, IPW_PARAM_WPA_ENABLED, enabled) < 0)
-               ret = -1;
-
-       return ret;
-}
-
-
-static int wpa_driver_ipw_set_key(const char *ifname, void *priv,
-                                 enum wpa_alg alg, const u8 *addr,
-                                 int key_idx, int set_tx,
-                                 const u8 *seq, size_t seq_len,
-                                 const u8 *key, size_t key_len)
-{
-       struct wpa_driver_ipw_data *drv = priv;
-       struct ipw_param *param;
-       u8 *buf;
-       size_t blen;
-       int ret = 0;
-       char *alg_name;
-
-       switch (alg) {
-       case WPA_ALG_NONE:
-               alg_name = "none";
-               break;
-       case WPA_ALG_WEP:
-               alg_name = "WEP";
-               break;
-       case WPA_ALG_TKIP:
-               alg_name = "TKIP";
-               break;
-       case WPA_ALG_CCMP:
-               alg_name = "CCMP";
-               break;
-       default:
-               return -1;
-       }
-
-       wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
-                  "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
-                  (unsigned long) seq_len, (unsigned long) key_len);
-
-       if (seq_len > 8)
-               return -2;
-
-       blen = sizeof(*param) + key_len;
-       buf = os_zalloc(blen);
-       if (buf == NULL)
-               return -1;
-
-       param = (struct ipw_param *) buf;
-       param->cmd = IPW_CMD_SET_ENCRYPTION;
-       os_memset(param->sta_addr, 0xff, ETH_ALEN);
-       os_strlcpy((char *) param->u.crypt.alg, alg_name,
-                  IPW_CRYPT_ALG_NAME_LEN);
-       param->u.crypt.set_tx = set_tx ? 1 : 0;
-       param->u.crypt.idx = key_idx;
-       os_memcpy(param->u.crypt.seq, seq, seq_len);
-       param->u.crypt.key_len = key_len;
-       os_memcpy((u8 *) (param + 1), key, key_len);
-
-       if (ipw_ioctl(drv, param, blen, 1)) {
-               wpa_printf(MSG_WARNING, "Failed to set encryption.");
-               ipw_show_set_key_error(param);
-               ret = -1;
-       }
-       os_free(buf);
-
-       return ret;
-}
-
-
-static int wpa_driver_ipw_set_countermeasures(void *priv, int enabled)
-{
-       struct wpa_driver_ipw_data *drv = priv;
-       wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-       return ipw_set_wpa_param(drv, IPW_PARAM_TKIP_COUNTERMEASURES,
-                                    enabled);
-
-}
-
-
-static int wpa_driver_ipw_set_drop_unencrypted(void *priv, int enabled)
-{
-       struct wpa_driver_ipw_data *drv = priv;
-       wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-       return ipw_set_wpa_param(drv, IPW_PARAM_DROP_UNENCRYPTED,
-                                    enabled);
-}
-
-
-static int wpa_driver_ipw_deauthenticate(void *priv, const u8 *addr,
-                                        int reason_code)
-{
-       struct wpa_driver_ipw_data *drv = priv;
-       return ipw_mlme(drv, addr, IPW_MLME_STA_DEAUTH, reason_code);
-}
-
-
-static int wpa_driver_ipw_disassociate(void *priv, const u8 *addr,
-                                      int reason_code)
-{
-       struct wpa_driver_ipw_data *drv = priv;
-       return ipw_mlme(drv, addr, IPW_MLME_STA_DISASSOC, reason_code);
-}
-
-
-static int
-wpa_driver_ipw_associate(void *priv, struct wpa_driver_associate_params *params)
-{
-       struct wpa_driver_ipw_data *drv = priv;
-       int ret = 0;
-       int unencrypted_eapol;
-
-       if (wpa_driver_ipw_set_auth_alg(drv, params->auth_alg) < 0)
-               ret = -1;
-       if (wpa_driver_ipw_set_drop_unencrypted(drv, params->drop_unencrypted)
-           < 0)
-               ret = -1;
-       if (ipw_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
-               ret = -1;
-       if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
-                                    params->ssid_len) < 0)
-               ret = -1;
-       if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
-               ret = -1;
-
-       if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
-           params->key_mgmt_suite == KEY_MGMT_PSK)
-               unencrypted_eapol = 0;
-       else
-               unencrypted_eapol = 1;
-       
-       if (ipw_set_wpa_param(drv, IPW_PARAM_IEEE_802_1X,
-                             unencrypted_eapol) < 0) {
-               wpa_printf(MSG_DEBUG, "ipw: Failed to configure "
-                          "ieee_802_1x param");
-       }
-
-       return ret;
-}
-
-
-static int wpa_driver_ipw_set_auth_alg(void *priv, int auth_alg)
-{
-       struct wpa_driver_ipw_data *drv = priv;
-       int algs = 0;
-
-       if (auth_alg & WPA_AUTH_ALG_OPEN)
-               algs |= 1;
-       if (auth_alg & WPA_AUTH_ALG_SHARED)
-               algs |= 2;
-       if (auth_alg & WPA_AUTH_ALG_LEAP)
-               algs |= 4;
-       if (algs == 0)
-               algs = 1; /* at least one algorithm should be set */
-
-       wpa_printf(MSG_DEBUG, "%s: auth_alg=0x%x", __FUNCTION__, algs);
-       return ipw_set_wpa_param(drv, IPW_PARAM_AUTH_ALGS, algs);
-}
-
-
-static int wpa_driver_ipw_get_bssid(void *priv, u8 *bssid)
-{
-       struct wpa_driver_ipw_data *drv = priv;
-       return wpa_driver_wext_get_bssid(drv->wext, bssid);
-}
-
-
-static int wpa_driver_ipw_get_ssid(void *priv, u8 *ssid)
-{
-       struct wpa_driver_ipw_data *drv = priv;
-       return wpa_driver_wext_get_ssid(drv->wext, ssid);
-}
-
-
-static int wpa_driver_ipw_scan(void *priv,
-                              struct wpa_driver_scan_params *params)
-{
-       struct wpa_driver_ipw_data *drv = priv;
-       return wpa_driver_wext_scan(drv->wext, params);
-}
-
-
-static struct wpa_scan_results * wpa_driver_ipw_get_scan_results(void *priv)
-{
-       struct wpa_driver_ipw_data *drv = priv;
-       return wpa_driver_wext_get_scan_results(drv->wext);
-}
-
-
-static int wpa_driver_ipw_set_operstate(void *priv, int state)
-{
-       struct wpa_driver_ipw_data *drv = priv;
-       return wpa_driver_wext_set_operstate(drv->wext, state);
-}
-
-
-static void * wpa_driver_ipw_init(void *ctx, const char *ifname)
-{
-       struct wpa_driver_ipw_data *drv;
-       int ver;
-
-       wpa_printf(MSG_DEBUG, "%s is called", __FUNCTION__);
-       drv = os_zalloc(sizeof(*drv));
-       if (drv == NULL)
-               return NULL;
-       drv->wext = wpa_driver_wext_init(ctx, ifname);
-       if (drv->wext == NULL) {
-               os_free(drv);
-               return NULL;
-       }
-
-       ver = wpa_driver_wext_get_version(drv->wext);
-       if (ver >= 18) {
-               wpa_printf(MSG_WARNING, "Linux wireless extensions version %d "
-                          "detected.", ver);
-               wpa_printf(MSG_WARNING, "ipw2x00 driver uses driver_wext "
-                          "(-Dwext) instead of driver_ipw.");
-       }
-
-       drv->ctx = ctx;
-       os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-       drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-       if (drv->sock < 0) {
-               wpa_driver_wext_deinit(drv->wext);
-               os_free(drv);
-               return NULL;
-       }
-
-       wpa_driver_ipw_set_wpa(drv, 1);
-
-       return drv;
-}
-
-
-static void wpa_driver_ipw_deinit(void *priv)
-{
-       struct wpa_driver_ipw_data *drv = priv;
-       wpa_driver_ipw_set_wpa(drv, 0);
-       wpa_driver_wext_deinit(drv->wext);
-       close(drv->sock);
-       os_free(drv);
-}
-
-
-const struct wpa_driver_ops wpa_driver_ipw_ops = {
-       .name = "ipw",
-       .desc = "Intel ipw2100/2200 driver (old; use wext with Linux 2.6.13 "
-       "or newer)",
-       .get_bssid = wpa_driver_ipw_get_bssid,
-       .get_ssid = wpa_driver_ipw_get_ssid,
-       .set_key = wpa_driver_ipw_set_key,
-       .set_countermeasures = wpa_driver_ipw_set_countermeasures,
-       .scan2 = wpa_driver_ipw_scan,
-       .get_scan_results2 = wpa_driver_ipw_get_scan_results,
-       .deauthenticate = wpa_driver_ipw_deauthenticate,
-       .disassociate = wpa_driver_ipw_disassociate,
-       .associate = wpa_driver_ipw_associate,
-       .init = wpa_driver_ipw_init,
-       .deinit = wpa_driver_ipw_deinit,
-       .set_operstate = wpa_driver_ipw_set_operstate,
-};
index 8687404..edb086f 100644 (file)
@@ -27,7 +27,7 @@
 #include "driver_wext.h"
 #include "eloop.h"
 #include "common/ieee802_11_defs.h"
-#include "wireless_copy.h"
+#include "linux_wext.h"
 
 /*
  * Avoid conflicts with wpa_supplicant definitions by undefining a definition.
@@ -69,8 +69,7 @@
 #define MADWIFI_NG
 #endif /* IEEE80211_IOCTL_SETWMMPARAMS */
 
-
-#ifdef HOSTAPD
+#define WPA_KEY_RSC_LEN 8
 
 #include "priv_netlink.h"
 #include "netlink.h"
@@ -461,7 +460,7 @@ wpa_driver_madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg,
        memset(&wk, 0, sizeof(wk));
        wk.ik_type = cipher;
        wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;
-       if (addr == NULL) {
+       if (addr == NULL || is_broadcast_ether_addr(addr)) {
                memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
                wk.ik_keyix = key_idx;
                wk.ik_flags |= IEEE80211_KEY_DEFAULT;
@@ -733,6 +732,8 @@ static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
 
        os_memset(&event, 0, sizeof(event));
        event.rx_probe_req.sa = mgmt->sa;
+       event.rx_probe_req.da = mgmt->da;
+       event.rx_probe_req.bssid = mgmt->bssid;
        event.rx_probe_req.ie = mgmt->u.probe_req.variable;
        event.rx_probe_req.ie_len =
                len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
@@ -787,7 +788,8 @@ madwifi_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
 
 static int
 madwifi_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
-                     const struct wpabuf *proberesp)
+                     const struct wpabuf *proberesp,
+                     const struct wpabuf *assocresp)
 {
        if (madwifi_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL,
                               beacon ? wpabuf_len(beacon) : 0,
@@ -802,6 +804,24 @@ madwifi_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
 #define madwifi_set_ap_wps_ie NULL
 #endif /* CONFIG_WPS */
 
+static int madwifi_set_freq(void *priv, struct hostapd_freq_params *freq)
+{
+       struct madwifi_driver_data *drv = priv;
+       struct iwreq iwr;
+
+       os_memset(&iwr, 0, sizeof(iwr));
+       os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+       iwr.u.freq.m = freq->channel;
+       iwr.u.freq.e = 0;
+
+       if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
+               perror("ioctl[SIOCSIWFREQ]");
+               return -1;
+       }
+
+       return 0;
+}
+
 static void
 madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
 {
@@ -846,7 +866,7 @@ madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
                ielen += 2;
 
 no_ie:
-       drv_event_assoc(hapd, addr, iebuf, ielen);
+       drv_event_assoc(hapd, addr, iebuf, ielen, 0);
 
        if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
                /* Cached accounting data is not valid anymore. */
@@ -1065,7 +1085,7 @@ madwifi_wireless_event_init(struct madwifi_driver_data *drv)
 
 static int
 madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
-                  int encrypt, const u8 *own_addr)
+                  int encrypt, const u8 *own_addr, u32 flags)
 {
        struct madwifi_driver_data *drv = priv;
        unsigned char buf[3000];
@@ -1272,554 +1292,11 @@ madwifi_commit(void *priv)
        return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);
 }
 
-#else /* HOSTAPD */
-
-struct wpa_driver_madwifi_data {
-       void *wext; /* private data for driver_wext */
-       void *ctx;
-       char ifname[IFNAMSIZ + 1];
-       int sock;
-};
-
-static int wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg);
-static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies,
-                                              size_t ies_len);
-
-
-static int
-set80211priv(struct wpa_driver_madwifi_data *drv, int op, void *data, int len,
-            int show_err)
-{
-       struct iwreq iwr;
-
-       os_memset(&iwr, 0, sizeof(iwr));
-       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-       if (len < IFNAMSIZ &&
-           op != IEEE80211_IOCTL_SET_APPIEBUF) {
-               /*
-                * Argument data fits inline; put it there.
-                */
-               os_memcpy(iwr.u.name, data, len);
-       } else {
-               /*
-                * Argument data too big for inline transfer; setup a
-                * parameter block instead; the kernel will transfer
-                * the data for the driver.
-                */
-               iwr.u.data.pointer = data;
-               iwr.u.data.length = len;
-       }
-
-       if (ioctl(drv->sock, op, &iwr) < 0) {
-               if (show_err) {
-#ifdef MADWIFI_NG
-                       int first = IEEE80211_IOCTL_SETPARAM;
-                       int last = IEEE80211_IOCTL_KICKMAC;
-                       static const char *opnames[] = {
-                               "ioctl[IEEE80211_IOCTL_SETPARAM]",
-                               "ioctl[IEEE80211_IOCTL_GETPARAM]",
-                               "ioctl[IEEE80211_IOCTL_SETMODE]",
-                               "ioctl[IEEE80211_IOCTL_GETMODE]",
-                               "ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
-                               "ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
-                               "ioctl[IEEE80211_IOCTL_SETCHANLIST]",
-                               "ioctl[IEEE80211_IOCTL_GETCHANLIST]",
-                               "ioctl[IEEE80211_IOCTL_CHANSWITCH]",
-                               NULL,
-                               "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
-                               "ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
-                               NULL,
-                               "ioctl[IEEE80211_IOCTL_GETCHANINFO]",
-                               "ioctl[IEEE80211_IOCTL_SETOPTIE]",
-                               "ioctl[IEEE80211_IOCTL_GETOPTIE]",
-                               "ioctl[IEEE80211_IOCTL_SETMLME]",
-                               NULL,
-                               "ioctl[IEEE80211_IOCTL_SETKEY]",
-                               NULL,
-                               "ioctl[IEEE80211_IOCTL_DELKEY]",
-                               NULL,
-                               "ioctl[IEEE80211_IOCTL_ADDMAC]",
-                               NULL,
-                               "ioctl[IEEE80211_IOCTL_DELMAC]",
-                               NULL,
-                               "ioctl[IEEE80211_IOCTL_WDSMAC]",
-                               NULL,
-                               "ioctl[IEEE80211_IOCTL_WDSDELMAC]",
-                               NULL,
-                               "ioctl[IEEE80211_IOCTL_KICKMAC]",
-                       };
-#else /* MADWIFI_NG */
-                       int first = IEEE80211_IOCTL_SETPARAM;
-                       int last = IEEE80211_IOCTL_CHANLIST;
-                       static const char *opnames[] = {
-                               "ioctl[IEEE80211_IOCTL_SETPARAM]",
-                               "ioctl[IEEE80211_IOCTL_GETPARAM]",
-                               "ioctl[IEEE80211_IOCTL_SETKEY]",
-                               "ioctl[IEEE80211_IOCTL_GETKEY]",
-                               "ioctl[IEEE80211_IOCTL_DELKEY]",
-                               NULL,
-                               "ioctl[IEEE80211_IOCTL_SETMLME]",
-                               NULL,
-                               "ioctl[IEEE80211_IOCTL_SETOPTIE]",
-                               "ioctl[IEEE80211_IOCTL_GETOPTIE]",
-                               "ioctl[IEEE80211_IOCTL_ADDMAC]",
-                               NULL,
-                               "ioctl[IEEE80211_IOCTL_DELMAC]",
-                               NULL,
-                               "ioctl[IEEE80211_IOCTL_CHANLIST]",
-                       };
-#endif /* MADWIFI_NG */
-                       int idx = op - first;
-                       if (first <= op && op <= last &&
-                           idx < (int) (sizeof(opnames) / sizeof(opnames[0]))
-                           && opnames[idx])
-                               perror(opnames[idx]);
-                       else
-                               perror("ioctl[unknown???]");
-               }
-               return -1;
-       }
-       return 0;
-}
-
-static int
-set80211param(struct wpa_driver_madwifi_data *drv, int op, int arg,
-             int show_err)
-{
-       struct iwreq iwr;
-
-       os_memset(&iwr, 0, sizeof(iwr));
-       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-       iwr.u.mode = op;
-       os_memcpy(iwr.u.name+sizeof(u32), &arg, sizeof(arg));
-
-       if (ioctl(drv->sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
-               if (show_err) 
-                       perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
-               return -1;
-       }
-       return 0;
-}
-
-static int
-wpa_driver_madwifi_set_wpa_ie(struct wpa_driver_madwifi_data *drv,
-                             const u8 *wpa_ie, size_t wpa_ie_len)
-{
-       struct iwreq iwr;
-
-       os_memset(&iwr, 0, sizeof(iwr));
-       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-       /* NB: SETOPTIE is not fixed-size so must not be inlined */
-       iwr.u.data.pointer = (void *) wpa_ie;
-       iwr.u.data.length = wpa_ie_len;
-
-       if (ioctl(drv->sock, IEEE80211_IOCTL_SETOPTIE, &iwr) < 0) {
-               perror("ioctl[IEEE80211_IOCTL_SETOPTIE]");
-               return -1;
-       }
-       return 0;
-}
-
-static int
-wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data *drv, int key_idx,
-                          const u8 *addr)
-{
-       struct ieee80211req_del_key wk;
-
-       wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __FUNCTION__, key_idx);
-       os_memset(&wk, 0, sizeof(wk));
-       wk.idk_keyix = key_idx;
-       if (addr != NULL)
-               os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
-
-       return set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk), 1);
-}
-
-static int
-wpa_driver_madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg,
-                          const u8 *addr, int key_idx, int set_tx,
-                          const u8 *seq, size_t seq_len,
-                          const u8 *key, size_t key_len)
-{
-       struct wpa_driver_madwifi_data *drv = priv;
-       struct ieee80211req_key wk;
-       char *alg_name;
-       u_int8_t cipher;
-
-       if (alg == WPA_ALG_NONE)
-               return wpa_driver_madwifi_del_key(drv, key_idx, addr);
-
-       switch (alg) {
-       case WPA_ALG_WEP:
-               if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
-                                             ETH_ALEN) == 0) {
-                       /*
-                        * madwifi did not seem to like static WEP key
-                        * configuration with IEEE80211_IOCTL_SETKEY, so use
-                        * Linux wireless extensions ioctl for this.
-                        */
-                       return wpa_driver_wext_set_key(ifname, drv->wext, alg,
-                                                      addr, key_idx, set_tx,
-                                                      seq, seq_len,
-                                                      key, key_len);
-               }
-               alg_name = "WEP";
-               cipher = IEEE80211_CIPHER_WEP;
-               break;
-       case WPA_ALG_TKIP:
-               alg_name = "TKIP";
-               cipher = IEEE80211_CIPHER_TKIP;
-               break;
-       case WPA_ALG_CCMP:
-               alg_name = "CCMP";
-               cipher = IEEE80211_CIPHER_AES_CCM;
-               break;
-       default:
-               wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
-                       __FUNCTION__, alg);
-               return -1;
-       }
-
-       wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
-                  "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
-                  (unsigned long) seq_len, (unsigned long) key_len);
-
-       if (seq_len > sizeof(u_int64_t)) {
-               wpa_printf(MSG_DEBUG, "%s: seq_len %lu too big",
-                          __FUNCTION__, (unsigned long) seq_len);
-               return -2;
-       }
-       if (key_len > sizeof(wk.ik_keydata)) {
-               wpa_printf(MSG_DEBUG, "%s: key length %lu too big",
-                          __FUNCTION__, (unsigned long) key_len);
-               return -3;
-       }
-
-       os_memset(&wk, 0, sizeof(wk));
-       wk.ik_type = cipher;
-       wk.ik_flags = IEEE80211_KEY_RECV;
-       if (addr == NULL ||
-           os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
-               wk.ik_flags |= IEEE80211_KEY_GROUP;
-       if (set_tx) {
-               wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
-               os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
-       } else
-               os_memset(wk.ik_macaddr, 0, IEEE80211_ADDR_LEN);
-       wk.ik_keyix = key_idx;
-       wk.ik_keylen = key_len;
-#ifdef WORDS_BIGENDIAN
-#define WPA_KEY_RSC_LEN 8
-       {
-               size_t i;
-               u8 tmp[WPA_KEY_RSC_LEN];
-               os_memset(tmp, 0, sizeof(tmp));
-               for (i = 0; i < seq_len; i++)
-                       tmp[WPA_KEY_RSC_LEN - i - 1] = seq[i];
-               os_memcpy(&wk.ik_keyrsc, tmp, WPA_KEY_RSC_LEN);
-       }
-#else /* WORDS_BIGENDIAN */
-       os_memcpy(&wk.ik_keyrsc, seq, seq_len);
-#endif /* WORDS_BIGENDIAN */
-       os_memcpy(wk.ik_keydata, key, key_len);
-
-       return set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk), 1);
-}
-
-static int
-wpa_driver_madwifi_set_countermeasures(void *priv, int enabled)
-{
-       struct wpa_driver_madwifi_data *drv = priv;
-       wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-       return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled, 1);
-}
-
-static int
-wpa_driver_madwifi_deauthenticate(void *priv, const u8 *addr, int reason_code)
-{
-       struct wpa_driver_madwifi_data *drv = priv;
-       struct ieee80211req_mlme mlme;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-       mlme.im_op = IEEE80211_MLME_DEAUTH;
-       mlme.im_reason = reason_code;
-       os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
-       return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
-}
-
-static int
-wpa_driver_madwifi_disassociate(void *priv, const u8 *addr, int reason_code)
-{
-       struct wpa_driver_madwifi_data *drv = priv;
-       struct ieee80211req_mlme mlme;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-       mlme.im_op = IEEE80211_MLME_DISASSOC;
-       mlme.im_reason = reason_code;
-       os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
-       return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
-}
-
-static int
-wpa_driver_madwifi_associate(void *priv,
-                            struct wpa_driver_associate_params *params)
-{
-       struct wpa_driver_madwifi_data *drv = priv;
-       struct ieee80211req_mlme mlme;
-       int ret = 0, privacy = 1;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       if (set80211param(drv, IEEE80211_PARAM_DROPUNENCRYPTED,
-                         params->drop_unencrypted, 1) < 0)
-               ret = -1;
-       if (wpa_driver_madwifi_set_auth_alg(drv, params->auth_alg) < 0)
-               ret = -1;
-
-       /*
-        * NB: Don't need to set the freq or cipher-related state as
-        *     this is implied by the bssid which is used to locate
-        *     the scanned node state which holds it.  The ssid is
-        *     needed to disambiguate an AP that broadcasts multiple
-        *     ssid's but uses the same bssid.
-        */
-       /* XXX error handling is wrong but unclear what to do... */
-       if (wpa_driver_madwifi_set_wpa_ie(drv, params->wpa_ie,
-                                         params->wpa_ie_len) < 0)
-               ret = -1;
-
-       if (params->pairwise_suite == CIPHER_NONE &&
-           params->group_suite == CIPHER_NONE &&
-           params->key_mgmt_suite == KEY_MGMT_NONE &&
-           params->wpa_ie_len == 0)
-               privacy = 0;
-
-       if (set80211param(drv, IEEE80211_PARAM_PRIVACY, privacy, 1) < 0)
-               ret = -1;
-
-       if (params->wpa_ie_len &&
-           set80211param(drv, IEEE80211_PARAM_WPA,
-                         params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1, 1) < 0)
-               ret = -1;
-
-       if (params->bssid == NULL) {
-               /* ap_scan=2 mode - driver takes care of AP selection and
-                * roaming */
-               /* FIX: this does not seem to work; would probably need to
-                * change something in the driver */
-               if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0)
-                       ret = -1;
-
-               if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
-                                            params->ssid_len) < 0)
-                       ret = -1;
-       } else {
-               if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0)
-                       ret = -1;
-               if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
-                                            params->ssid_len) < 0)
-                       ret = -1;
-               os_memset(&mlme, 0, sizeof(mlme));
-               mlme.im_op = IEEE80211_MLME_ASSOC;
-               os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
-               if (set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
-                                sizeof(mlme), 1) < 0) {
-                       wpa_printf(MSG_DEBUG, "%s: SETMLME[ASSOC] failed",
-                                  __func__);
-                       ret = -1;
-               }
-       }
-
-       return ret;
-}
-
-static int
-wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg)
-{
-       struct wpa_driver_madwifi_data *drv = priv;
-       int authmode;
-
-       if ((auth_alg & WPA_AUTH_ALG_OPEN) &&
-           (auth_alg & WPA_AUTH_ALG_SHARED))
-               authmode = IEEE80211_AUTH_AUTO;
-       else if (auth_alg & WPA_AUTH_ALG_SHARED)
-               authmode = IEEE80211_AUTH_SHARED;
-       else
-               authmode = IEEE80211_AUTH_OPEN;
-
-       return set80211param(drv, IEEE80211_PARAM_AUTHMODE, authmode, 1);
-}
-
-static int
-wpa_driver_madwifi_scan(void *priv, struct wpa_driver_scan_params *params)
-{
-       struct wpa_driver_madwifi_data *drv = priv;
-       struct iwreq iwr;
-       int ret = 0;
-       const u8 *ssid = params->ssids[0].ssid;
-       size_t ssid_len = params->ssids[0].ssid_len;
-
-       wpa_driver_madwifi_set_probe_req_ie(drv, params->extra_ies,
-                                           params->extra_ies_len);
-
-       os_memset(&iwr, 0, sizeof(iwr));
-       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-       /* set desired ssid before scan */
-       /* FIX: scan should not break the current association, so using
-        * set_ssid may not be the best way of doing this.. */
-       if (wpa_driver_wext_set_ssid(drv->wext, ssid, ssid_len) < 0)
-               ret = -1;
-
-       if (ioctl(drv->sock, SIOCSIWSCAN, &iwr) < 0) {
-               perror("ioctl[SIOCSIWSCAN]");
-               ret = -1;
-       }
-
-       /*
-        * madwifi delivers a scan complete event so no need to poll, but
-        * register a backup timeout anyway to make sure that we recover even
-        * if the driver does not send this event for any reason. This timeout
-        * will only be used if the event is not delivered (event handler will
-        * cancel the timeout).
-        */
-       eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
-                            drv->ctx);
-       eloop_register_timeout(30, 0, wpa_driver_wext_scan_timeout, drv->wext,
-                              drv->ctx);
-
-       return ret;
-}
-
-static int wpa_driver_madwifi_get_bssid(void *priv, u8 *bssid)
-{
-       struct wpa_driver_madwifi_data *drv = priv;
-       return wpa_driver_wext_get_bssid(drv->wext, bssid);
-}
-
-
-static int wpa_driver_madwifi_get_ssid(void *priv, u8 *ssid)
-{
-       struct wpa_driver_madwifi_data *drv = priv;
-       return wpa_driver_wext_get_ssid(drv->wext, ssid);
-}
-
-
-static struct wpa_scan_results *
-wpa_driver_madwifi_get_scan_results(void *priv)
-{
-       struct wpa_driver_madwifi_data *drv = priv;
-       return wpa_driver_wext_get_scan_results(drv->wext);
-}
-
-
-static int wpa_driver_madwifi_set_operstate(void *priv, int state)
-{
-       struct wpa_driver_madwifi_data *drv = priv;
-       return wpa_driver_wext_set_operstate(drv->wext, state);
-}
-
-
-static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies,
-                                              size_t ies_len)
-{
-       struct ieee80211req_getset_appiebuf *probe_req_ie;
-       int ret;
-
-       probe_req_ie = os_malloc(sizeof(*probe_req_ie) + ies_len);
-       if (probe_req_ie == NULL)
-               return -1;
-
-       probe_req_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_REQ;
-       probe_req_ie->app_buflen = ies_len;
-       os_memcpy(probe_req_ie->app_buf, ies, ies_len);
-
-       ret = set80211priv(priv, IEEE80211_IOCTL_SET_APPIEBUF, probe_req_ie,
-                          sizeof(struct ieee80211req_getset_appiebuf) +
-                          ies_len, 1);
-
-       os_free(probe_req_ie);
-
-       return ret;
-}
-
-
-static void * wpa_driver_madwifi_init(void *ctx, const char *ifname)
-{
-       struct wpa_driver_madwifi_data *drv;
-
-       drv = os_zalloc(sizeof(*drv));
-       if (drv == NULL)
-               return NULL;
-       drv->wext = wpa_driver_wext_init(ctx, ifname);
-       if (drv->wext == NULL)
-               goto fail;
-
-       drv->ctx = ctx;
-       os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-       drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-       if (drv->sock < 0)
-               goto fail2;
-
-       if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0) {
-               wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
-                          "roaming", __FUNCTION__);
-               goto fail3;
-       }
-
-       if (set80211param(drv, IEEE80211_PARAM_WPA, 3, 1) < 0) {
-               wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support",
-                          __FUNCTION__);
-               goto fail3;
-       }
-
-       return drv;
-
-fail3:
-       close(drv->sock);
-fail2:
-       wpa_driver_wext_deinit(drv->wext);
-fail:
-       os_free(drv);
-       return NULL;
-}
-
-
-static void wpa_driver_madwifi_deinit(void *priv)
-{
-       struct wpa_driver_madwifi_data *drv = priv;
-
-       if (wpa_driver_madwifi_set_wpa_ie(drv, NULL, 0) < 0) {
-               wpa_printf(MSG_DEBUG, "%s: failed to clear WPA IE",
-                          __FUNCTION__);
-       }
-       if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0) {
-               wpa_printf(MSG_DEBUG, "%s: failed to enable driver-based "
-                          "roaming", __FUNCTION__);
-       }
-       if (set80211param(drv, IEEE80211_PARAM_PRIVACY, 0, 1) < 0) {
-               wpa_printf(MSG_DEBUG, "%s: failed to disable forced Privacy "
-                          "flag", __FUNCTION__);
-       }
-       if (set80211param(drv, IEEE80211_PARAM_WPA, 0, 1) < 0) {
-               wpa_printf(MSG_DEBUG, "%s: failed to disable WPA",
-                          __FUNCTION__);
-       }
-
-       wpa_driver_wext_deinit(drv->wext);
-
-       close(drv->sock);
-       os_free(drv);
-}
-
-#endif /* HOSTAPD */
-
 
 const struct wpa_driver_ops wpa_driver_madwifi_ops = {
        .name                   = "madwifi",
        .desc                   = "MADWIFI 802.11 support (Atheros, etc.)",
        .set_key                = wpa_driver_madwifi_set_key,
-#ifdef HOSTAPD
        .hapd_init              = madwifi_init,
        .hapd_deinit            = madwifi_deinit,
        .set_ieee8021x          = madwifi_set_ieee8021x,
@@ -1838,17 +1315,5 @@ const struct wpa_driver_ops wpa_driver_madwifi_ops = {
        .sta_clear_stats        = madwifi_sta_clear_stats,
        .commit                 = madwifi_commit,
        .set_ap_wps_ie          = madwifi_set_ap_wps_ie,
-#else /* HOSTAPD */
-       .get_bssid              = wpa_driver_madwifi_get_bssid,
-       .get_ssid               = wpa_driver_madwifi_get_ssid,
-       .init                   = wpa_driver_madwifi_init,
-       .deinit                 = wpa_driver_madwifi_deinit,
-       .set_countermeasures    = wpa_driver_madwifi_set_countermeasures,
-       .scan2                  = wpa_driver_madwifi_scan,
-       .get_scan_results2      = wpa_driver_madwifi_get_scan_results,
-       .deauthenticate         = wpa_driver_madwifi_deauthenticate,
-       .disassociate           = wpa_driver_madwifi_disassociate,
-       .associate              = wpa_driver_madwifi_associate,
-       .set_operstate          = wpa_driver_madwifi_set_operstate,
-#endif /* HOSTAPD */
+       .set_freq               = madwifi_set_freq,
 };
index 462dd81..dbe9a28 100644 (file)
@@ -1001,8 +1001,7 @@ static int wpa_driver_ndis_set_key(const char *ifname, void *priv,
        int res, pairwise;
        u8 bssid[ETH_ALEN];
 
-       if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
-                                     ETH_ALEN) == 0) {
+       if (addr == NULL || is_broadcast_ether_addr(addr)) {
                /* Group Key */
                pairwise = 0;
                if (wpa_driver_ndis_get_bssid(drv, bssid) < 0)
@@ -1066,6 +1065,7 @@ wpa_driver_ndis_associate(void *priv,
 {
        struct wpa_driver_ndis_data *drv = priv;
        u32 auth_mode, encr, priv_mode, mode;
+       u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
        drv->mode = params->mode;
 
@@ -1091,7 +1091,6 @@ wpa_driver_ndis_associate(void *priv,
        if (params->key_mgmt_suite == KEY_MGMT_NONE ||
            params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) {
                /* Re-set WEP keys if static WEP configuration is used. */
-               u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
                int i;
                for (i = 0; i < 4; i++) {
                        if (!params->wep_key[i])
@@ -1125,6 +1124,22 @@ wpa_driver_ndis_associate(void *priv,
        } else if (params->key_mgmt_suite == KEY_MGMT_WPS) {
                auth_mode = Ndis802_11AuthModeOpen;
                priv_mode = Ndis802_11PrivFilterAcceptAll;
+               if (params->wps == WPS_MODE_PRIVACY) {
+                       u8 dummy_key[5] = { 0x11, 0x22, 0x33, 0x44, 0x55 };
+                       /*
+                        * Some NDIS drivers refuse to associate in open mode
+                        * configuration due to Privacy field mismatch, so use
+                        * a workaround to make the configuration look like
+                        * matching one for WPS provisioning.
+                        */
+                       wpa_printf(MSG_DEBUG, "NDIS: Set dummy WEP key as a "
+                                  "workaround to allow driver to associate "
+                                  "for WPS");
+                       wpa_driver_ndis_set_key(drv->ifname, drv, WPA_ALG_WEP,
+                                               bcast, 0, 1,
+                                               NULL, 0, dummy_key,
+                                               sizeof(dummy_key));
+               }
 #endif /* CONFIG_WPS */
        } else {
                priv_mode = Ndis802_11PrivFilter8021xWEP;
@@ -1148,6 +1163,12 @@ wpa_driver_ndis_associate(void *priv,
                encr = Ndis802_11Encryption1Enabled;
                break;
        case CIPHER_NONE:
+#ifdef CONFIG_WPS
+               if (params->wps == WPS_MODE_PRIVACY) {
+                       encr = Ndis802_11Encryption1Enabled;
+                       break;
+               }
+#endif /* CONFIG_WPS */
                if (params->group_suite == CIPHER_CCMP)
                        encr = Ndis802_11Encryption3Enabled;
                else if (params->group_suite == CIPHER_TKIP)
@@ -1156,7 +1177,14 @@ wpa_driver_ndis_associate(void *priv,
                        encr = Ndis802_11EncryptionDisabled;
                break;
        default:
+#ifdef CONFIG_WPS
+               if (params->wps == WPS_MODE_PRIVACY) {
+                       encr = Ndis802_11Encryption1Enabled;
+                       break;
+               }
+#endif /* CONFIG_WPS */
                encr = Ndis802_11EncryptionDisabled;
+               break;
        };
 
        if (ndis_set_oid(drv, OID_802_11_PRIVACY_FILTER,
@@ -3185,94 +3213,33 @@ wpa_driver_ndis_get_interfaces(void *global_priv)
 }
 
 
-const struct wpa_driver_ops wpa_driver_ndis_ops = {
-       "ndis",
-       "Windows NDIS driver",
-       wpa_driver_ndis_get_bssid,
-       wpa_driver_ndis_get_ssid,
-       wpa_driver_ndis_set_key,
-       wpa_driver_ndis_init,
-       wpa_driver_ndis_deinit,
-       NULL /* set_param */,
-       NULL /* set_countermeasures */,
-       wpa_driver_ndis_deauthenticate,
-       wpa_driver_ndis_disassociate,
-       wpa_driver_ndis_associate,
-       wpa_driver_ndis_add_pmkid,
-       wpa_driver_ndis_remove_pmkid,
-       wpa_driver_ndis_flush_pmkid,
-       wpa_driver_ndis_get_capa,
-       wpa_driver_ndis_poll,
-       wpa_driver_ndis_get_ifname,
-       wpa_driver_ndis_get_mac_addr,
-       NULL /* send_eapol */,
-       NULL /* set_operstate */,
-       NULL /* mlme_setprotection */,
-       NULL /* get_hw_feature_data */,
-       NULL /* set_channel */,
-       NULL /* set_ssid */,
-       NULL /* set_bssid */,
-       NULL /* send_mlme */,
-       NULL /* mlme_add_sta */,
-       NULL /* mlme_remove_sta */,
-       NULL /* update_ft_ies */,
-       NULL /* send_ft_action */,
-       wpa_driver_ndis_get_scan_results,
-       NULL /* set_country */,
-       NULL /* global_init */,
-       NULL /* global_deinit */,
-       NULL /* init2 */,
-       wpa_driver_ndis_get_interfaces,
-       wpa_driver_ndis_scan,
-       NULL /* authenticate */,
-       NULL /* set_beacon */,
-       NULL /* hapd_init */,
-       NULL /* hapd_deinit */,
-       NULL /* set_ieee8021x */,
-       NULL /* set_privacy */,
-       NULL /* get_seqnum */,
-       NULL /* flush */,
-       NULL /* set_generic_elem */,
-       NULL /* read_sta_data */,
-       NULL /* hapd_send_eapol */,
-       NULL /* sta_deauth */,
-       NULL /* sta_disassoc */,
-       NULL /* sta_remove */,
-       NULL /* hapd_get_ssid */,
-       NULL /* hapd_set_ssid */,
-       NULL /* hapd_set_countermeasures */,
-       NULL /* sta_add */,
-       NULL /* get_inact_sec */,
-       NULL /* sta_clear_stats */,
-       NULL /* set_freq */,
-       NULL /* set_rts */,
-       NULL /* set_frag */,
-       NULL /* sta_set_flags */,
-       NULL /* set_rate_sets */,
-       NULL /* set_cts_protect */,
-       NULL /* set_preamble */,
-       NULL /* set_short_slot_time */,
-       NULL /* set_tx_queue_params */,
-       NULL /* valid_bss_mask */,
-       NULL /* if_add */,
-       NULL /* if_remove */,
-       NULL /* set_sta_vlan */,
-       NULL /* commit */,
-       NULL /* send_ether */,
-       NULL /* set_radius_acl_auth */,
-       NULL /* set_radius_acl_expire */,
-       NULL /* set_ht_params */,
-       NULL /* set_ap_wps_ie */,
-       NULL /* set_supp_port */,
-       NULL /* set_wds_sta */,
-       NULL /* send_action */,
-       NULL /* remain_on_channel */,
-       NULL /* cancel_remain_on_channel */,
-       NULL /* probe_req_report */,
-       NULL /* disable_11b_rates */,
-       NULL /* deinit_ap */,
-       NULL /* suspend */,
-       NULL /* resume */,
-       NULL /* signal_monitor */,
-       NULL /* send_frame */
-};
+static const char *ndis_drv_name = "ndis";
+static const char *ndis_drv_desc = "Windows NDIS driver";
+
+struct wpa_driver_ops wpa_driver_ndis_ops;
+
+void driver_ndis_init_ops(void)
+{
+       os_memset(&wpa_driver_ndis_ops, 0, sizeof(wpa_driver_ndis_ops));
+       wpa_driver_ndis_ops.name = ndis_drv_name;
+       wpa_driver_ndis_ops.desc = ndis_drv_desc;
+       wpa_driver_ndis_ops.get_bssid = wpa_driver_ndis_get_bssid;
+       wpa_driver_ndis_ops.get_ssid = wpa_driver_ndis_get_ssid;
+       wpa_driver_ndis_ops.set_key = wpa_driver_ndis_set_key;
+       wpa_driver_ndis_ops.init = wpa_driver_ndis_init;
+       wpa_driver_ndis_ops.deinit = wpa_driver_ndis_deinit;
+       wpa_driver_ndis_ops.deauthenticate = wpa_driver_ndis_deauthenticate;
+       wpa_driver_ndis_ops.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;
+       wpa_driver_ndis_ops.flush_pmkid = wpa_driver_ndis_flush_pmkid;
+       wpa_driver_ndis_ops.get_capa = wpa_driver_ndis_get_capa;
+       wpa_driver_ndis_ops.poll = wpa_driver_ndis_poll;
+       wpa_driver_ndis_ops.get_ifname = wpa_driver_ndis_get_ifname;
+       wpa_driver_ndis_ops.get_mac_addr = wpa_driver_ndis_get_mac_addr;
+       wpa_driver_ndis_ops.get_scan_results2 =
+               wpa_driver_ndis_get_scan_results;
+       wpa_driver_ndis_ops.get_interfaces = wpa_driver_ndis_get_interfaces;
+       wpa_driver_ndis_ops.scan2 = wpa_driver_ndis_scan;
+}
diff --git a/src/drivers/driver_ndiswrapper.c b/src/drivers/driver_ndiswrapper.c
deleted file mode 100644 (file)
index cd2f61e..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * WPA Supplicant - driver interaction with Linux ndiswrapper
- * Copyright (c) 2004-2006, Giridhar Pemmasani <giri@lmc.cs.sunysb.edu>
- * 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.
- *
- * Please note that ndiswrapper supports WPA configuration via Linux wireless
- * extensions and if the kernel includes support for this, driver_wext.c should
- * be used instead of this driver wrapper.
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-
-#include "wireless_copy.h"
-#include "common.h"
-#include "driver.h"
-#include "driver_wext.h"
-
-struct wpa_driver_ndiswrapper_data {
-       void *wext; /* private data for driver_wext */
-       void *ctx;
-       char ifname[IFNAMSIZ + 1];
-       int sock;
-};
-
-
-struct wpa_key {
-       enum wpa_alg alg;
-       const u8 *addr;
-       int key_index;
-       int set_tx;
-       const u8 *seq;
-       size_t seq_len;
-       const u8 *key;
-       size_t key_len;
-};
-
-struct wpa_assoc_info {
-       const u8 *bssid;
-       const u8 *ssid;
-       size_t ssid_len;
-       int freq;
-       const u8 *wpa_ie;
-       size_t wpa_ie_len;
-       enum wpa_cipher pairwise_suite;
-       enum wpa_cipher group_suite;
-       enum wpa_key_mgmt key_mgmt_suite;
-       int auth_alg;
-       int mode;
-};
-
-#define PRIV_RESET                     SIOCIWFIRSTPRIV+0
-#define WPA_SET_WPA                    SIOCIWFIRSTPRIV+1
-#define WPA_SET_KEY                    SIOCIWFIRSTPRIV+2
-#define WPA_ASSOCIATE                  SIOCIWFIRSTPRIV+3
-#define WPA_DISASSOCIATE               SIOCIWFIRSTPRIV+4
-#define WPA_DROP_UNENCRYPTED           SIOCIWFIRSTPRIV+5
-#define WPA_SET_COUNTERMEASURES        SIOCIWFIRSTPRIV+6
-#define WPA_DEAUTHENTICATE             SIOCIWFIRSTPRIV+7
-#define WPA_SET_AUTH_ALG               SIOCIWFIRSTPRIV+8
-#define WPA_INIT                       SIOCIWFIRSTPRIV+9
-#define WPA_DEINIT                     SIOCIWFIRSTPRIV+10
-#define WPA_GET_CAPA                   SIOCIWFIRSTPRIV+11
-
-static int wpa_ndiswrapper_set_auth_alg(void *priv, int auth_alg);
-
-static int get_socket(void)
-{
-       static const int families[] = {
-               AF_INET, AF_IPX, AF_AX25, AF_APPLETALK
-       };
-       unsigned int i;
-       int sock;
-
-       for (i = 0; i < sizeof(families) / sizeof(int); ++i) {
-               sock = socket(families[i], SOCK_DGRAM, 0);
-               if (sock >= 0)
-                       return sock;
-       }
-
-       return -1;
-}
-
-static int iw_set_ext(struct wpa_driver_ndiswrapper_data *drv, int request,
-                     struct iwreq *pwrq)
-{
-       os_strlcpy(pwrq->ifr_name, drv->ifname, IFNAMSIZ);
-       return ioctl(drv->sock, request, pwrq);
-}
-
-static int wpa_ndiswrapper_set_wpa(void *priv, int enabled)
-{
-       struct wpa_driver_ndiswrapper_data *drv = priv;
-       struct iwreq priv_req;
-       int ret = 0;
-
-       os_memset(&priv_req, 0, sizeof(priv_req));
-
-       priv_req.u.data.flags = enabled;
-       if (iw_set_ext(drv, WPA_SET_WPA, &priv_req) < 0)
-               ret = -1;
-       return ret;
-}
-
-static int wpa_ndiswrapper_set_key(const char *ifname, void *priv,
-                                  enum wpa_alg alg, const u8 *addr,
-                                  int key_idx, int set_tx,
-                                  const u8 *seq, size_t seq_len,
-                                  const u8 *key, size_t key_len)
-{
-       struct wpa_driver_ndiswrapper_data *drv = priv;
-       struct wpa_key wpa_key;
-       int ret = 0;
-       struct iwreq priv_req;
-
-       os_memset(&priv_req, 0, sizeof(priv_req));
-
-       wpa_key.alg = alg;
-       wpa_key.addr = addr;
-       wpa_key.key_index = key_idx;
-       wpa_key.set_tx = set_tx;
-       wpa_key.seq = seq;
-       wpa_key.seq_len = seq_len;
-       wpa_key.key = key;
-       wpa_key.key_len = key_len;
-
-       priv_req.u.data.pointer = (void *)&wpa_key;
-       priv_req.u.data.length = sizeof(wpa_key);
-
-       if (iw_set_ext(drv, WPA_SET_KEY, &priv_req) < 0)
-               ret = -1;
-
-       if (alg == WPA_ALG_NONE) {
-               /*
-                * ndiswrapper did not seem to be clearing keys properly in
-                * some cases with WPA_SET_KEY. For example, roaming from WPA
-                * enabled AP to plaintext one seemed to fail since the driver
-                * did not associate. Try to make sure the keys are cleared so
-                * that plaintext APs can be used in all cases.
-                */
-               wpa_driver_wext_set_key(ifname, drv->wext, alg, addr, key_idx,
-                                       set_tx, seq, seq_len, key, key_len);
-       }
-
-       return ret;
-}
-
-static int wpa_ndiswrapper_set_countermeasures(void *priv, int enabled)
-{
-       struct wpa_driver_ndiswrapper_data *drv = priv;
-       int ret = 0;
-       struct iwreq priv_req;
-
-       os_memset(&priv_req, 0, sizeof(priv_req));
-
-       priv_req.u.param.value = enabled;
-       if (iw_set_ext(drv, WPA_SET_COUNTERMEASURES, &priv_req) < 0)
-               ret = -1;
-
-       return ret;
-}
-
-static int wpa_ndiswrapper_set_drop_unencrypted(void *priv,
-                                               int enabled)
-{
-       struct wpa_driver_ndiswrapper_data *drv = priv;
-       int ret = 0;
-       struct iwreq priv_req;
-
-       os_memset(&priv_req, 0, sizeof(priv_req));
-
-       priv_req.u.param.value = enabled;
-       if (iw_set_ext(drv, WPA_DROP_UNENCRYPTED, &priv_req) < 0)
-               ret = -1;
-       return ret;
-}
-
-static int wpa_ndiswrapper_deauthenticate(void *priv, const u8 *addr,
-                                         int reason_code)
-{
-       struct wpa_driver_ndiswrapper_data *drv = priv;
-       int ret = 0;
-       struct iwreq priv_req;
-
-       os_memset(&priv_req, 0, sizeof(priv_req));
-
-       priv_req.u.param.value = reason_code;
-       os_memcpy(&priv_req.u.ap_addr.sa_data, addr, ETH_ALEN);
-       if (iw_set_ext(drv, WPA_DEAUTHENTICATE, &priv_req) < 0)
-               ret = -1;
-       return ret;
-}
-
-static int wpa_ndiswrapper_disassociate(void *priv, const u8 *addr,
-                                       int reason_code)
-{
-       struct wpa_driver_ndiswrapper_data *drv = priv;
-       int ret = 0;
-       struct iwreq priv_req;
-
-       os_memset(&priv_req, 0, sizeof(priv_req));
-
-       os_memcpy(&priv_req.u.ap_addr.sa_data, addr, ETH_ALEN);
-       if (iw_set_ext(drv, WPA_DISASSOCIATE, &priv_req) < 0)
-               ret = -1;
-       return ret;
-}
-
-static int
-wpa_ndiswrapper_associate(void *priv,
-                         struct wpa_driver_associate_params *params)
-{
-       struct wpa_driver_ndiswrapper_data *drv = priv;
-       int ret = 0;
-       struct wpa_assoc_info wpa_assoc_info;
-       struct iwreq priv_req;
-
-       if (wpa_ndiswrapper_set_drop_unencrypted(drv,
-                                                params->drop_unencrypted) < 0)
-               ret = -1;
-       if (wpa_ndiswrapper_set_auth_alg(drv, params->auth_alg) < 0)
-               ret = -1;
-
-       os_memset(&priv_req, 0, sizeof(priv_req));
-       os_memset(&wpa_assoc_info, 0, sizeof(wpa_assoc_info));
-
-       wpa_assoc_info.bssid = params->bssid;
-       wpa_assoc_info.ssid = params->ssid;
-       wpa_assoc_info.ssid_len = params->ssid_len;
-       wpa_assoc_info.freq = params->freq;
-       wpa_assoc_info.wpa_ie = params->wpa_ie;
-       wpa_assoc_info.wpa_ie_len = params->wpa_ie_len;
-       wpa_assoc_info.pairwise_suite = params->pairwise_suite;
-       wpa_assoc_info.group_suite = params->group_suite;
-       wpa_assoc_info.key_mgmt_suite = params->key_mgmt_suite;
-       wpa_assoc_info.auth_alg = params->auth_alg;
-       wpa_assoc_info.mode = params->mode;
-
-       priv_req.u.data.pointer = (void *)&wpa_assoc_info;
-       priv_req.u.data.length = sizeof(wpa_assoc_info);
-
-       if (iw_set_ext(drv, WPA_ASSOCIATE, &priv_req) < 0)
-               ret = -1;
-       return ret;
-}
-
-static int wpa_ndiswrapper_set_auth_alg(void *priv, int auth_alg)
-{
-       struct wpa_driver_ndiswrapper_data *drv = priv;
-       int ret = 0;
-       struct iwreq priv_req;
-
-       os_memset(&priv_req, 0, sizeof(priv_req));
-
-       priv_req.u.param.value = auth_alg;
-       if (iw_set_ext(drv, WPA_SET_AUTH_ALG, &priv_req) < 0)
-               ret = -1;
-       return ret;
-}
-
-static int wpa_ndiswrapper_get_bssid(void *priv, u8 *bssid)
-{
-       struct wpa_driver_ndiswrapper_data *drv = priv;
-       return wpa_driver_wext_get_bssid(drv->wext, bssid);
-}
-
-
-static int wpa_ndiswrapper_get_ssid(void *priv, u8 *ssid)
-{
-       struct wpa_driver_ndiswrapper_data *drv = priv;
-       return wpa_driver_wext_get_ssid(drv->wext, ssid);
-}
-
-
-static int wpa_ndiswrapper_scan(void *priv,
-                               struct wpa_driver_scan_params *params)
-{
-       struct wpa_driver_ndiswrapper_data *drv = priv;
-       return wpa_driver_wext_scan(drv->wext, params);
-}
-
-
-static struct wpa_scan_results * wpa_ndiswrapper_get_scan_results(void *priv)
-{
-       struct wpa_driver_ndiswrapper_data *drv = priv;
-       return wpa_driver_wext_get_scan_results(drv->wext);
-}
-
-
-static int wpa_ndiswrapper_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
-       struct wpa_driver_ndiswrapper_data *drv = priv;
-       int ret = 0;
-       struct iwreq priv_req;
-
-       os_memset(&priv_req, 0, sizeof(priv_req));
-
-       priv_req.u.data.pointer = (void *) capa;
-       priv_req.u.data.length = sizeof(*capa);
-       if (iw_set_ext(drv, WPA_GET_CAPA, &priv_req) < 0)
-               ret = -1;
-       return ret;
-       
-}
-
-
-static int wpa_ndiswrapper_set_operstate(void *priv, int state)
-{
-       struct wpa_driver_ndiswrapper_data *drv = priv;
-       return wpa_driver_wext_set_operstate(drv->wext, state);
-}
-
-
-static void * wpa_ndiswrapper_init(void *ctx, const char *ifname)
-{
-       struct wpa_driver_ndiswrapper_data *drv;
-
-       drv = os_zalloc(sizeof(*drv));
-       if (drv == NULL)
-               return NULL;
-       drv->wext = wpa_driver_wext_init(ctx, ifname);
-       if (drv->wext == NULL) {
-               os_free(drv);
-               return NULL;
-       }
-
-       drv->ctx = ctx;
-       os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-       drv->sock = get_socket();
-       if (drv->sock < 0) {
-               wpa_driver_wext_deinit(drv->wext);
-               os_free(drv);
-               return NULL;
-       }
-
-       wpa_ndiswrapper_set_wpa(drv, 1);
-
-       return drv;
-}
-
-
-static void wpa_ndiswrapper_deinit(void *priv)
-{
-       struct wpa_driver_ndiswrapper_data *drv = priv;
-       wpa_ndiswrapper_set_wpa(drv, 0);
-       wpa_driver_wext_deinit(drv->wext);
-       close(drv->sock);
-       os_free(drv);
-}
-
-
-const struct wpa_driver_ops wpa_driver_ndiswrapper_ops = {
-       .name = "ndiswrapper",
-       .desc = "Linux ndiswrapper (deprecated; use wext)",
-       .set_key = wpa_ndiswrapper_set_key,
-       .set_countermeasures = wpa_ndiswrapper_set_countermeasures,
-       .deauthenticate = wpa_ndiswrapper_deauthenticate,
-       .disassociate = wpa_ndiswrapper_disassociate,
-       .associate = wpa_ndiswrapper_associate,
-
-       .get_bssid = wpa_ndiswrapper_get_bssid,
-       .get_ssid = wpa_ndiswrapper_get_ssid,
-       .scan2 = wpa_ndiswrapper_scan,
-       .get_scan_results2 = wpa_ndiswrapper_get_scan_results,
-       .init = wpa_ndiswrapper_init,
-       .deinit = wpa_ndiswrapper_deinit,
-       .get_capa = wpa_ndiswrapper_get_capa,
-       .set_operstate = wpa_ndiswrapper_set_operstate,
-};
index 364158c..bc8b1fc 100644 (file)
 
 #include "includes.h"
 #include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 #include <net/if.h>
 #include <netlink/genl/genl.h>
 #include <netlink/genl/family.h>
 #include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
 #include <netpacket/packet.h>
 #include <linux/filter.h>
+#include <linux/errqueue.h>
 #include "nl80211_copy.h"
 
 #include "common.h"
 #include "eloop.h"
+#include "utils/list.h"
 #include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "l2_packet/l2_packet.h"
 #include "netlink.h"
 #include "linux_ioctl.h"
 #include "radiotap.h"
 #include "radiotap_iter.h"
+#include "rfkill.h"
 #include "driver.h"
 
+#ifndef SO_WIFI_STATUS
+# if defined(__sparc__)
+#  define SO_WIFI_STATUS       0x0025
+# elif defined(__parisc__)
+#  define SO_WIFI_STATUS       0x4022
+# else
+#  define SO_WIFI_STATUS       41
+# endif
+
+# define SCM_WIFI_STATUS       SO_WIFI_STATUS
+#endif
+
+#ifndef SO_EE_ORIGIN_TXSTATUS
+#define SO_EE_ORIGIN_TXSTATUS  4
+#endif
+
+#ifndef PACKET_TX_TIMESTAMP
+#define PACKET_TX_TIMESTAMP    16
+#endif
+
+#ifdef ANDROID
+#include "android_drv.h"
+#endif /* ANDROID */
 #ifdef CONFIG_LIBNL20
 /* libnl 2.0 compatibility code */
 #define nl_handle nl_sock
-#define nl_handle_alloc_cb nl_socket_alloc_cb
-#define nl_handle_destroy nl_socket_free
+#define nl80211_handle_alloc nl_socket_alloc_cb
+#define nl80211_handle_destroy nl_socket_free
+#else
+/*
+ * libnl 1.1 has a bug, it tries to allocate socket numbers densely
+ * but when you free a socket again it will mess up its bitmap and
+ * and use the wrong number the next time it needs a socket ID.
+ * Therefore, we wrap the handle alloc/destroy and add our own pid
+ * accounting.
+ */
+static uint32_t port_bitmap[32] = { 0 };
+
+static struct nl_handle *nl80211_handle_alloc(void *cb)
+{
+       struct nl_handle *handle;
+       uint32_t pid = getpid() & 0x3FFFFF;
+       int i;
+
+       handle = nl_handle_alloc_cb(cb);
+
+       for (i = 0; i < 1024; i++) {
+               if (port_bitmap[i / 32] & (1 << (i % 32)))
+                       continue;
+               port_bitmap[i / 32] |= 1 << (i % 32);
+               pid += i << 22;
+               break;
+       }
+
+       nl_socket_set_local_port(handle, pid);
+
+       return handle;
+}
+
+static void nl80211_handle_destroy(struct nl_handle *handle)
+{
+       uint32_t port = nl_socket_get_local_port(handle);
+
+       port >>= 22;
+       port_bitmap[port / 32] &= ~(1 << (port % 32));
+
+       nl_handle_destroy(handle);
+}
 #endif /* CONFIG_LIBNL20 */
 
 
+static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg)
+{
+       struct nl_handle *handle;
+
+       handle = nl80211_handle_alloc(cb);
+       if (handle == NULL) {
+               wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
+                          "callbacks (%s)", dbg);
+               return NULL;
+       }
+
+       if (genl_connect(handle)) {
+               wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
+                          "netlink (%s)", dbg);
+               nl80211_handle_destroy(handle);
+               return NULL;
+       }
+
+       return handle;
+}
+
+
+static void nl_destroy_handles(struct nl_handle **handle)
+{
+       if (*handle == NULL)
+               return;
+       nl80211_handle_destroy(*handle);
+       *handle = NULL;
+}
+
+
 #ifndef IFF_LOWER_UP
 #define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
 #endif
 #define IF_OPER_UP 6
 #endif
 
+struct nl80211_global {
+       struct dl_list interfaces;
+       int if_add_ifindex;
+       struct netlink_data *netlink;
+       struct nl_cb *nl_cb;
+       struct nl_handle *nl;
+       int nl80211_id;
+       int ioctl_sock; /* socket for ioctl() use */
+
+       struct nl_handle *nl_event;
+};
+
+struct nl80211_wiphy_data {
+       struct dl_list list;
+       struct dl_list bsss;
+       struct dl_list drvs;
+
+       struct nl_handle *nl_beacons;
+       struct nl_cb *nl_cb;
+
+       int wiphy_idx;
+};
+
+static void nl80211_global_deinit(void *priv);
+static void wpa_driver_nl80211_deinit(void *priv);
+
 struct i802_bss {
        struct wpa_driver_nl80211_data *drv;
        struct i802_bss *next;
        int ifindex;
        char ifname[IFNAMSIZ + 1];
+       char brname[IFNAMSIZ];
        unsigned int beacon_set:1;
+       unsigned int added_if_into_bridge:1;
+       unsigned int added_bridge:1;
+
+       u8 addr[ETH_ALEN];
+
+       int freq;
+
+       struct nl_handle *nl_preq, *nl_mgmt;
+       struct nl_cb *nl_cb;
+
+       struct nl80211_wiphy_data *wiphy_data;
+       struct dl_list wiphy_list;
 };
 
 struct wpa_driver_nl80211_data {
+       struct nl80211_global *global;
+       struct dl_list list;
+       struct dl_list wiphy_list;
+       char phyname[32];
        void *ctx;
-       struct netlink_data *netlink;
-       int ioctl_sock; /* socket for ioctl() use */
-       char brname[IFNAMSIZ];
        int ifindex;
        int if_removed;
+       int if_disabled;
+       int ignore_if_down_event;
+       struct rfkill_data *rfkill;
        struct wpa_driver_capa capa;
        int has_capability;
 
@@ -79,39 +225,43 @@ struct wpa_driver_nl80211_data {
 
        int scan_complete_events;
 
-       struct nl_handle *nl_handle;
-       struct nl_handle *nl_handle_event;
-       struct nl_cache *nl_cache;
-       struct nl_cache *nl_cache_event;
        struct nl_cb *nl_cb;
-       struct genl_family *nl80211;
 
        u8 auth_bssid[ETH_ALEN];
        u8 bssid[ETH_ALEN];
        int associated;
        u8 ssid[32];
        size_t ssid_len;
-       int nlmode;
-       int ap_scan_as_station;
+       enum nl80211_iftype nlmode;
+       enum nl80211_iftype ap_scan_as_station;
        unsigned int assoc_freq;
 
        int monitor_sock;
        int monitor_ifidx;
-       int probe_req_report;
-       int disable_11b_rates;
+       int monitor_refcount;
 
+       unsigned int disabled_11b_rates:1;
        unsigned int pending_remain_on_chan:1;
-       unsigned int added_bridge:1;
-       unsigned int added_if_into_bridge:1;
+       unsigned int in_interface_list:1;
+       unsigned int device_ap_sme:1;
+       unsigned int poll_command_supported:1;
+       unsigned int data_tx_status:1;
+       unsigned int scan_for_auth:1;
+       unsigned int retry_auth:1;
+       unsigned int use_monitor:1;
 
        u64 remain_on_chan_cookie;
        u64 send_action_cookie;
 
+       unsigned int last_mgmt_freq;
+
        struct wpa_driver_scan_filter *filter_ssids;
        size_t num_filter_ssids;
 
        struct i802_bss first_bss;
 
+       int eapol_tx_sock;
+
 #ifdef HOSTAPD
        int eapol_sock; /* socket for EAPOL frames */
 
@@ -122,12 +272,27 @@ struct wpa_driver_nl80211_data {
        int last_freq;
        int last_freq_ht;
 #endif /* HOSTAPD */
+
+       /* From failed authentication command */
+       int auth_freq;
+       u8 auth_bssid_[ETH_ALEN];
+       u8 auth_ssid[32];
+       size_t auth_ssid_len;
+       int auth_alg;
+       u8 *auth_ie;
+       size_t auth_ie_len;
+       u8 auth_wep_key[4][16];
+       size_t auth_wep_key_len[4];
+       int auth_wep_tx_keyidx;
+       int auth_local_state_change;
+       int auth_p2p;
 };
 
 
 static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
                                            void *timeout_ctx);
-static int wpa_driver_nl80211_set_mode(void *priv, int mode);
+static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
+                                      enum nl80211_iftype nlmode);
 static int
 wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
 static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
@@ -135,6 +300,16 @@ static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
                                   int local_state_change);
 static void nl80211_remove_monitor_interface(
        struct wpa_driver_nl80211_data *drv);
+static int nl80211_send_frame_cmd(struct i802_bss *bss,
+                                 unsigned int freq, unsigned int wait,
+                                 const u8 *buf, size_t buf_len, u64 *cookie,
+                                 int no_cck, int no_ack, int offchanok);
+static int wpa_driver_nl80211_probe_req_report(void *priv, int report);
+#ifdef ANDROID
+static int android_pno_start(struct i802_bss *bss,
+                            struct wpa_driver_scan_params *params);
+static int android_pno_stop(struct i802_bss *bss);
+#endif /* ANDROID */
 
 #ifdef HOSTAPD
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
@@ -144,18 +319,59 @@ static int wpa_driver_nl80211_if_remove(void *priv,
                                        enum wpa_driver_if_type type,
                                        const char *ifname);
 #else /* HOSTAPD */
-static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+static inline void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+}
+
+static inline void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+}
+
+static inline int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
 {
        return 0;
 }
 #endif /* HOSTAPD */
 
 static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
-static void wpa_driver_nl80211_probe_req_report_timeout(void *eloop_ctx,
-                                                       void *timeout_ctx);
 static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
                                     int ifindex, int disabled);
 
+static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv);
+static int wpa_driver_nl80211_authenticate_retry(
+       struct wpa_driver_nl80211_data *drv);
+
+
+static int is_ap_interface(enum nl80211_iftype nlmode)
+{
+       return (nlmode == NL80211_IFTYPE_AP ||
+               nlmode == NL80211_IFTYPE_P2P_GO);
+}
+
+
+static int is_sta_interface(enum nl80211_iftype nlmode)
+{
+       return (nlmode == NL80211_IFTYPE_STATION ||
+               nlmode == NL80211_IFTYPE_P2P_CLIENT);
+}
+
+
+static int is_p2p_interface(enum nl80211_iftype nlmode)
+{
+       return (nlmode == NL80211_IFTYPE_P2P_CLIENT ||
+               nlmode == NL80211_IFTYPE_P2P_GO);
+}
+
+
+struct nl80211_bss_info_arg {
+       struct wpa_driver_nl80211_data *drv;
+       struct wpa_scan_results *res;
+       unsigned int assoc_freq;
+       u8 assoc_bssid[ETH_ALEN];
+};
+
+static int bss_info_handler(struct nl_msg *msg, void *arg);
+
 
 /* nl80211 code */
 static int ack_handler(struct nl_msg *msg, void *arg)
@@ -187,7 +403,7 @@ static int no_seq_check(struct nl_msg *msg, void *arg)
 }
 
 
-static int send_and_recv(struct wpa_driver_nl80211_data *drv,
+static int send_and_recv(struct nl80211_global *global,
                         struct nl_handle *nl_handle, struct nl_msg *msg,
                         int (*valid_handler)(struct nl_msg *, void *),
                         void *valid_data)
@@ -195,7 +411,7 @@ static int send_and_recv(struct wpa_driver_nl80211_data *drv,
        struct nl_cb *cb;
        int err = -ENOMEM;
 
-       cb = nl_cb_clone(drv->nl_cb);
+       cb = nl_cb_clone(global->nl_cb);
        if (!cb)
                goto out;
 
@@ -222,13 +438,23 @@ static int send_and_recv(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static int send_and_recv_msgs_global(struct nl80211_global *global,
+                                    struct nl_msg *msg,
+                                    int (*valid_handler)(struct nl_msg *, void *),
+                                    void *valid_data)
+{
+       return send_and_recv(global, global->nl, msg, valid_handler,
+                            valid_data);
+}
+
+
 static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
                              struct nl_msg *msg,
                              int (*valid_handler)(struct nl_msg *, void *),
                              void *valid_data)
 {
-       return send_and_recv(drv, drv->nl_handle, msg, valid_handler,
-                            valid_data);
+       return send_and_recv(drv->global, drv->global->nl, msg,
+                            valid_handler, valid_data);
 }
 
 
@@ -269,7 +495,7 @@ static int family_handler(struct nl_msg *msg, void *arg)
 }
 
 
-static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv,
+static int nl_get_multicast_id(struct nl80211_global *global,
                               const char *family, const char *group)
 {
        struct nl_msg *msg;
@@ -279,11 +505,11 @@ static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv,
        msg = nlmsg_alloc();
        if (!msg)
                return -ENOMEM;
-       genlmsg_put(msg, 0, 0, genl_ctrl_resolve(drv->nl_handle, "nlctrl"),
+       genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
                    0, 0, CTRL_CMD_GETFAMILY, 0);
        NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
 
-       ret = send_and_recv_msgs(drv, msg, family_handler, &res);
+       ret = send_and_recv_msgs_global(global, msg, family_handler, &res);
        msg = NULL;
        if (ret == 0)
                ret = res.id;
@@ -294,6 +520,235 @@ nla_put_failure:
 }
 
 
+static void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
+                         struct nl_msg *msg, int flags, uint8_t cmd)
+{
+       return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
+                          0, flags, cmd, 0);
+}
+
+
+struct wiphy_idx_data {
+       int wiphy_idx;
+};
+
+
+static int netdev_info_handler(struct nl_msg *msg, void *arg)
+{
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct wiphy_idx_data *info = arg;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       if (tb[NL80211_ATTR_WIPHY])
+               info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+
+       return NL_SKIP;
+}
+
+
+static int nl80211_get_wiphy_index(struct i802_bss *bss)
+{
+       struct nl_msg *msg;
+       struct wiphy_idx_data data = {
+               .wiphy_idx = -1,
+       };
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -1;
+
+       nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+       if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
+               return data.wiphy_idx;
+       msg = NULL;
+nla_put_failure:
+       nlmsg_free(msg);
+       return -1;
+}
+
+
+static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
+                                   struct nl80211_wiphy_data *w)
+{
+       struct nl_msg *msg;
+       int ret = -1;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -1;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx);
+
+       ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL);
+       msg = NULL;
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
+                          "failed: ret=%d (%s)",
+                          ret, strerror(-ret));
+               goto nla_put_failure;
+       }
+       ret = 0;
+nla_put_failure:
+       nlmsg_free(msg);
+       return ret;
+}
+
+
+static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
+{
+       struct nl80211_wiphy_data *w = eloop_ctx;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Beacon event message available");
+
+       nl_recvmsgs(handle, w->nl_cb);
+}
+
+
+static int process_beacon_event(struct nl_msg *msg, void *arg)
+{
+       struct nl80211_wiphy_data *w = arg;
+       struct wpa_driver_nl80211_data *drv;
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       union wpa_event_data event;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       if (gnlh->cmd != NL80211_CMD_FRAME) {
+               wpa_printf(MSG_DEBUG, "nl80211: Unexpected beacon event? (%d)",
+                          gnlh->cmd);
+               return NL_SKIP;
+       }
+
+       if (!tb[NL80211_ATTR_FRAME])
+               return NL_SKIP;
+
+       dl_list_for_each(drv, &w->drvs, struct wpa_driver_nl80211_data,
+                        wiphy_list) {
+               os_memset(&event, 0, sizeof(event));
+               event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]);
+               event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]);
+               wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+       }
+
+       return NL_SKIP;
+}
+
+
+static struct nl80211_wiphy_data *
+nl80211_get_wiphy_data_ap(struct i802_bss *bss)
+{
+       static DEFINE_DL_LIST(nl80211_wiphys);
+       struct nl80211_wiphy_data *w;
+       int wiphy_idx, found = 0;
+       struct i802_bss *tmp_bss;
+
+       if (bss->wiphy_data != NULL)
+               return bss->wiphy_data;
+
+       wiphy_idx = nl80211_get_wiphy_index(bss);
+
+       dl_list_for_each(w, &nl80211_wiphys, struct nl80211_wiphy_data, list) {
+               if (w->wiphy_idx == wiphy_idx)
+                       goto add;
+       }
+
+       /* alloc new one */
+       w = os_zalloc(sizeof(*w));
+       if (w == NULL)
+               return NULL;
+       w->wiphy_idx = wiphy_idx;
+       dl_list_init(&w->bsss);
+       dl_list_init(&w->drvs);
+
+       w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+       if (!w->nl_cb) {
+               os_free(w);
+               return NULL;
+       }
+       nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
+       nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_beacon_event,
+                 w);
+
+       w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
+                                        "wiphy beacons");
+       if (w->nl_beacons == NULL) {
+               os_free(w);
+               return NULL;
+       }
+
+       if (nl80211_register_beacons(bss->drv, w)) {
+               nl_destroy_handles(&w->nl_beacons);
+               os_free(w);
+               return NULL;
+       }
+
+       eloop_register_read_sock(nl_socket_get_fd(w->nl_beacons),
+                                nl80211_recv_beacons, w, w->nl_beacons);
+
+       dl_list_add(&nl80211_wiphys, &w->list);
+
+add:
+       /* drv entry for this bss already there? */
+       dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
+               if (tmp_bss->drv == bss->drv) {
+                       found = 1;
+                       break;
+               }
+       }
+       /* if not add it */
+       if (!found)
+               dl_list_add(&w->drvs, &bss->drv->wiphy_list);
+
+       dl_list_add(&w->bsss, &bss->wiphy_list);
+       bss->wiphy_data = w;
+       return w;
+}
+
+
+static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
+{
+       struct nl80211_wiphy_data *w = bss->wiphy_data;
+       struct i802_bss *tmp_bss;
+       int found = 0;
+
+       if (w == NULL)
+               return;
+       bss->wiphy_data = NULL;
+       dl_list_del(&bss->wiphy_list);
+
+       /* still any for this drv present? */
+       dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
+               if (tmp_bss->drv == bss->drv) {
+                       found = 1;
+                       break;
+               }
+       }
+       /* if not remove it */
+       if (!found)
+               dl_list_del(&bss->drv->wiphy_list);
+
+       if (!dl_list_empty(&w->bsss))
+               return;
+
+       eloop_unregister_read_sock(nl_socket_get_fd(w->nl_beacons));
+
+       nl_cb_put(w->nl_cb);
+       nl_destroy_handles(&w->nl_beacons);
+       dl_list_del(&w->list);
+       os_free(w);
+}
+
+
 static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
 {
        struct i802_bss *bss = priv;
@@ -387,17 +842,33 @@ static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static struct wpa_driver_nl80211_data *
+nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len)
+{
+       struct wpa_driver_nl80211_data *drv;
+       dl_list_for_each(drv, &global->interfaces,
+                        struct wpa_driver_nl80211_data, list) {
+               if (wpa_driver_nl80211_own_ifindex(drv, idx, buf, len) ||
+                   have_ifidx(drv, idx))
+                       return drv;
+       }
+       return NULL;
+}
+
+
 static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                                                 struct ifinfomsg *ifi,
                                                 u8 *buf, size_t len)
 {
-       struct wpa_driver_nl80211_data *drv = ctx;
+       struct nl80211_global *global = ctx;
+       struct wpa_driver_nl80211_data *drv;
        int attrlen, rta_len;
        struct rtattr *attr;
        u32 brid = 0;
+       char namebuf[IFNAMSIZ];
 
-       if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, buf, len) &&
-           !have_ifidx(drv, ifi->ifi_index)) {
+       drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+       if (!drv) {
                wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign "
                           "ifindex %d", ifi->ifi_index);
                return;
@@ -410,6 +881,42 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                   (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
                   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
                   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+
+       if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
+               if (if_indextoname(ifi->ifi_index, namebuf) &&
+                   linux_iface_up(drv->global->ioctl_sock,
+                                  drv->first_bss.ifname) > 0) {
+                       wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
+                                  "event since interface %s is up", namebuf);
+                       return;
+               }
+               wpa_printf(MSG_DEBUG, "nl80211: Interface down");
+               if (drv->ignore_if_down_event) {
+                       wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
+                                  "event generated by mode change");
+                       drv->ignore_if_down_event = 0;
+               } else {
+                       drv->if_disabled = 1;
+                       wpa_supplicant_event(drv->ctx,
+                                            EVENT_INTERFACE_DISABLED, NULL);
+               }
+       }
+
+       if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
+               if (if_indextoname(ifi->ifi_index, namebuf) &&
+                   linux_iface_up(drv->global->ioctl_sock,
+                                  drv->first_bss.ifname) == 0) {
+                       wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
+                                  "event since interface %s is down",
+                                  namebuf);
+               } else {
+                       wpa_printf(MSG_DEBUG, "nl80211: Interface up");
+                       drv->if_disabled = 0;
+                       wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+                                            NULL);
+               }
+       }
+
        /*
         * Some drivers send the association event before the operup event--in
         * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
@@ -419,7 +926,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
        if (drv->operstate == 1 &&
            (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
            !(ifi->ifi_flags & IFF_RUNNING))
-               netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+               netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
                                       -1, IF_OPER_UP);
 
        attrlen = len;
@@ -436,16 +943,13 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                attr = RTA_NEXT(attr, attrlen);
        }
 
-#ifdef HOSTAPD
        if (ifi->ifi_family == AF_BRIDGE && brid) {
                /* device has been added to bridge */
-               char namebuf[IFNAMSIZ];
                if_indextoname(brid, namebuf);
                wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
                           brid, namebuf);
                add_ifidx(drv, brid);
        }
-#endif /* HOSTAPD */
 }
 
 
@@ -453,11 +957,19 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
                                                 struct ifinfomsg *ifi,
                                                 u8 *buf, size_t len)
 {
-       struct wpa_driver_nl80211_data *drv = ctx;
+       struct nl80211_global *global = ctx;
+       struct wpa_driver_nl80211_data *drv;
        int attrlen, rta_len;
        struct rtattr *attr;
        u32 brid = 0;
 
+       drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+       if (!drv) {
+               wpa_printf(MSG_DEBUG, "nl80211: Ignore dellink event for "
+                          "foreign ifindex %d", ifi->ifi_index);
+               return;
+       }
+
        attrlen = len;
        attr = (struct rtattr *) buf;
 
@@ -473,7 +985,6 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
                attr = RTA_NEXT(attr, attrlen);
        }
 
-#ifdef HOSTAPD
        if (ifi->ifi_family == AF_BRIDGE && brid) {
                /* device has been removed from bridge */
                char namebuf[IFNAMSIZ];
@@ -482,7 +993,6 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
                           "%s", brid, namebuf);
                del_ifidx(drv, brid);
        }
-#endif /* HOSTAPD */
 }
 
 
@@ -513,6 +1023,37 @@ static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
+{
+       struct nl_msg *msg;
+       int ret;
+       struct nl80211_bss_info_arg arg;
+
+       os_memset(&arg, 0, sizeof(arg));
+       msg = nlmsg_alloc();
+       if (!msg)
+               goto nla_put_failure;
+
+       nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+       arg.drv = drv;
+       ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
+       msg = NULL;
+       if (ret == 0) {
+               wpa_printf(MSG_DEBUG, "nl80211: Operating frequency for the "
+                          "associated BSS from scan results: %u MHz",
+                          arg.assoc_freq);
+               return arg.assoc_freq ? arg.assoc_freq : drv->assoc_freq;
+       }
+       wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
+                  "(%s)", ret, strerror(-ret));
+nla_put_failure:
+       nlmsg_free(msg);
+       return drv->assoc_freq;
+}
+
+
 static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
                            const u8 *frame, size_t len)
 {
@@ -530,6 +1071,7 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
        status = le_to_host16(mgmt->u.assoc_resp.status_code);
        if (status != WLAN_STATUS_SUCCESS) {
                os_memset(&event, 0, sizeof(event));
+               event.assoc_reject.bssid = mgmt->bssid;
                if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
                        event.assoc_reject.resp_ies =
                                (u8 *) mgmt->u.assoc_resp.variable;
@@ -578,6 +1120,8 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
        os_memset(&event, 0, sizeof(event));
        if (cmd == NL80211_CMD_CONNECT &&
            nla_get_u16(status) != WLAN_STATUS_SUCCESS) {
+               if (addr)
+                       event.assoc_reject.bssid = nla_data(addr);
                if (resp_ie) {
                        event.assoc_reject.resp_ies = nla_data(resp_ie);
                        event.assoc_reject.resp_ies_len = nla_len(resp_ie);
@@ -600,10 +1144,35 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
                event.assoc_info.resp_ies_len = nla_len(resp_ie);
        }
 
+       event.assoc_info.freq = nl80211_get_assoc_freq(drv);
+
        wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
 }
 
 
+static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
+                                 struct nlattr *reason, struct nlattr *addr)
+{
+       union wpa_event_data data;
+
+       if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+               /*
+                * Avoid reporting two disassociation events that could
+                * confuse the core code.
+                */
+               wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
+                          "event when using userspace SME");
+               return;
+       }
+
+       drv->associated = 0;
+       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);
+}
+
+
 static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
                               enum nl80211_commands cmd, struct nlattr *addr)
 {
@@ -629,8 +1198,8 @@ static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
 }
 
 
-static void mlme_event_action(struct wpa_driver_nl80211_data *drv,
-                             struct nlattr *freq, const u8 *frame, size_t len)
+static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
+                           struct nlattr *freq, const u8 *frame, size_t len)
 {
        const struct ieee80211_mgmt *mgmt;
        union wpa_event_data event;
@@ -646,37 +1215,49 @@ static void mlme_event_action(struct wpa_driver_nl80211_data *drv,
        stype = WLAN_FC_GET_STYPE(fc);
 
        os_memset(&event, 0, sizeof(event));
-       event.rx_action.da = mgmt->da;
-       event.rx_action.sa = mgmt->sa;
-       event.rx_action.bssid = mgmt->bssid;
-       event.rx_action.category = mgmt->u.action.category;
-       event.rx_action.data = &mgmt->u.action.category + 1;
-       event.rx_action.len = frame + len - event.rx_action.data;
-       if (freq)
+       if (freq) {
                event.rx_action.freq = nla_get_u32(freq);
-       wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event);
+               drv->last_mgmt_freq = event.rx_action.freq;
+       }
+       if (stype == WLAN_FC_STYPE_ACTION) {
+               event.rx_action.da = mgmt->da;
+               event.rx_action.sa = mgmt->sa;
+               event.rx_action.bssid = mgmt->bssid;
+               event.rx_action.category = mgmt->u.action.category;
+               event.rx_action.data = &mgmt->u.action.category + 1;
+               event.rx_action.len = frame + len - event.rx_action.data;
+               wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event);
+       } else {
+               event.rx_mgmt.frame = frame;
+               event.rx_mgmt.frame_len = len;
+               wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+       }
 }
 
 
-static void mlme_event_action_tx_status(struct wpa_driver_nl80211_data *drv,
-                                       struct nlattr *cookie, const u8 *frame,
-                                       size_t len, struct nlattr *ack)
+static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
+                                     struct nlattr *cookie, const u8 *frame,
+                                     size_t len, struct nlattr *ack)
 {
        union wpa_event_data event;
        const struct ieee80211_hdr *hdr;
        u16 fc;
-       u64 cookie_val;
 
-       if (!cookie)
-               return;
+       if (!is_ap_interface(drv->nlmode)) {
+               u64 cookie_val;
 
-       cookie_val = nla_get_u64(cookie);
-       wpa_printf(MSG_DEBUG, "nl80211: Action TX status: cookie=0%llx%s",
-                  (long long unsigned int) cookie_val,
-                  cookie_val == drv->send_action_cookie ?
-                  " (match)" : " (unknown)");
-       if (cookie_val != drv->send_action_cookie)
-               return;
+               if (!cookie)
+                       return;
+
+               cookie_val = nla_get_u64(cookie);
+               wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
+                          " cookie=0%llx%s (ack=%d)",
+                          (long long unsigned int) cookie_val,
+                          cookie_val == drv->send_action_cookie ?
+                          " (match)" : " (unknown)", ack != NULL);
+               if (cookie_val != drv->send_action_cookie)
+                       return;
+       }
 
        hdr = (const struct ieee80211_hdr *) frame;
        fc = le_to_host16(hdr->frame_control);
@@ -730,9 +1311,51 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
        if (type == EVENT_DISASSOC) {
                event.disassoc_info.addr = bssid;
                event.disassoc_info.reason_code = reason_code;
+               if (frame + len > mgmt->u.disassoc.variable) {
+                       event.disassoc_info.ie = mgmt->u.disassoc.variable;
+                       event.disassoc_info.ie_len = frame + len -
+                               mgmt->u.disassoc.variable;
+               }
        } else {
                event.deauth_info.addr = bssid;
                event.deauth_info.reason_code = reason_code;
+               if (frame + len > mgmt->u.deauth.variable) {
+                       event.deauth_info.ie = mgmt->u.deauth.variable;
+                       event.deauth_info.ie_len = frame + len -
+                               mgmt->u.deauth.variable;
+               }
+       }
+
+       wpa_supplicant_event(drv->ctx, type, &event);
+}
+
+
+static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
+                                        enum wpa_event_type type,
+                                        const u8 *frame, size_t len)
+{
+       const struct ieee80211_mgmt *mgmt;
+       union wpa_event_data event;
+       u16 reason_code = 0;
+
+       if (len < 24)
+               return;
+
+       mgmt = (const struct ieee80211_mgmt *) frame;
+
+       os_memset(&event, 0, sizeof(event));
+       /* Note: Same offset for Reason Code in both frame subtypes */
+       if (len >= 24 + sizeof(mgmt->u.deauth))
+               reason_code = le_to_host16(mgmt->u.deauth.reason_code);
+
+       if (type == EVENT_UNPROT_DISASSOC) {
+               event.unprot_disassoc.sa = mgmt->sa;
+               event.unprot_disassoc.da = mgmt->da;
+               event.unprot_disassoc.reason_code = reason_code;
+       } else {
+               event.unprot_deauth.sa = mgmt->sa;
+               event.unprot_deauth.da = mgmt->da;
+               event.unprot_deauth.reason_code = reason_code;
        }
 
        wpa_supplicant_event(drv->ctx, type, &event);
@@ -775,12 +1398,20 @@ static void mlme_event(struct wpa_driver_nl80211_data *drv,
                mlme_event_deauth_disassoc(drv, EVENT_DISASSOC,
                                           nla_data(frame), nla_len(frame));
                break;
-       case NL80211_CMD_ACTION:
-               mlme_event_action(drv, freq, nla_data(frame), nla_len(frame));
+       case NL80211_CMD_FRAME:
+               mlme_event_mgmt(drv, freq, nla_data(frame), nla_len(frame));
+               break;
+       case NL80211_CMD_FRAME_TX_STATUS:
+               mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
+                                         nla_len(frame), ack);
                break;
-       case NL80211_CMD_ACTION_TX_STATUS:
-               mlme_event_action_tx_status(drv, cookie, nla_data(frame),
-                                           nla_len(frame), ack);
+       case NL80211_CMD_UNPROT_DEAUTHENTICATE:
+               mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH,
+                                            nla_data(frame), nla_len(frame));
+               break;
+       case NL80211_CMD_UNPROT_DISASSOCIATE:
+               mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC,
+                                            nla_data(frame), nla_len(frame));
                break;
        default:
                break;
@@ -877,7 +1508,8 @@ static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv,
        if (cookie != drv->remain_on_chan_cookie)
                return; /* not for us */
 
-       drv->pending_remain_on_chan = !cancel_event;
+       if (cancel_event)
+               drv->pending_remain_on_chan = 0;
 
        os_memset(&data, 0, sizeof(data));
        data.remain_on_channel.freq = freq;
@@ -899,6 +1531,14 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
        int freqs[MAX_REPORT_FREQS];
        int num_freqs = 0;
 
+       if (drv->scan_for_auth) {
+               drv->scan_for_auth = 0;
+               wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing "
+                          "cfg80211 BSS entry");
+               wpa_driver_nl80211_authenticate_retry(drv);
+               return;
+       }
+
        os_memset(&event, 0, sizeof(event));
        info = &event.scan_info;
        info->aborted = aborted;
@@ -929,6 +1569,219 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
 }
 
 
+static int get_link_signal(struct nl_msg *msg, void *arg)
+{
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
+       static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
+               [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
+       };
+       struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
+       static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
+               [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
+               [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
+               [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
+               [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
+       };
+       struct wpa_signal_info *sig_change = arg;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+       if (!tb[NL80211_ATTR_STA_INFO] ||
+           nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
+                            tb[NL80211_ATTR_STA_INFO], policy))
+               return NL_SKIP;
+       if (!sinfo[NL80211_STA_INFO_SIGNAL])
+               return NL_SKIP;
+
+       sig_change->current_signal =
+               (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
+
+       if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
+               if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
+                                    sinfo[NL80211_STA_INFO_TX_BITRATE],
+                                    rate_policy)) {
+                       sig_change->current_txrate = 0;
+               } else {
+                       if (rinfo[NL80211_RATE_INFO_BITRATE]) {
+                               sig_change->current_txrate =
+                                       nla_get_u16(rinfo[
+                                            NL80211_RATE_INFO_BITRATE]) * 100;
+                       }
+               }
+       }
+
+       return NL_SKIP;
+}
+
+
+static int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
+                                  struct wpa_signal_info *sig)
+{
+       struct nl_msg *msg;
+
+       sig->current_signal = -9999;
+       sig->current_txrate = 0;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
+
+       return send_and_recv_msgs(drv, msg, get_link_signal, sig);
+ nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+
+
+static int get_link_noise(struct nl_msg *msg, void *arg)
+{
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
+       static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
+               [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
+               [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
+       };
+       struct wpa_signal_info *sig_change = arg;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       if (!tb[NL80211_ATTR_SURVEY_INFO]) {
+               wpa_printf(MSG_DEBUG, "nl80211: survey data missing!");
+               return NL_SKIP;
+       }
+
+       if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
+                            tb[NL80211_ATTR_SURVEY_INFO],
+                            survey_policy)) {
+               wpa_printf(MSG_DEBUG, "nl80211: failed to parse nested "
+                          "attributes!");
+               return NL_SKIP;
+       }
+
+       if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
+               return NL_SKIP;
+
+       if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
+           sig_change->frequency)
+               return NL_SKIP;
+
+       if (!sinfo[NL80211_SURVEY_INFO_NOISE])
+               return NL_SKIP;
+
+       sig_change->current_noise =
+               (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+
+       return NL_SKIP;
+}
+
+
+static int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
+                                 struct wpa_signal_info *sig_change)
+{
+       struct nl_msg *msg;
+
+       sig_change->current_noise = 9999;
+       sig_change->frequency = drv->assoc_freq;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+       return send_and_recv_msgs(drv, msg, get_link_noise, sig_change);
+ nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+
+
+static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
+{
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
+       static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
+               [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
+               [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
+       };
+       struct wpa_scan_results *scan_results = arg;
+       struct wpa_scan_res *scan_res;
+       size_t i;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       if (!tb[NL80211_ATTR_SURVEY_INFO]) {
+               wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
+               return NL_SKIP;
+       }
+
+       if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
+                            tb[NL80211_ATTR_SURVEY_INFO],
+                            survey_policy)) {
+               wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
+                          "attributes");
+               return NL_SKIP;
+       }
+
+       if (!sinfo[NL80211_SURVEY_INFO_NOISE])
+               return NL_SKIP;
+
+       if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
+               return NL_SKIP;
+
+       for (i = 0; i < scan_results->num; ++i) {
+               scan_res = scan_results->res[i];
+               if (!scan_res)
+                       continue;
+               if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
+                   scan_res->freq)
+                       continue;
+               if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
+                       continue;
+               scan_res->noise = (s8)
+                       nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+               scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
+       }
+
+       return NL_SKIP;
+}
+
+
+static int nl80211_get_noise_for_scan_results(
+       struct wpa_driver_nl80211_data *drv,
+       struct wpa_scan_results *scan_res)
+{
+       struct nl_msg *msg;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+       return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
+                                 scan_res);
+ nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+
+
 static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
                              struct nlattr *tb[])
 {
@@ -936,10 +1789,13 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
                [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
                [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
                [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
+               [NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 },
        };
        struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
        enum nl80211_cqm_rssi_threshold_event event;
        union wpa_event_data ed;
+       struct wpa_signal_info sig;
+       int res;
 
        if (tb[NL80211_ATTR_CQM] == NULL ||
            nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM],
@@ -948,12 +1804,21 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
                return;
        }
 
+       os_memset(&ed, 0, sizeof(ed));
+
+       if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
+               if (!tb[NL80211_ATTR_MAC])
+                       return;
+               os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]),
+                         ETH_ALEN);
+               wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed);
+               return;
+       }
+
        if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
                return;
        event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
 
-       os_memset(&ed, 0, sizeof(ed));
-
        if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
                wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
                           "event: RSSI high");
@@ -965,49 +1830,227 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
        } else
                return;
 
+       res = nl80211_get_link_signal(drv, &sig);
+       if (res == 0) {
+               ed.signal_change.current_signal = sig.current_signal;
+               ed.signal_change.current_txrate = sig.current_txrate;
+               wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm  txrate: %d",
+                          sig.current_signal, sig.current_txrate);
+       }
+
+       res = nl80211_get_link_noise(drv, &sig);
+       if (res == 0) {
+               ed.signal_change.current_noise = sig.current_noise;
+               wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm",
+                          sig.current_noise);
+       }
+
        wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
 }
 
 
-static int process_event(struct nl_msg *msg, void *arg)
+static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
+                                     struct nlattr **tb)
 {
-       struct wpa_driver_nl80211_data *drv = arg;
-       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       u8 *addr;
        union wpa_event_data data;
 
-       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-                 genlmsg_attrlen(gnlh, 0), NULL);
-
-       if (tb[NL80211_ATTR_IFINDEX]) {
-               int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
-               if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) {
-                       wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
-                                  " for foreign interface (ifindex %d)",
-                                  gnlh->cmd, ifindex);
-                       return NL_SKIP;
+       if (tb[NL80211_ATTR_MAC] == NULL)
+               return;
+       addr = nla_data(tb[NL80211_ATTR_MAC]);
+       wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr));
+
+       if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
+               u8 *ies = NULL;
+               size_t ies_len = 0;
+               if (tb[NL80211_ATTR_IE]) {
+                       ies = nla_data(tb[NL80211_ATTR_IE]);
+                       ies_len = nla_len(tb[NL80211_ATTR_IE]);
                }
+               wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", ies, ies_len);
+               drv_event_assoc(drv->ctx, addr, ies, ies_len, 0);
+               return;
        }
 
-       if (drv->ap_scan_as_station &&
-           (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
-            gnlh->cmd == NL80211_CMD_SCAN_ABORTED)) {
-               wpa_driver_nl80211_set_mode(&drv->first_bss,
-                                           IEEE80211_MODE_AP);
-               drv->ap_scan_as_station = 0;
+       if (drv->nlmode != NL80211_IFTYPE_ADHOC)
+               return;
+
+       os_memset(&data, 0, sizeof(data));
+       os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN);
+       wpa_supplicant_event(drv->ctx, EVENT_IBSS_RSN_START, &data);
+}
+
+
+static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
+                                     struct nlattr **tb)
+{
+       u8 *addr;
+       union wpa_event_data data;
+
+       if (tb[NL80211_ATTR_MAC] == NULL)
+               return;
+       addr = nla_data(tb[NL80211_ATTR_MAC]);
+       wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR,
+                  MAC2STR(addr));
+
+       if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
+               drv_event_disassoc(drv->ctx, addr);
+               return;
        }
 
-       switch (gnlh->cmd) {
-       case NL80211_CMD_TRIGGER_SCAN:
-               wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
-               break;
-       case NL80211_CMD_NEW_SCAN_RESULTS:
-               wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
-               drv->scan_complete_events = 1;
-               eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
+       if (drv->nlmode != NL80211_IFTYPE_ADHOC)
+               return;
+
+       os_memset(&data, 0, sizeof(data));
+       os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN);
+       wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data);
+}
+
+
+static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv,
+                                       struct nlattr **tb)
+{
+       struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA];
+       static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = {
+               [NL80211_REKEY_DATA_KEK] = {
+                       .minlen = NL80211_KEK_LEN,
+                       .maxlen = NL80211_KEK_LEN,
+               },
+               [NL80211_REKEY_DATA_KCK] = {
+                       .minlen = NL80211_KCK_LEN,
+                       .maxlen = NL80211_KCK_LEN,
+               },
+               [NL80211_REKEY_DATA_REPLAY_CTR] = {
+                       .minlen = NL80211_REPLAY_CTR_LEN,
+                       .maxlen = NL80211_REPLAY_CTR_LEN,
+               },
+       };
+       union wpa_event_data data;
+
+       if (!tb[NL80211_ATTR_MAC])
+               return;
+       if (!tb[NL80211_ATTR_REKEY_DATA])
+               return;
+       if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA,
+                            tb[NL80211_ATTR_REKEY_DATA], rekey_policy))
+               return;
+       if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR])
+               return;
+
+       os_memset(&data, 0, sizeof(data));
+       data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]);
+       wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR,
+                  MAC2STR(data.driver_gtk_rekey.bssid));
+       data.driver_gtk_rekey.replay_ctr =
+               nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]);
+       wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter",
+                   data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN);
+       wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data);
+}
+
+
+static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
+                                         struct nlattr **tb)
+{
+       struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE];
+       static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = {
+               [NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 },
+               [NL80211_PMKSA_CANDIDATE_BSSID] = {
+                       .minlen = ETH_ALEN,
+                       .maxlen = ETH_ALEN,
+               },
+               [NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG },
+       };
+       union wpa_event_data data;
+
+       if (!tb[NL80211_ATTR_PMKSA_CANDIDATE])
+               return;
+       if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
+                            tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy))
+               return;
+       if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] ||
+           !cand[NL80211_PMKSA_CANDIDATE_BSSID])
+               return;
+
+       os_memset(&data, 0, sizeof(data));
+       os_memcpy(data.pmkid_candidate.bssid,
+                 nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN);
+       data.pmkid_candidate.index =
+               nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]);
+       data.pmkid_candidate.preauth =
+               cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL;
+       wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
+}
+
+
+static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
+                                      struct nlattr **tb)
+{
+       union wpa_event_data data;
+
+       if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
+               return;
+
+       os_memset(&data, 0, sizeof(data));
+       os_memcpy(data.client_poll.addr,
+                 nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+       wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
+}
+
+
+static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
+                                  int wds)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       union wpa_event_data event;
+
+       if (!tb[NL80211_ATTR_MAC])
+               return;
+
+       os_memset(&event, 0, sizeof(event));
+       event.rx_from_unknown.bssid = bss->addr;
+       event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]);
+       event.rx_from_unknown.wds = wds;
+
+       wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
+}
+
+
+static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
+                                int cmd, struct nlattr **tb)
+{
+       if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
+           (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
+            cmd == NL80211_CMD_SCAN_ABORTED)) {
+               wpa_driver_nl80211_set_mode(&drv->first_bss,
+                                           drv->ap_scan_as_station);
+               drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
+       }
+
+       switch (cmd) {
+       case NL80211_CMD_TRIGGER_SCAN:
+               wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
+               break;
+       case NL80211_CMD_START_SCHED_SCAN:
+               wpa_printf(MSG_DEBUG, "nl80211: Sched scan started");
+               break;
+       case NL80211_CMD_SCHED_SCAN_STOPPED:
+               wpa_printf(MSG_DEBUG, "nl80211: Sched scan stopped");
+               wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
+               break;
+       case NL80211_CMD_NEW_SCAN_RESULTS:
+               wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
+               drv->scan_complete_events = 1;
+               eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
                                     drv->ctx);
                send_scan_event(drv, 0, tb);
                break;
+       case NL80211_CMD_SCHED_SCAN_RESULTS:
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: New sched scan results available");
+               send_scan_event(drv, 0, tb);
+               break;
        case NL80211_CMD_SCAN_ABORTED:
                wpa_printf(MSG_DEBUG, "nl80211: Scan aborted");
                /*
@@ -1022,37 +2065,25 @@ static int process_event(struct nl_msg *msg, void *arg)
        case NL80211_CMD_ASSOCIATE:
        case NL80211_CMD_DEAUTHENTICATE:
        case NL80211_CMD_DISASSOCIATE:
-       case NL80211_CMD_ACTION:
-       case NL80211_CMD_ACTION_TX_STATUS:
-               mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
+       case NL80211_CMD_FRAME_TX_STATUS:
+       case NL80211_CMD_UNPROT_DEAUTHENTICATE:
+       case NL80211_CMD_UNPROT_DISASSOCIATE:
+               mlme_event(drv, cmd, tb[NL80211_ATTR_FRAME],
                           tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
                           tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
                           tb[NL80211_ATTR_COOKIE]);
                break;
        case NL80211_CMD_CONNECT:
        case NL80211_CMD_ROAM:
-               mlme_event_connect(drv, gnlh->cmd,
+               mlme_event_connect(drv, cmd,
                                   tb[NL80211_ATTR_STATUS_CODE],
                                   tb[NL80211_ATTR_MAC],
                                   tb[NL80211_ATTR_REQ_IE],
                                   tb[NL80211_ATTR_RESP_IE]);
                break;
        case NL80211_CMD_DISCONNECT:
-               if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
-                       /*
-                        * Avoid reporting two disassociation events that could
-                        * confuse the core code.
-                        */
-                       wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
-                                  "event when using userspace SME");
-                       break;
-               }
-               drv->associated = 0;
-               os_memset(&data, 0, sizeof(data));
-               if (tb[NL80211_ATTR_REASON_CODE])
-                       data.disassoc_info.reason_code =
-                               nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
-               wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data);
+               mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
+                                     tb[NL80211_ATTR_MAC]);
                break;
        case NL80211_CMD_MICHAEL_MIC_FAILURE:
                mlme_event_michael_mic_failure(drv, tb);
@@ -1069,6 +2100,111 @@ static int process_event(struct nl_msg *msg, void *arg)
        case NL80211_CMD_NOTIFY_CQM:
                nl80211_cqm_event(drv, tb);
                break;
+       case NL80211_CMD_REG_CHANGE:
+               wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
+               wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
+                                    NULL);
+               break;
+       case NL80211_CMD_REG_BEACON_HINT:
+               wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
+               wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
+                                    NULL);
+               break;
+       case NL80211_CMD_NEW_STATION:
+               nl80211_new_station_event(drv, tb);
+               break;
+       case NL80211_CMD_DEL_STATION:
+               nl80211_del_station_event(drv, tb);
+               break;
+       case NL80211_CMD_SET_REKEY_OFFLOAD:
+               nl80211_rekey_offload_event(drv, tb);
+               break;
+       case NL80211_CMD_PMKSA_CANDIDATE:
+               nl80211_pmksa_candidate_event(drv, tb);
+               break;
+       case NL80211_CMD_PROBE_CLIENT:
+               nl80211_client_probe_event(drv, tb);
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
+                          "(cmd=%d)", cmd);
+               break;
+       }
+}
+
+
+static int process_drv_event(struct nl_msg *msg, void *arg)
+{
+       struct wpa_driver_nl80211_data *drv = arg;
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+       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;
+               }
+       }
+
+       do_process_drv_event(drv, gnlh->cmd, tb);
+       return NL_SKIP;
+}
+
+
+static int process_global_event(struct nl_msg *msg, void *arg)
+{
+       struct nl80211_global *global = arg;
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct wpa_driver_nl80211_data *drv;
+       int ifidx = -1;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       if (tb[NL80211_ATTR_IFINDEX])
+               ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+
+       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);
+       }
+
+       return NL_SKIP;
+}
+
+
+static int process_bss_event(struct nl_msg *msg, void *arg)
+{
+       struct i802_bss *bss = arg;
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       switch (gnlh->cmd) {
+       case NL80211_CMD_FRAME:
+       case NL80211_CMD_FRAME_TX_STATUS:
+               mlme_event(bss->drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
+                          tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
+                          tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
+                          tb[NL80211_ATTR_COOKIE]);
+               break;
+       case NL80211_CMD_UNEXPECTED_FRAME:
+               nl80211_spurious_frame(bss, tb, 0);
+               break;
+       case NL80211_CMD_UNEXPECTED_4ADDR_FRAME:
+               nl80211_spurious_frame(bss, tb, 1);
+               break;
        default:
                wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
                           "(cmd=%d)", gnlh->cmd);
@@ -1080,20 +2216,13 @@ static int process_event(struct nl_msg *msg, void *arg)
 
 
 static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
-                                            void *sock_ctx)
+                                            void *handle)
 {
-       struct nl_cb *cb;
-       struct wpa_driver_nl80211_data *drv = eloop_ctx;
+       struct nl_cb *cb = eloop_ctx;
 
        wpa_printf(MSG_DEBUG, "nl80211: Event message available");
 
-       cb = nl_cb_clone(drv->nl_cb);
-       if (!cb)
-               return;
-       nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
-       nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, drv);
-       nl_recvmsgs(drv->nl_handle_event, cb);
-       nl_cb_put(cb);
+       nl_recvmsgs(handle, cb);
 }
 
 
@@ -1121,49 +2250,154 @@ static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
        alpha2[1] = alpha2_arg[1];
        alpha2[2] = '\0';
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_REQ_SET_REG, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG);
 
        NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
        if (send_and_recv_msgs(drv, msg, NULL, NULL))
                return -EINVAL;
        return 0;
 nla_put_failure:
+       nlmsg_free(msg);
        return -EINVAL;
 }
 
 
-#ifndef HOSTAPD
 struct wiphy_info_data {
-       int max_scan_ssids;
-       int ap_supported;
-       int auth_supported;
-       int connect_supported;
+       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;
 };
 
 
+static unsigned int probe_resp_offload_support(int supp_protocols)
+{
+       unsigned int prot = 0;
+
+       if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS)
+               prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS;
+       if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2)
+               prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2;
+       if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P)
+               prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P;
+       if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U)
+               prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING;
+
+       return prot;
+}
+
+
 static int wiphy_info_handler(struct nl_msg *msg, void *arg)
 {
        struct nlattr *tb[NL80211_ATTR_MAX + 1];
        struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
        struct wiphy_info_data *info = arg;
+       int p2p_go_supported = 0, p2p_client_supported = 0;
+       int p2p_concurrent = 0;
+       int auth_supported = 0, connect_supported = 0;
+       struct wpa_driver_capa *capa = info->capa;
+       static struct nla_policy
+       iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
+               [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
+               [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
+               [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG },
+               [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 },
+       },
+       iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
+               [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
+               [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
+       };
 
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
 
        if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
-               info->max_scan_ssids =
+               capa->max_scan_ssids =
                        nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
 
+       if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
+               capa->max_sched_scan_ssids =
+                       nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
+
+       if (tb[NL80211_ATTR_MAX_MATCH_SETS])
+               capa->max_match_sets =
+                       nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
+
        if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) {
                struct nlattr *nl_mode;
                int i;
                nla_for_each_nested(nl_mode,
                                    tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
-                       if (nl_mode->nla_type == NL80211_IFTYPE_AP) {
-                               info->ap_supported = 1;
+                       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;
                        }
+
+broken_combination:
+                       ;
                }
        }
 
@@ -1173,14 +2407,92 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
 
                nla_for_each_nested(nl_cmd,
                                    tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
-                       u32 cmd = nla_get_u32(nl_cmd);
-                       if (cmd == NL80211_CMD_AUTHENTICATE)
-                               info->auth_supported = 1;
-                       else if (cmd == NL80211_CMD_CONNECT)
-                               info->connect_supported = 1;
+                       switch (nla_get_u32(nl_cmd)) {
+                       case NL80211_CMD_AUTHENTICATE:
+                               auth_supported = 1;
+                               break;
+                       case NL80211_CMD_CONNECT:
+                               connect_supported = 1;
+                               break;
+                       case NL80211_CMD_START_SCHED_SCAN:
+                               capa->sched_scan_supported = 1;
+                               break;
+                       case NL80211_CMD_PROBE_CLIENT:
+                               info->poll_command_supported = 1;
+                               break;
+                       }
+               }
+       }
+
+       if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
+               wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
+                          "off-channel TX");
+               capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
+       }
+
+       if (tb[NL80211_ATTR_ROAM_SUPPORT]) {
+               wpa_printf(MSG_DEBUG, "nl80211: Using driver-based roaming");
+               capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
+       }
+
+       /* default to 5000 since early versions of mac80211 don't set it */
+       capa->max_remain_on_chan = 5000;
+
+       if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
+               capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
+
+       if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION])
+               capa->max_remain_on_chan =
+                       nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
+
+       if (auth_supported)
+               capa->flags |= WPA_DRIVER_FLAGS_SME;
+       else if (!connect_supported) {
+               wpa_printf(MSG_INFO, "nl80211: Driver does not support "
+                          "authentication/association or connect commands");
+               info->error = 1;
+       }
+
+       if (p2p_go_supported && p2p_client_supported)
+               capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
+       if (p2p_concurrent) {
+               wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
+                          "interface (driver advertised support)");
+               capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
+               capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
+       }
+
+       if (tb[NL80211_ATTR_TDLS_SUPPORT]) {
+               wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
+               capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
+
+               if (tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]) {
+                       wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
+                       capa->flags |=
+                               WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
                }
        }
 
+       if (tb[NL80211_ATTR_DEVICE_AP_SME])
+               info->device_ap_sme = 1;
+
+       if (tb[NL80211_ATTR_FEATURE_FLAGS]) {
+               u32 flags = nla_get_u32(tb[NL80211_ATTR_FEATURE_FLAGS]);
+
+               if (flags & NL80211_FEATURE_SK_TX_STATUS)
+                       info->data_tx_status = 1;
+       }
+
+       if (tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]) {
+               int protocols =
+                       nla_get_u32(tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
+               wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response "
+                          "offload in AP mode");
+               capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
+               capa->probe_resp_offloads =
+                       probe_resp_offload_support(protocols);
+       }
+
        return NL_SKIP;
 }
 
@@ -1191,12 +2503,13 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
        struct nl_msg *msg;
 
        os_memset(info, 0, sizeof(*info));
+       info->capa = &drv->capa;
+
        msg = nlmsg_alloc();
        if (!msg)
                return -1;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_GET_WIPHY, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex);
 
@@ -1214,6 +2527,10 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
        struct wiphy_info_data info;
        if (wpa_driver_nl80211_get_info(drv, &info))
                return -1;
+
+       if (info.error)
+               return -1;
+
        drv->has_capability = 1;
        /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
        drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
@@ -1228,210 +2545,363 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
                WPA_DRIVER_AUTH_SHARED |
                WPA_DRIVER_AUTH_LEAP;
 
-       drv->capa.max_scan_ssids = info.max_scan_ssids;
-       if (info.ap_supported)
-               drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
+       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.auth_supported)
-               drv->capa.flags |= WPA_DRIVER_FLAGS_SME;
-       else if (!info.connect_supported) {
-               wpa_printf(MSG_INFO, "nl80211: Driver does not support "
-                          "authentication/association or connect commands");
-               return -1;
-       }
+       drv->device_ap_sme = info.device_ap_sme;
+       drv->poll_command_supported = info.poll_command_supported;
+       drv->data_tx_status = info.data_tx_status;
 
-       drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
-       drv->capa.max_remain_on_chan = 5000;
+       /*
+        * If poll command is supported mac80211 is new enough to
+        * have everything we need to not need monitor interfaces.
+        */
+       drv->use_monitor = !info.poll_command_supported;
+
+       /*
+        * If we aren't going to use monitor interfaces, but the
+        * driver doesn't support data TX status, we won't get TX
+        * status for EAPOL frames.
+        */
+       if (!drv->use_monitor && !info.data_tx_status)
+               drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
 
        return 0;
 }
-#endif /* HOSTAPD */
 
 
-static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv,
-                                     void *ctx)
+static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
 {
        int ret;
 
-       /* Initialize generic netlink and nl80211 */
-
-       drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
-       if (drv->nl_cb == NULL) {
-               wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
-                          "callbacks");
-               goto err1;
-       }
-
-       drv->nl_handle = nl_handle_alloc_cb(drv->nl_cb);
-       if (drv->nl_handle == NULL) {
+       global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+       if (global->nl_cb == NULL) {
                wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
                           "callbacks");
-               goto err2;
-       }
-
-       drv->nl_handle_event = nl_handle_alloc_cb(drv->nl_cb);
-       if (drv->nl_handle_event == NULL) {
-               wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
-                          "callbacks (event)");
-               goto err2b;
-       }
-
-       if (genl_connect(drv->nl_handle)) {
-               wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
-                          "netlink");
-               goto err3;
-       }
-
-       if (genl_connect(drv->nl_handle_event)) {
-               wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
-                          "netlink (event)");
-               goto err3;
+               return -1;
        }
 
-#ifdef CONFIG_LIBNL20
-       if (genl_ctrl_alloc_cache(drv->nl_handle, &drv->nl_cache) < 0) {
-               wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-                          "netlink cache");
-               goto err3;
-       }
-       if (genl_ctrl_alloc_cache(drv->nl_handle_event, &drv->nl_cache_event) <
-           0) {
-               wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-                          "netlink cache (event)");
-               goto err3b;
-       }
-#else /* CONFIG_LIBNL20 */
-       drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle);
-       if (drv->nl_cache == NULL) {
-               wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-                          "netlink cache");
-               goto err3;
-       }
-       drv->nl_cache_event = genl_ctrl_alloc_cache(drv->nl_handle_event);
-       if (drv->nl_cache_event == NULL) {
-               wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-                          "netlink cache (event)");
-               goto err3b;
-       }
-#endif /* CONFIG_LIBNL20 */
+       global->nl = nl_create_handle(global->nl_cb, "nl");
+       if (global->nl == NULL)
+               goto err;
 
-       drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211");
-       if (drv->nl80211 == NULL) {
+       global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");
+       if (global->nl80211_id < 0) {
                wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
                           "found");
-               goto err4;
+               goto err;
        }
 
-       ret = nl_get_multicast_id(drv, "nl80211", "scan");
+       global->nl_event = nl_create_handle(global->nl_cb, "event");
+       if (global->nl_event == NULL)
+               goto err;
+
+       ret = nl_get_multicast_id(global, "nl80211", "scan");
        if (ret >= 0)
-               ret = nl_socket_add_membership(drv->nl_handle_event, ret);
+               ret = nl_socket_add_membership(global->nl_event, ret);
        if (ret < 0) {
                wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
                           "membership for scan events: %d (%s)",
                           ret, strerror(-ret));
-               goto err4;
+               goto err;
        }
 
-       ret = nl_get_multicast_id(drv, "nl80211", "mlme");
+       ret = nl_get_multicast_id(global, "nl80211", "mlme");
        if (ret >= 0)
-               ret = nl_socket_add_membership(drv->nl_handle_event, ret);
+               ret = nl_socket_add_membership(global->nl_event, ret);
        if (ret < 0) {
                wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
                           "membership for mlme events: %d (%s)",
                           ret, strerror(-ret));
-               goto err4;
+               goto err;
+       }
+
+       ret = nl_get_multicast_id(global, "nl80211", "regulatory");
+       if (ret >= 0)
+               ret = nl_socket_add_membership(global->nl_event, ret);
+       if (ret < 0) {
+               wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
+                          "membership for regulatory events: %d (%s)",
+                          ret, strerror(-ret));
+               /* Continue without regulatory events */
        }
 
-       eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event),
-                                wpa_driver_nl80211_event_receive, drv, ctx);
+       nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+                 no_seq_check, NULL);
+       nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+                 process_global_event, global);
+
+       eloop_register_read_sock(nl_socket_get_fd(global->nl_event),
+                                wpa_driver_nl80211_event_receive,
+                                global->nl_cb, global->nl_event);
 
        return 0;
 
-err4:
-       nl_cache_free(drv->nl_cache_event);
-err3b:
-       nl_cache_free(drv->nl_cache);
-err3:
-       nl_handle_destroy(drv->nl_handle_event);
-err2b:
-       nl_handle_destroy(drv->nl_handle);
-err2:
-       nl_cb_put(drv->nl_cb);
-err1:
+err:
+       nl_destroy_handles(&global->nl_event);
+       nl_destroy_handles(&global->nl);
+       nl_cb_put(global->nl_cb);
+       global->nl_cb = NULL;
        return -1;
 }
 
 
-/**
- * wpa_driver_nl80211_init - Initialize nl80211 driver interface
- * @ctx: context to be used when calling wpa_supplicant functions,
- * e.g., wpa_supplicant_event()
- * @ifname: interface name, e.g., wlan0
- * Returns: Pointer to private data, %NULL on failure
- */
-static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
+static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
 {
-       struct wpa_driver_nl80211_data *drv;
-       struct netlink_config *cfg;
-       struct i802_bss *bss;
+       drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+       if (!drv->nl_cb) {
+               wpa_printf(MSG_ERROR, "nl80211: Failed to alloc cb struct");
+               return -1;
+       }
 
-       drv = os_zalloc(sizeof(*drv));
-       if (drv == NULL)
-               return NULL;
-       drv->ctx = ctx;
-       bss = &drv->first_bss;
-       bss->drv = drv;
-       os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
+       nl_cb_set(drv->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+                 no_seq_check, NULL);
+       nl_cb_set(drv->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+                 process_drv_event, drv);
+
+       return 0;
+}
+
+
+static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
+{
+       wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
+       /*
+        * This may be for any interface; use ifdown event to disable
+        * interface.
+        */
+}
+
+
+static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
+{
+       struct wpa_driver_nl80211_data *drv = ctx;
+       wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
+       if (linux_set_iface_flags(drv->global->ioctl_sock,
+                                 drv->first_bss.ifname, 1)) {
+               wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
+                          "after rfkill unblock");
+               return;
+       }
+       /* rtnetlink ifup handler will report interface as enabled */
+}
+
+
+static void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv)
+{
+       /* Find phy (radio) to which this interface belongs */
+       char buf[90], *pos;
+       int f, rv;
+
+       drv->phyname[0] = '\0';
+       snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name",
+                drv->first_bss.ifname);
+       f = open(buf, O_RDONLY);
+       if (f < 0) {
+               wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
+                          buf, strerror(errno));
+               return;
+       }
+
+       rv = read(f, drv->phyname, sizeof(drv->phyname) - 1);
+       close(f);
+       if (rv < 0) {
+               wpa_printf(MSG_DEBUG, "Could not read file %s: %s",
+                          buf, strerror(errno));
+               return;
+       }
+
+       drv->phyname[rv] = '\0';
+       pos = os_strchr(drv->phyname, '\n');
+       if (pos)
+               *pos = '\0';
+       wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
+                  drv->first_bss.ifname, drv->phyname);
+}
+
+
+static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
+                                                     void *eloop_ctx,
+                                                     void *handle)
+{
+       struct wpa_driver_nl80211_data *drv = eloop_ctx;
+       u8 data[2048];
+       struct msghdr msg;
+       struct iovec entry;
+       struct {
+               struct cmsghdr cm;
+               char control[512];
+       } control;
+       struct cmsghdr *cmsg;
+       int res, found_ee = 0, found_wifi = 0, acked = 0;
+       union wpa_event_data event;
+
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_iov = &entry;
+       msg.msg_iovlen = 1;
+       entry.iov_base = data;
+       entry.iov_len = sizeof(data);
+       msg.msg_control = &control;
+       msg.msg_controllen = sizeof(control);
+
+       res = recvmsg(sock, &msg, MSG_ERRQUEUE);
+       /* if error or not fitting 802.3 header, return */
+       if (res < 14)
+               return;
+
+       for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
+       {
+               if (cmsg->cmsg_level == SOL_SOCKET &&
+                   cmsg->cmsg_type == SCM_WIFI_STATUS) {
+                       int *ack;
+
+                       found_wifi = 1;
+                       ack = (void *)CMSG_DATA(cmsg);
+                       acked = *ack;
+               }
+
+               if (cmsg->cmsg_level == SOL_PACKET &&
+                   cmsg->cmsg_type == PACKET_TX_TIMESTAMP) {
+                       struct sock_extended_err *err =
+                               (struct sock_extended_err *)CMSG_DATA(cmsg);
+
+                       if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS)
+                               found_ee = 1;
+               }
+       }
+
+       if (!found_ee || !found_wifi)
+               return;
+
+       memset(&event, 0, sizeof(event));
+       event.eapol_tx_status.dst = data;
+       event.eapol_tx_status.data = data + 14;
+       event.eapol_tx_status.data_len = res - 14;
+       event.eapol_tx_status.ack = acked;
+       wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
+}
+
+
+static int nl80211_init_bss(struct i802_bss *bss)
+{
+       bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+       if (!bss->nl_cb)
+               return -1;
+
+       nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+                 no_seq_check, NULL);
+       nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+                 process_bss_event, bss);
+
+       return 0;
+}
+
+
+static void nl80211_destroy_bss(struct i802_bss *bss)
+{
+       nl_cb_put(bss->nl_cb);
+       bss->nl_cb = NULL;
+}
+
+
+/**
+ * wpa_driver_nl80211_init - Initialize nl80211 driver interface
+ * @ctx: context to be used when calling wpa_supplicant functions,
+ * e.g., wpa_supplicant_event()
+ * @ifname: interface name, e.g., wlan0
+ * @global_priv: private driver global data from global_init()
+ * Returns: Pointer to private data, %NULL on failure
+ */
+static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
+                                     void *global_priv)
+{
+       struct wpa_driver_nl80211_data *drv;
+       struct rfkill_config *rcfg;
+       struct i802_bss *bss;
+
+       if (global_priv == NULL)
+               return NULL;
+       drv = os_zalloc(sizeof(*drv));
+       if (drv == NULL)
+               return NULL;
+       drv->global = global_priv;
+       drv->ctx = ctx;
+       bss = &drv->first_bss;
+       bss->drv = drv;
+       os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
        drv->monitor_ifidx = -1;
        drv->monitor_sock = -1;
-       drv->ioctl_sock = -1;
+       drv->eapol_tx_sock = -1;
+       drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
 
-       if (wpa_driver_nl80211_init_nl(drv, ctx)) {
+       if (wpa_driver_nl80211_init_nl(drv)) {
                os_free(drv);
                return NULL;
        }
 
-       drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
-       if (drv->ioctl_sock < 0) {
-               perror("socket(PF_INET,SOCK_DGRAM)");
+       if (nl80211_init_bss(bss))
                goto failed;
-       }
 
-       cfg = os_zalloc(sizeof(*cfg));
-       if (cfg == NULL)
-               goto failed;
-       cfg->ctx = drv;
-       cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
-       cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
-       drv->netlink = netlink_init(cfg);
-       if (drv->netlink == NULL) {
-               os_free(cfg);
+       nl80211_get_phy_name(drv);
+
+       rcfg = os_zalloc(sizeof(*rcfg));
+       if (rcfg == NULL)
                goto failed;
+       rcfg->ctx = drv;
+       os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname));
+       rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
+       rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
+       drv->rfkill = rfkill_init(rcfg);
+       if (drv->rfkill == NULL) {
+               wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available");
+               os_free(rcfg);
        }
+
        if (wpa_driver_nl80211_finish_drv_init(drv))
                goto failed;
 
-       return bss;
+       drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
+       if (drv->eapol_tx_sock < 0)
+               goto failed;
 
-failed:
-       netlink_deinit(drv->netlink);
-       if (drv->ioctl_sock >= 0)
-               close(drv->ioctl_sock);
+       if (drv->data_tx_status) {
+               int enabled = 1;
+
+               if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
+                              &enabled, sizeof(enabled)) < 0) {
+                       wpa_printf(MSG_DEBUG,
+                               "nl80211: wifi status sockopt failed\n");
+                       drv->data_tx_status = 0;
+                       if (!drv->use_monitor)
+                               drv->capa.flags &=
+                                       ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+               } else {
+                       eloop_register_read_sock(drv->eapol_tx_sock,
+                               wpa_driver_nl80211_handle_eapol_tx_status,
+                               drv, NULL);
+               }
+       }
 
-       genl_family_put(drv->nl80211);
-       nl_cache_free(drv->nl_cache);
-       nl_handle_destroy(drv->nl_handle);
-       nl_cb_put(drv->nl_cb);
-       eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
+       if (drv->global) {
+               dl_list_add(&drv->global->interfaces, &drv->list);
+               drv->in_interface_list = 1;
+       }
 
-       os_free(drv);
+       return bss;
+
+failed:
+       wpa_driver_nl80211_deinit(bss);
        return NULL;
 }
 
 
-static int nl80211_register_action_frame(struct wpa_driver_nl80211_data *drv,
-                                        const u8 *match, size_t match_len)
+static int nl80211_register_frame(struct i802_bss *bss,
+                                 struct nl_handle *nl_handle,
+                                 u16 type, const u8 *match, size_t match_len)
 {
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        int ret = -1;
 
@@ -1439,18 +2909,19 @@ static int nl80211_register_action_frame(struct wpa_driver_nl80211_data *drv,
        if (!msg)
                return -1;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-                   NL80211_CMD_REGISTER_ACTION, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
        NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
 
-       ret = send_and_recv(drv, drv->nl_handle_event, msg, NULL, NULL);
+       ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL);
        msg = NULL;
        if (ret) {
-               wpa_printf(MSG_DEBUG, "nl80211: Register Action command "
-                          "failed: ret=%d (%s)", ret, strerror(-ret));
-               wpa_hexdump(MSG_DEBUG, "nl80211: Register Action match",
+               wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
+                          "failed (type=%u): ret=%d (%s)",
+                          type, ret, strerror(-ret));
+               wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
                            match, match_len);
                goto nla_put_failure;
        }
@@ -1461,16 +2932,188 @@ nla_put_failure:
 }
 
 
-static int nl80211_register_action_frames(struct wpa_driver_nl80211_data *drv)
+static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+
+       if (bss->nl_mgmt) {
+               wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
+                          "already on!");
+               return -1;
+       }
+
+       bss->nl_mgmt = nl_create_handle(drv->nl_cb, "mgmt");
+       if (bss->nl_mgmt == NULL)
+               return -1;
+
+       eloop_register_read_sock(nl_socket_get_fd(bss->nl_mgmt),
+                                wpa_driver_nl80211_event_receive, bss->nl_cb,
+                                bss->nl_mgmt);
+
+       return 0;
+}
+
+
+static int nl80211_register_action_frame(struct i802_bss *bss,
+                                        const u8 *match, size_t match_len)
+{
+       u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
+       return nl80211_register_frame(bss, bss->nl_mgmt,
+                                     type, match, match_len);
+}
+
+
+static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
 {
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+
+       if (nl80211_alloc_mgmt_handle(bss))
+               return -1;
+
+#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING)
+       /* GAS Initial Request */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
+               return -1;
+       /* GAS Initial Response */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0)
+               return -1;
+       /* GAS Comeback Request */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0)
+               return -1;
+       /* GAS Comeback Response */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)
+               return -1;
+#endif /* CONFIG_P2P || CONFIG_INTERWORKING */
+#ifdef CONFIG_P2P
+       /* P2P Public Action */
+       if (nl80211_register_action_frame(bss,
+                                         (u8 *) "\x04\x09\x50\x6f\x9a\x09",
+                                         6) < 0)
+               return -1;
+       /* P2P Action */
+       if (nl80211_register_action_frame(bss,
+                                         (u8 *) "\x7f\x50\x6f\x9a\x09",
+                                         5) < 0)
+               return -1;
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_IEEE80211W
+       /* SA Query Response */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
+               return -1;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_TDLS
+       if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
+               /* TDLS Discovery Response */
+               if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) <
+                   0)
+                       return -1;
+       }
+#endif /* CONFIG_TDLS */
+
        /* FT Action frames */
-       if (nl80211_register_action_frame(drv, (u8 *) "\x06", 1) < 0)
+       if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
                return -1;
        else
                drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
                        WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
 
+       /* WNM - BSS Transition Management Request */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
+               return -1;
+
+       return 0;
+}
+
+
+static int nl80211_register_spurious_class3(struct i802_bss *bss)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret = -1;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -1;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_UNEXPECTED_FRAME);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+       ret = send_and_recv(drv->global, bss->nl_mgmt, msg, NULL, NULL);
+       msg = NULL;
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
+                          "failed: ret=%d (%s)",
+                          ret, strerror(-ret));
+               goto nla_put_failure;
+       }
+       ret = 0;
+nla_put_failure:
+       nlmsg_free(msg);
+       return ret;
+}
+
+
+static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
+{
+       static const int stypes[] = {
+               WLAN_FC_STYPE_AUTH,
+               WLAN_FC_STYPE_ASSOC_REQ,
+               WLAN_FC_STYPE_REASSOC_REQ,
+               WLAN_FC_STYPE_DISASSOC,
+               WLAN_FC_STYPE_DEAUTH,
+               WLAN_FC_STYPE_ACTION,
+               WLAN_FC_STYPE_PROBE_REQ,
+/* Beacon doesn't work as mac80211 doesn't currently allow
+ * it, but it wouldn't really be the right thing anyway as
+ * it isn't per interface ... maybe just dump the scan
+ * results periodically for OLBC?
+ */
+//             WLAN_FC_STYPE_BEACON,
+       };
+       unsigned int i;
+
+       if (nl80211_alloc_mgmt_handle(bss))
+               return -1;
+
+       for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) {
+               if (nl80211_register_frame(bss, bss->nl_mgmt,
+                                          (WLAN_FC_TYPE_MGMT << 2) |
+                                          (stypes[i] << 4),
+                                          NULL, 0) < 0) {
+                       goto out_err;
+               }
+       }
+
+       if (nl80211_register_spurious_class3(bss))
+               goto out_err;
+
+       if (nl80211_get_wiphy_data_ap(bss) == NULL)
+               goto out_err;
+
        return 0;
+
+out_err:
+       eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
+       nl_destroy_handles(&bss->nl_mgmt);
+       return -1;
+}
+
+
+static void nl80211_mgmt_unsubscribe(struct i802_bss *bss)
+{
+       if (bss->nl_mgmt == NULL)
+               return;
+       eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
+       nl_destroy_handles(&bss->nl_mgmt);
+
+       nl80211_put_wiphy_data_ap(bss);
+}
+
+
+static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
+{
+       wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
 }
 
 
@@ -1478,37 +3121,52 @@ static int
 wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
 {
        struct i802_bss *bss = &drv->first_bss;
+       int send_rfkill_event = 0;
 
        drv->ifindex = if_nametoindex(bss->ifname);
        drv->first_bss.ifindex = drv->ifindex;
 
 #ifndef HOSTAPD
-       if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA) < 0) {
-               wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to "
+       /*
+        * Make sure the interface starts up in station mode unless this is a
+        * dynamically added interface (e.g., P2P) that was already configured
+        * with proper iftype.
+        */
+       if (drv->ifindex != drv->global->if_add_ifindex &&
+           wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION) < 0) {
+               wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to "
                           "use managed mode");
+               return -1;
        }
 
-       if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) {
-               wpa_printf(MSG_ERROR, "Could not set interface '%s' UP",
-                          bss->ifname);
-               return -1;
+       if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
+               if (rfkill_is_blocked(drv->rfkill)) {
+                       wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable "
+                                  "interface '%s' due to rfkill",
+                                  bss->ifname);
+                       drv->if_disabled = 1;
+                       send_rfkill_event = 1;
+               } else {
+                       wpa_printf(MSG_ERROR, "nl80211: Could not set "
+                                  "interface '%s' UP", bss->ifname);
+                       return -1;
+               }
        }
 
+       netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
+                              1, IF_OPER_DORMANT);
+#endif /* HOSTAPD */
+
        if (wpa_driver_nl80211_capa(drv))
                return -1;
 
-       netlink_send_oper_ifla(drv->netlink, drv->ifindex,
-                              1, IF_OPER_DORMANT);
-#endif /* HOSTAPD */
+       if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+                              bss->addr))
+               return -1;
 
-       if (nl80211_register_action_frames(drv) < 0) {
-               wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
-                          "frame processing - ignore for now");
-               /*
-                * Older kernel versions did not support this, so ignore the
-                * error for now. Some functionality may not be available
-                * because of this.
-                */
+       if (send_rfkill_event) {
+               eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
+                                      drv, drv->ctx);
        }
 
        return 0;
@@ -1523,12 +3181,12 @@ static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
        if (!msg)
                return -ENOMEM;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_DEL_BEACON, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
        return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
@@ -1545,23 +3203,30 @@ static void wpa_driver_nl80211_deinit(void *priv)
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
 
-       if (drv->added_if_into_bridge) {
-               if (linux_br_del_if(drv->ioctl_sock, drv->brname, bss->ifname)
-                   < 0)
+       if (drv->data_tx_status)
+               eloop_unregister_read_sock(drv->eapol_tx_sock);
+       if (drv->eapol_tx_sock >= 0)
+               close(drv->eapol_tx_sock);
+
+       if (bss->nl_preq)
+               wpa_driver_nl80211_probe_req_report(bss, 0);
+       if (bss->added_if_into_bridge) {
+               if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
+                                   bss->ifname) < 0)
                        wpa_printf(MSG_INFO, "nl80211: Failed to remove "
                                   "interface %s from bridge %s: %s",
-                                  bss->ifname, drv->brname, strerror(errno));
+                                  bss->ifname, bss->brname, strerror(errno));
        }
-       if (drv->added_bridge) {
-               if (linux_br_del(drv->ioctl_sock, drv->brname) < 0)
+       if (bss->added_bridge) {
+               if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
                        wpa_printf(MSG_INFO, "nl80211: Failed to remove "
                                   "bridge %s: %s",
-                                  drv->brname, strerror(errno));
+                                  bss->brname, strerror(errno));
        }
 
        nl80211_remove_monitor_interface(drv);
 
-       if (drv->nlmode == NL80211_IFTYPE_AP)
+       if (is_ap_interface(drv->nlmode))
                wpa_driver_nl80211_del_beacon(drv);
 
 #ifdef HOSTAPD
@@ -1582,33 +3247,30 @@ static void wpa_driver_nl80211_deinit(void *priv)
                os_free(drv->if_indices);
 #endif /* HOSTAPD */
 
-       if (drv->disable_11b_rates)
+       if (drv->disabled_11b_rates)
                nl80211_disable_11b_rates(drv, drv->ifindex, 0);
 
-       netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
-       netlink_deinit(drv->netlink);
+       netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
+                              IF_OPER_UP);
+       rfkill_deinit(drv->rfkill);
 
        eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
 
-       (void) linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0);
-       wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA);
+       (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);
 
-       if (drv->ioctl_sock >= 0)
-               close(drv->ioctl_sock);
-
-       eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
-       genl_family_put(drv->nl80211);
-       nl_cache_free(drv->nl_cache);
-       nl_cache_free(drv->nl_cache_event);
-       nl_handle_destroy(drv->nl_handle);
-       nl_handle_destroy(drv->nl_handle_event);
        nl_cb_put(drv->nl_cb);
 
-       eloop_cancel_timeout(wpa_driver_nl80211_probe_req_report_timeout,
-                            drv, NULL);
+       nl80211_destroy_bss(&drv->first_bss);
 
        os_free(drv->filter_ssids);
 
+       os_free(drv->auth_ie);
+
+       if (drv->in_interface_list)
+               dl_list_del(&drv->list);
+
        os_free(drv);
 }
 
@@ -1624,10 +3286,10 @@ static void wpa_driver_nl80211_deinit(void *priv)
 static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 {
        struct wpa_driver_nl80211_data *drv = eloop_ctx;
-       if (drv->ap_scan_as_station) {
+       if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
                wpa_driver_nl80211_set_mode(&drv->first_bss,
-                                           IEEE80211_MODE_AP);
-               drv->ap_scan_as_station = 0;
+                                           drv->ap_scan_as_station);
+               drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
        }
        wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
        wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
@@ -1646,16 +3308,20 @@ static int wpa_driver_nl80211_scan(void *priv,
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int ret = 0, timeout;
-       struct nl_msg *msg, *ssids, *freqs;
+       struct nl_msg *msg, *ssids, *freqs, *rates;
        size_t i;
 
+       drv->scan_for_auth = 0;
+
        msg = nlmsg_alloc();
        ssids = nlmsg_alloc();
        freqs = nlmsg_alloc();
-       if (!msg || !ssids || !freqs) {
+       rates = nlmsg_alloc();
+       if (!msg || !ssids || !freqs || !rates) {
                nlmsg_free(msg);
                nlmsg_free(ssids);
                nlmsg_free(freqs);
+               nlmsg_free(rates);
                return -1;
        }
 
@@ -1664,8 +3330,7 @@ static int wpa_driver_nl80211_scan(void *priv,
        params->filter_ssids = NULL;
        drv->num_filter_ssids = params->num_filter_ssids;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-                   NL80211_CMD_TRIGGER_SCAN, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_TRIGGER_SCAN);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
@@ -1680,8 +3345,8 @@ static int wpa_driver_nl80211_scan(void *priv,
                nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
 
        if (params->extra_ies) {
-               wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan extra IEs",
-                                 params->extra_ies, params->extra_ies_len);
+               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);
        }
@@ -1695,29 +3360,42 @@ static int wpa_driver_nl80211_scan(void *priv,
                nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
        }
 
+       if (params->p2p_probe) {
+               /*
+                * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
+                * by masking out everything else apart from the OFDM rates 6,
+                * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
+                * rates are left enabled.
+                */
+               NLA_PUT(rates, NL80211_BAND_2GHZ, 8,
+                       "\x0c\x12\x18\x24\x30\x48\x60\x6c");
+               nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates);
+
+               NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
+       }
+
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
        if (ret) {
                wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
                           "(%s)", ret, strerror(-ret));
 #ifdef HOSTAPD
-               if (drv->nlmode == NL80211_IFTYPE_AP) {
+               if (is_ap_interface(drv->nlmode)) {
                        /*
                         * mac80211 does not allow scan requests in AP mode, so
                         * try to do this in station mode.
                         */
-                       if (wpa_driver_nl80211_set_mode(bss,
-                                                       IEEE80211_MODE_INFRA))
+                       if (wpa_driver_nl80211_set_mode(
+                                   bss, NL80211_IFTYPE_STATION))
                                goto nla_put_failure;
 
                        if (wpa_driver_nl80211_scan(drv, params)) {
-                               wpa_driver_nl80211_set_mode(bss,
-                                                           IEEE80211_MODE_AP);
+                               wpa_driver_nl80211_set_mode(bss, drv->nlmode);
                                goto nla_put_failure;
                        }
 
                        /* Restore AP mode when processing scan results */
-                       drv->ap_scan_as_station = 1;
+                       drv->ap_scan_as_station = drv->nlmode;
                        ret = 0;
                } else
                        goto nla_put_failure;
@@ -1747,30 +3425,189 @@ nla_put_failure:
        nlmsg_free(ssids);
        nlmsg_free(msg);
        nlmsg_free(freqs);
+       nlmsg_free(rates);
        return ret;
 }
 
 
-static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
+/**
+ * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @params: Scan parameters
+ * @interval: Interval between scan cycles in milliseconds
+ * Returns: 0 on success, -1 on failure or if not supported
+ */
+static int wpa_driver_nl80211_sched_scan(void *priv,
+                                        struct wpa_driver_scan_params *params,
+                                        u32 interval)
 {
-       const u8 *end, *pos;
-
-       if (ies == NULL)
-               return NULL;
+       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;
+       size_t i;
 
-       pos = ies;
-       end = ies + ies_len;
+#ifdef ANDROID
+       if (!drv->capa.sched_scan_supported)
+               return android_pno_start(bss, params);
+#endif /* ANDROID */
 
-       while (pos + 1 < end) {
-               if (pos + 2 + pos[1] > end)
-                       break;
-               if (pos[0] == ie)
-                       return pos;
-               pos += 2 + pos[1];
+       msg = nlmsg_alloc();
+       ssids = nlmsg_alloc();
+       freqs = nlmsg_alloc();
+       if (!msg || !ssids || !freqs) {
+               nlmsg_free(msg);
+               nlmsg_free(ssids);
+               nlmsg_free(freqs);
+               return -1;
        }
 
-       return NULL;
-}
+       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);
+
+       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();
+
+               for (i = 0; i < drv->num_filter_ssids; i++) {
+                       wpa_hexdump_ascii(MSG_MSGDUMP,
+                                         "nl80211: Sched scan filter SSID",
+                                         drv->filter_ssids[i].ssid,
+                                         drv->filter_ssids[i].ssid_len);
+
+                       match_set_ssid = nlmsg_alloc();
+                       nla_put(match_set_ssid,
+                               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_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]);
+               }
+               nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
+       }
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+
+       /* TODO: if we get an error here, we should fall back to normal scan */
+
+       msg = NULL;
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: "
+                          "ret=%d (%s)", ret, strerror(-ret));
+               goto nla_put_failure;
+       }
+
+       wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
+                  "scan interval %d msec", ret, interval);
+
+nla_put_failure:
+       nlmsg_free(ssids);
+       nlmsg_free(msg);
+       nlmsg_free(freqs);
+       return ret;
+}
+
+
+/**
+ * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * Returns: 0 on success, -1 on failure or if not supported
+ */
+static int wpa_driver_nl80211_stop_sched_scan(void *priv)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       int ret = 0;
+       struct nl_msg *msg;
+
+#ifdef ANDROID
+       if (!drv->capa.sched_scan_supported)
+               return android_pno_stop(bss);
+#endif /* ANDROID */
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -1;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_SCHED_SCAN);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop failed: "
+                          "ret=%d (%s)", ret, strerror(-ret));
+               goto nla_put_failure;
+       }
+
+       wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop sent (ret=%d)", ret);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return ret;
+}
+
+
+static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
+{
+       const u8 *end, *pos;
+
+       if (ies == NULL)
+               return NULL;
+
+       pos = ies;
+       end = ies + ies_len;
+
+       while (pos + 1 < end) {
+               if (pos + 2 + pos[1] > end)
+                       break;
+               if (pos[0] == ie)
+                       return pos;
+               pos += 2 + pos[1];
+       }
+
+       return NULL;
+}
 
 
 static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
@@ -1797,11 +3634,6 @@ static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
 }
 
 
-struct nl80211_bss_info_arg {
-       struct wpa_driver_nl80211_data *drv;
-       struct wpa_scan_results *res;
-};
-
 static int bss_info_handler(struct nl_msg *msg, void *arg)
 {
        struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -1827,6 +3659,7 @@ static int bss_info_handler(struct nl_msg *msg, void *arg)
        const u8 *ie, *beacon_ie;
        size_t ie_len, beacon_ie_len;
        u8 *pos;
+       size_t i;
 
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
@@ -1835,6 +3668,26 @@ static int bss_info_handler(struct nl_msg *msg, void *arg)
        if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
                             bss_policy))
                return NL_SKIP;
+       if (bss[NL80211_BSS_STATUS]) {
+               enum nl80211_bss_status status;
+               status = nla_get_u32(bss[NL80211_BSS_STATUS]);
+               if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+                   bss[NL80211_BSS_FREQUENCY]) {
+                       _arg->assoc_freq =
+                               nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+                       wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
+                                  _arg->assoc_freq);
+               }
+               if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+                   bss[NL80211_BSS_BSSID]) {
+                       os_memcpy(_arg->assoc_bssid,
+                                 nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
+                       wpa_printf(MSG_DEBUG, "nl80211: Associated with "
+                                  MACSTR, MAC2STR(_arg->assoc_bssid));
+               }
+       }
+       if (!res)
+               return NL_SKIP;
        if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
                ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
                ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
@@ -1873,7 +3726,7 @@ static int bss_info_handler(struct nl_msg *msg, void *arg)
                r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
        } else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
                r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
-               r->flags |= WPA_SCAN_LEVEL_INVALID;
+               r->flags |= WPA_SCAN_QUAL_INVALID;
        } else
                r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
        if (bss[NL80211_BSS_TSF])
@@ -1905,6 +3758,38 @@ static int bss_info_handler(struct nl_msg *msg, void *arg)
                }
        }
 
+       /*
+        * cfg80211 maintains separate BSS table entries for APs if the same
+        * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
+        * not use frequency as a separate key in the BSS table, so filter out
+        * duplicated entries. Prefer associated BSS entry in such a case in
+        * order to get the correct frequency into the BSS table.
+        */
+       for (i = 0; i < res->num; i++) {
+               const u8 *s1, *s2;
+               if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
+                       continue;
+
+               s1 = nl80211_get_ie((u8 *) (res->res[i] + 1),
+                                   res->res[i]->ie_len, WLAN_EID_SSID);
+               s2 = nl80211_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
+               if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
+                   os_memcmp(s1, s2, 2 + s1[1]) != 0)
+                       continue;
+
+               /* Same BSSID,SSID was already included in scan results */
+               wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
+                          "for " MACSTR, MAC2STR(r->bssid));
+
+               if ((r->flags & WPA_SCAN_ASSOCIATED) &&
+                   !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) {
+                       os_free(res->res[i]);
+                       res->res[i] = r;
+               } else
+                       os_free(r);
+               return NL_SKIP;
+       }
+
        tmp = os_realloc(res->res,
                         (res->num + 1) * sizeof(struct wpa_scan_res *));
        if (tmp == NULL) {
@@ -1943,7 +3828,7 @@ static void wpa_driver_nl80211_check_bss_status(
                                   "indicates BSS status with " MACSTR
                                   " as authenticated",
                                   MAC2STR(r->bssid));
-                       if (drv->nlmode == NL80211_IFTYPE_STATION &&
+                       if (is_sta_interface(drv->nlmode) &&
                            os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 &&
                            os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) !=
                            0) {
@@ -1961,13 +3846,13 @@ static void wpa_driver_nl80211_check_bss_status(
                                   "indicate BSS status with " MACSTR
                                   " as associated",
                                   MAC2STR(r->bssid));
-                       if (drv->nlmode == NL80211_IFTYPE_STATION &&
+                       if (is_sta_interface(drv->nlmode) &&
                            !drv->associated) {
                                wpa_printf(MSG_DEBUG, "nl80211: Local state "
                                           "(not associated) does not match "
                                           "with BSS state");
                                clear_state_mismatch(drv, r->bssid);
-                       } else if (drv->nlmode == NL80211_IFTYPE_STATION &&
+                       } else if (is_sta_interface(drv->nlmode) &&
                                   os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
                                   0) {
                                wpa_printf(MSG_DEBUG, "nl80211: Local state "
@@ -1982,20 +3867,6 @@ static void wpa_driver_nl80211_check_bss_status(
 }
 
 
-static void wpa_scan_results_free(struct wpa_scan_results *res)
-{
-       size_t i;
-
-       if (res == NULL)
-               return;
-
-       for (i = 0; i < res->num; i++)
-               os_free(res->res[i]);
-       os_free(res->res);
-       os_free(res);
-}
-
-
 static struct wpa_scan_results *
 nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
 {
@@ -2011,8 +3882,7 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
        if (!msg)
                goto nla_put_failure;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, NLM_F_DUMP,
-                   NL80211_CMD_GET_SCAN, 0);
+       nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
        arg.drv = drv;
@@ -2020,8 +3890,9 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
        ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
        msg = NULL;
        if (ret == 0) {
-               wpa_printf(MSG_DEBUG, "Received scan results (%lu BSSes)",
-                          (unsigned long) res->num);
+               wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
+                          "BSSes)", (unsigned long) res->num);
+               nl80211_get_noise_for_scan_results(drv, res);
                return res;
        }
        wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
@@ -2092,17 +3963,19 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
                   "set_tx=%d seq_len=%lu key_len=%lu",
                   __func__, ifindex, alg, addr, key_idx, set_tx,
                   (unsigned long) seq_len, (unsigned long) key_len);
+#ifdef CONFIG_TDLS
+       if (key_idx == -1)
+               key_idx = 0;
+#endif /* CONFIG_TDLS */
 
        msg = nlmsg_alloc();
        if (!msg)
                return -ENOMEM;
 
        if (alg == WPA_ALG_NONE) {
-               genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                           0, NL80211_CMD_DEL_KEY, 0);
+               nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_KEY);
        } else {
-               genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                           0, NL80211_CMD_NEW_KEY, 0);
+               nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY);
                NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
                switch (alg) {
                case WPA_ALG_WEP:
@@ -2136,10 +4009,28 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
        if (seq && seq_len)
                NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq);
 
-       if (addr && os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)
-       {
+       if (addr && !is_broadcast_ether_addr(addr)) {
                wpa_printf(MSG_DEBUG, "   addr=" MACSTR, MAC2STR(addr));
                NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+               if (alg != WPA_ALG_WEP && key_idx && !set_tx) {
+                       wpa_printf(MSG_DEBUG, "   RSN IBSS RX GTK");
+                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE,
+                                   NL80211_KEYTYPE_GROUP);
+               }
+       } else if (addr && is_broadcast_ether_addr(addr)) {
+               struct nl_msg *types;
+               int err;
+               wpa_printf(MSG_DEBUG, "   broadcast key");
+               types = nlmsg_alloc();
+               if (!types)
+                       goto nla_put_failure;
+               NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+               err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
+                                    types);
+               nlmsg_free(types);
+               if (err)
+                       goto nla_put_failure;
        }
        NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
@@ -2157,26 +4048,46 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
         */
        if (ret || !set_tx || alg == WPA_ALG_NONE)
                return ret;
-#ifdef HOSTAPD
-       if (addr)
-               return ret;
-#else /* HOSTAPD */
-       if (drv->nlmode == NL80211_IFTYPE_AP && addr)
+       if (is_ap_interface(drv->nlmode) && addr &&
+           !is_broadcast_ether_addr(addr))
                return ret;
-#endif /* HOSTAPD */
 
        msg = nlmsg_alloc();
        if (!msg)
                return -ENOMEM;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_SET_KEY, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_KEY);
        NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
        if (alg == WPA_ALG_IGTK)
                NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT);
        else
                NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
+       if (addr && is_broadcast_ether_addr(addr)) {
+               struct nl_msg *types;
+               int err;
+               types = nlmsg_alloc();
+               if (!types)
+                       goto nla_put_failure;
+               NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+               err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
+                                    types);
+               nlmsg_free(types);
+               if (err)
+                       goto nla_put_failure;
+       } else if (addr) {
+               struct nl_msg *types;
+               int err;
+               types = nlmsg_alloc();
+               if (!types)
+                       goto nla_put_failure;
+               NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_UNICAST);
+               err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
+                                    types);
+               nlmsg_free(types);
+               if (err)
+                       goto nla_put_failure;
+       }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        if (ret == -ENOENT)
@@ -2187,6 +4098,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
        return ret;
 
 nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
@@ -2257,6 +4169,12 @@ static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
                privacy = 1;
                break;
        }
+       if (params->wps == WPS_MODE_PRIVACY)
+               privacy = 1;
+       if (params->pairwise_suite &&
+           params->pairwise_suite != WPA_CIPHER_NONE)
+               privacy = 1;
+
        if (!privacy)
                return 0;
 
@@ -2310,7 +4228,7 @@ static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
        if (!msg)
                return -1;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, cmd, 0);
+       nl80211_cmd(drv, msg, 0, cmd);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
        NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
@@ -2321,8 +4239,9 @@ static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
        if (ret) {
-               wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
-                          "(%s)", ret, strerror(-ret));
+               wpa_dbg(drv->ctx, MSG_DEBUG,
+                       "nl80211: MLME command failed: reason=%u ret=%d (%s)",
+                       reason_code, ret, strerror(-ret));
                goto nla_put_failure;
        }
        ret = 0;
@@ -2336,7 +4255,8 @@ nla_put_failure:
 static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
                                         const u8 *addr, int reason_code)
 {
-       wpa_printf(MSG_DEBUG, "%s", __func__);
+       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,
                                       reason_code, 0);
@@ -2350,8 +4270,11 @@ static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
        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__);
+       wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
+                  __func__, MAC2STR(addr), reason_code);
        drv->associated = 0;
+       if (drv->nlmode == NL80211_IFTYPE_ADHOC)
+               return nl80211_leave_ibss(drv);
        return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
                                       reason_code, 0);
 }
@@ -2371,6 +4294,52 @@ static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
 }
 
 
+static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
+                                    struct wpa_driver_auth_params *params)
+{
+       int i;
+
+       drv->auth_freq = params->freq;
+       drv->auth_alg = params->auth_alg;
+       drv->auth_wep_tx_keyidx = params->wep_tx_keyidx;
+       drv->auth_local_state_change = params->local_state_change;
+       drv->auth_p2p = params->p2p;
+
+       if (params->bssid)
+               os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN);
+       else
+               os_memset(drv->auth_bssid_, 0, ETH_ALEN);
+
+       if (params->ssid) {
+               os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len);
+               drv->auth_ssid_len = params->ssid_len;
+       } else
+               drv->auth_ssid_len = 0;
+
+
+       os_free(drv->auth_ie);
+       drv->auth_ie = NULL;
+       drv->auth_ie_len = 0;
+       if (params->ie) {
+               drv->auth_ie = os_malloc(params->ie_len);
+               if (drv->auth_ie) {
+                       os_memcpy(drv->auth_ie, params->ie, params->ie_len);
+                       drv->auth_ie_len = params->ie_len;
+               }
+       }
+
+       for (i = 0; i < 4; i++) {
+               if (params->wep_key[i] && params->wep_key_len[i] &&
+                   params->wep_key_len[i] <= 16) {
+                       os_memcpy(drv->auth_wep_key[i], params->wep_key[i],
+                                 params->wep_key_len[i]);
+                       drv->auth_wep_key_len[i] = params->wep_key_len[i];
+               } else
+                       drv->auth_wep_key_len[i] = 0;
+       }
+}
+
+
 static int wpa_driver_nl80211_authenticate(
        void *priv, struct wpa_driver_auth_params *params)
 {
@@ -2379,15 +4348,20 @@ static int wpa_driver_nl80211_authenticate(
        int ret = -1, i;
        struct nl_msg *msg;
        enum nl80211_auth_type type;
+       enum nl80211_iftype nlmode;
        int count = 0;
+       int is_retry;
+
+       is_retry = drv->retry_auth;
+       drv->retry_auth = 0;
 
        drv->associated = 0;
        os_memset(drv->auth_bssid, 0, ETH_ALEN);
        /* FIX: IBSS mode */
-       if (drv->nlmode != NL80211_IFTYPE_STATION)
-               wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA);
-
-       if (wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA) < 0)
+       nlmode = params->p2p ?
+               NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
+       if (drv->nlmode != nlmode &&
+           wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
                return -1;
 
 retry:
@@ -2398,8 +4372,7 @@ retry:
        wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
                   drv->ifindex);
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-                   NL80211_CMD_AUTHENTICATE, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_AUTHENTICATE);
 
        for (i = 0; i < 4; i++) {
                if (!params->wep_key[i])
@@ -2457,8 +4430,9 @@ retry:
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
        if (ret) {
-               wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
-                          "(%s)", ret, strerror(-ret));
+               wpa_dbg(drv->ctx, MSG_DEBUG,
+                       "nl80211: MLME command failed (auth): ret=%d (%s)",
+                       ret, strerror(-ret));
                count++;
                if (ret == -EALREADY && count == 1 && params->bssid &&
                    !params->local_state_change) {
@@ -2475,6 +4449,49 @@ retry:
                        nlmsg_free(msg);
                        goto retry;
                }
+
+               if (ret == -ENOENT && params->freq && !is_retry) {
+                       /*
+                        * cfg80211 has likely expired the BSS entry even
+                        * though it was previously available in our internal
+                        * BSS table. To recover quickly, start a single
+                        * channel scan on the specified channel.
+                        */
+                       struct wpa_driver_scan_params scan;
+                       int freqs[2];
+
+                       os_memset(&scan, 0, sizeof(scan));
+                       scan.num_ssids = 1;
+                       if (params->ssid) {
+                               scan.ssids[0].ssid = params->ssid;
+                               scan.ssids[0].ssid_len = params->ssid_len;
+                       }
+                       freqs[0] = params->freq;
+                       freqs[1] = 0;
+                       scan.freqs = freqs;
+                       wpa_printf(MSG_DEBUG, "nl80211: Trigger single "
+                                  "channel scan to refresh cfg80211 BSS "
+                                  "entry");
+                       ret = wpa_driver_nl80211_scan(bss, &scan);
+                       if (ret == 0) {
+                               nl80211_copy_auth_params(drv, params);
+                               drv->scan_for_auth = 1;
+                       }
+               } else if (is_retry) {
+                       /*
+                        * Need to indicate this with an event since the return
+                        * value from the retry is not delivered to core code.
+                        */
+                       union wpa_event_data event;
+                       wpa_printf(MSG_DEBUG, "nl80211: Authentication retry "
+                                  "failed");
+                       os_memset(&event, 0, sizeof(event));
+                       os_memcpy(event.timeout_event.addr, drv->auth_bssid_,
+                                 ETH_ALEN);
+                       wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
+                                            &event);
+               }
+
                goto nla_put_failure;
        }
        ret = 0;
@@ -2487,6 +4504,45 @@ nla_put_failure:
 }
 
 
+static int wpa_driver_nl80211_authenticate_retry(
+       struct wpa_driver_nl80211_data *drv)
+{
+       struct wpa_driver_auth_params params;
+       struct i802_bss *bss = &drv->first_bss;
+       int i;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
+
+       os_memset(&params, 0, sizeof(params));
+       params.freq = drv->auth_freq;
+       params.auth_alg = drv->auth_alg;
+       params.wep_tx_keyidx = drv->auth_wep_tx_keyidx;
+       params.local_state_change = drv->auth_local_state_change;
+       params.p2p = drv->auth_p2p;
+
+       if (!is_zero_ether_addr(drv->auth_bssid_))
+               params.bssid = drv->auth_bssid_;
+
+       if (drv->auth_ssid_len) {
+               params.ssid = drv->auth_ssid;
+               params.ssid_len = drv->auth_ssid_len;
+       }
+
+       params.ie = drv->auth_ie;
+       params.ie_len = drv->auth_ie_len;
+
+       for (i = 0; i < 4; i++) {
+               if (drv->auth_wep_key_len[i]) {
+                       params.wep_key[i] = drv->auth_wep_key[i];
+                       params.wep_key_len[i] = drv->auth_wep_key_len[i];
+               }
+       }
+
+       drv->retry_auth = 1;
+       return wpa_driver_nl80211_authenticate(bss, &params);
+}
+
+
 struct phy_info_arg {
        u16 *num_modes;
        struct hostapd_hw_modes *modes;
@@ -2539,6 +4595,7 @@ static int phy_info_handler(struct nl_msg *msg, void *arg)
 
                mode = &phy_info->modes[*(phy_info->num_modes)];
                memset(mode, 0, sizeof(*mode));
+               mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN;
                *(phy_info->num_modes) += 1;
 
                nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
@@ -2737,45 +4794,195 @@ wpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes)
 }
 
 
-static struct hostapd_hw_modes *
-wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
+static void nl80211_set_ht40_mode(struct hostapd_hw_modes *mode, int start,
+                                 int end)
 {
-       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,
-       };
+       int c;
 
-       *num_modes = 0;
-       *flags = 0;
+       for (c = 0; c < mode->num_channels; c++) {
+               struct hostapd_channel_data *chan = &mode->channels[c];
+               if (chan->freq - 10 >= start && chan->freq + 10 <= end)
+                       chan->flag |= HOSTAPD_CHAN_HT40;
+       }
+}
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return NULL;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_GET_WIPHY, 0);
+static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start,
+                                     int end)
+{
+       int c;
+
+       for (c = 0; c < mode->num_channels; c++) {
+               struct hostapd_channel_data *chan = &mode->channels[c];
+               if (!(chan->flag & HOSTAPD_CHAN_HT40))
+                       continue;
+               if (chan->freq - 30 >= start && chan->freq - 10 <= end)
+                       chan->flag |= HOSTAPD_CHAN_HT40MINUS;
+               if (chan->freq + 10 >= start && chan->freq + 30 <= end)
+                       chan->flag |= HOSTAPD_CHAN_HT40PLUS;
+       }
+}
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
-       if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0)
-               return wpa_driver_nl80211_add_11b(result.modes, num_modes);
- nla_put_failure:
-       return NULL;
+static void nl80211_reg_rule_ht40(struct nlattr *tb[],
+                                 struct phy_info_arg *results)
+{
+       u32 start, end, max_bw;
+       u16 m;
+
+       if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+           tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+           tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
+               return;
+
+       start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+       end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+       max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+
+       wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz",
+                  start, end, max_bw);
+       if (max_bw < 40)
+               return;
+
+       for (m = 0; m < *results->num_modes; m++) {
+               if (!(results->modes[m].ht_capab &
+                     HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+                       continue;
+               nl80211_set_ht40_mode(&results->modes[m], start, end);
+       }
 }
 
 
-static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv,
-                                        const void *data, size_t len,
-                                        int encrypt)
+static void nl80211_reg_rule_sec(struct nlattr *tb[],
+                                struct phy_info_arg *results)
 {
-       __u8 rtap_hdr[] = {
-               0x00, 0x00, /* radiotap version */
-               0x0e, 0x00, /* radiotap length */
-               0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
-               IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
+       u32 start, end, max_bw;
+       u16 m;
+
+       if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+           tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+           tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
+               return;
+
+       start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+       end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+       max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+
+       if (max_bw < 20)
+               return;
+
+       for (m = 0; m < *results->num_modes; m++) {
+               if (!(results->modes[m].ht_capab &
+                     HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+                       continue;
+               nl80211_set_ht40_mode_sec(&results->modes[m], start, end);
+       }
+}
+
+
+static int nl80211_get_reg(struct nl_msg *msg, void *arg)
+{
+       struct phy_info_arg *results = arg;
+       struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *nl_rule;
+       struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1];
+       int rem_rule;
+       static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
+               [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
+               [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
+               [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
+               [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
+               [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
+               [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
+       };
+
+       nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+       if (!tb_msg[NL80211_ATTR_REG_ALPHA2] ||
+           !tb_msg[NL80211_ATTR_REG_RULES]) {
+               wpa_printf(MSG_DEBUG, "nl80211: No regulatory information "
+                          "available");
+               return NL_SKIP;
+       }
+
+       wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
+                  (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
+
+       nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+       {
+               nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+                         nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+               nl80211_reg_rule_ht40(tb_rule, results);
+       }
+
+       nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+       {
+               nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+                         nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+               nl80211_reg_rule_sec(tb_rule, results);
+       }
+
+       return NL_SKIP;
+}
+
+
+static int nl80211_set_ht40_flags(struct wpa_driver_nl80211_data *drv,
+                                 struct phy_info_arg *results)
+{
+       struct nl_msg *msg;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
+       return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
+}
+
+
+static struct hostapd_hw_modes *
+wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       struct phy_info_arg result = {
+               .num_modes = num_modes,
+               .modes = NULL,
+       };
+
+       *num_modes = 0;
+       *flags = 0;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return NULL;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+       if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
+               nl80211_set_ht40_flags(drv, &result);
+               return wpa_driver_nl80211_add_11b(result.modes, num_modes);
+       }
+       msg = NULL;
+ nla_put_failure:
+       nlmsg_free(msg);
+       return NULL;
+}
+
+
+static int wpa_driver_nl80211_send_mntr(struct wpa_driver_nl80211_data *drv,
+                                       const void *data, size_t len,
+                                       int encrypt, int noack)
+{
+       __u8 rtap_hdr[] = {
+               0x00, 0x00, /* radiotap version */
+               0x0e, 0x00, /* radiotap length */
+               0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
+               IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
                0x00,       /* padding */
                0x00, 0x00, /* RX and TX flags to indicate that */
                0x00, 0x00, /* this is the injected frame directly */
@@ -2799,16 +5006,49 @@ static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv,
                .msg_controllen = 0,
                .msg_flags = 0,
        };
+       int res;
+       u16 txflags = 0;
 
        if (encrypt)
                rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
 
-       return sendmsg(drv->monitor_sock, &msg, 0);
+       if (drv->monitor_sock < 0) {
+               wpa_printf(MSG_DEBUG, "nl80211: No monitor socket available "
+                          "for %s", __func__);
+               return -1;
+       }
+
+       if (noack)
+               txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
+       *(le16 *) &rtap_hdr[12] = host_to_le16(txflags);
+
+       res = sendmsg(drv->monitor_sock, &msg, 0);
+       if (res < 0) {
+               wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
+                                        const void *data, size_t len,
+                                        int encrypt, int noack)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       u64 cookie;
+
+       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);
 }
 
 
 static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
-                                       size_t data_len)
+                                       size_t data_len, int noack)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -2819,6 +5059,25 @@ 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) &&
+           WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+           WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
+               /*
+                * The use of last_mgmt_freq is a bit of a hack,
+                * but it works due to the single-threaded nature
+                * of wpa_supplicant.
+                */
+               return nl80211_send_frame_cmd(bss, drv->last_mgmt_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 (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
            WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
                /*
@@ -2833,14 +5092,58 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
                        encrypt = 0;
        }
 
-       return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
+       return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
+                                            noack);
+}
+
+
+static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
+                          int slot, int ht_opmode, int ap_isolate,
+                          int *basic_rates)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_BSS);
+
+       if (cts >= 0)
+               NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts);
+       if (preamble >= 0)
+               NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble);
+       if (slot >= 0)
+               NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
+       if (ht_opmode >= 0)
+               NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode);
+       if (ap_isolate >= 0)
+               NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate);
+
+       if (basic_rates) {
+               u8 rates[NL80211_MAX_SUPP_RATES];
+               u8 rates_len = 0;
+               int i;
+
+               for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0;
+                    i++)
+                       rates[rates_len++] = basic_rates[i] / 5;
+
+               NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
+       }
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
+
+       return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
 }
 
 
-static int wpa_driver_nl80211_set_beacon(void *priv,
-                                        const u8 *head, size_t head_len,
-                                        const u8 *tail, size_t tail_len,
-                                        int dtim_period, int beacon_int)
+static int wpa_driver_nl80211_set_ap(void *priv,
+                                    struct wpa_driver_ap_params *params)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -2849,6 +5152,9 @@ static int wpa_driver_nl80211_set_beacon(void *priv,
        int ret;
        int beacon_set;
        int ifindex = if_nametoindex(bss->ifname);
+       int num_suites;
+       u32 suites[10];
+       u32 ver;
 
        beacon_set = bss->beacon_set;
 
@@ -2861,13 +5167,112 @@ static int wpa_driver_nl80211_set_beacon(void *priv,
        if (beacon_set)
                cmd = NL80211_CMD_SET_BEACON;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, cmd, 0);
-       NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head);
-       NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail);
+       nl80211_cmd(drv, msg, 0, cmd);
+       NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head);
+       NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
-       NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, beacon_int);
-       NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
+       NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int);
+       NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period);
+       NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
+               params->ssid);
+       if (params->proberesp && params->proberesp_len)
+               NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
+                       params->proberesp);
+       switch (params->hide_ssid) {
+       case NO_SSID_HIDING:
+               NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
+                           NL80211_HIDDEN_SSID_NOT_IN_USE);
+               break;
+       case HIDDEN_SSID_ZERO_LEN:
+               NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
+                           NL80211_HIDDEN_SSID_ZERO_LEN);
+               break;
+       case HIDDEN_SSID_ZERO_CONTENTS:
+               NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
+                           NL80211_HIDDEN_SSID_ZERO_CONTENTS);
+               break;
+       }
+       if (params->privacy)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
+       if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
+           (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
+               /* Leave out the attribute */
+       } else if (params->auth_algs & WPA_AUTH_ALG_SHARED)
+               NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
+                           NL80211_AUTHTYPE_SHARED_KEY);
+       else
+               NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
+                           NL80211_AUTHTYPE_OPEN_SYSTEM);
+
+       ver = 0;
+       if (params->wpa_version & WPA_PROTO_WPA)
+               ver |= NL80211_WPA_VERSION_1;
+       if (params->wpa_version & WPA_PROTO_RSN)
+               ver |= NL80211_WPA_VERSION_2;
+       if (ver)
+               NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
+
+       num_suites = 0;
+       if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
+               suites[num_suites++] = WLAN_AKM_SUITE_8021X;
+       if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK)
+               suites[num_suites++] = WLAN_AKM_SUITE_PSK;
+       if (num_suites) {
+               NLA_PUT(msg, NL80211_ATTR_AKM_SUITES,
+                       num_suites * sizeof(u32), suites);
+       }
+
+       if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X &&
+           params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40))
+               NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT);
+
+       num_suites = 0;
+       if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
+               suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
+       if (params->pairwise_ciphers & WPA_CIPHER_TKIP)
+               suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP;
+       if (params->pairwise_ciphers & WPA_CIPHER_WEP104)
+               suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104;
+       if (params->pairwise_ciphers & WPA_CIPHER_WEP40)
+               suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40;
+       if (num_suites) {
+               NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+                       num_suites * sizeof(u32), suites);
+       }
+
+       switch (params->group_cipher) {
+       case WPA_CIPHER_CCMP:
+               NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+                           WLAN_CIPHER_SUITE_CCMP);
+               break;
+       case WPA_CIPHER_TKIP:
+               NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+                           WLAN_CIPHER_SUITE_TKIP);
+               break;
+       case WPA_CIPHER_WEP104:
+               NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+                           WLAN_CIPHER_SUITE_WEP104);
+               break;
+       case WPA_CIPHER_WEP40:
+               NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+                           WLAN_CIPHER_SUITE_WEP40);
+               break;
+       }
+
+       if (params->beacon_ies) {
+               NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies),
+                       wpabuf_head(params->beacon_ies));
+       }
+       if (params->proberesp_ies) {
+               NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
+                       wpabuf_len(params->proberesp_ies),
+                       wpabuf_head(params->proberesp_ies));
+       }
+       if (params->assocresp_ies) {
+               NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP,
+                       wpabuf_len(params->assocresp_ies),
+                       wpabuf_head(params->assocresp_ies));
+       }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        if (ret) {
@@ -2875,26 +5280,33 @@ static int wpa_driver_nl80211_set_beacon(void *priv,
                           ret, strerror(-ret));
        } else {
                bss->beacon_set = 1;
+               nl80211_set_bss(bss, params->cts_protect, params->preamble,
+                               params->short_slot_time, params->ht_opmode,
+                               params->isolate, params->basic_rates);
        }
        return ret;
  nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
 
-static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv,
+static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
                                       int freq, int ht_enabled,
                                       int sec_channel_offset)
 {
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        int ret;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d "
+                  "sec_channel_offset=%d)",
+                  freq, ht_enabled, sec_channel_offset);
        msg = nlmsg_alloc();
        if (!msg)
                return -1;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-                   NL80211_CMD_SET_WIPHY, 0);
+       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);
@@ -2916,50 +5328,102 @@ static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv,
        }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-       if (ret == 0)
+       msg = NULL;
+       if (ret == 0) {
+               bss->freq = freq;
                return 0;
+       }
        wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
                   "%d (%s)", freq, ret, strerror(-ret));
 nla_put_failure:
+       nlmsg_free(msg);
        return -1;
 }
 
 
+static u32 sta_flags_nl80211(int flags)
+{
+       u32 f = 0;
+
+       if (flags & WPA_STA_AUTHORIZED)
+               f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
+       if (flags & WPA_STA_WMM)
+               f |= BIT(NL80211_STA_FLAG_WME);
+       if (flags & WPA_STA_SHORT_PREAMBLE)
+               f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
+       if (flags & WPA_STA_MFP)
+               f |= BIT(NL80211_STA_FLAG_MFP);
+       if (flags & WPA_STA_TDLS_PEER)
+               f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
+
+       return f;
+}
+
+
 static int wpa_driver_nl80211_sta_add(void *priv,
                                      struct hostapd_sta_add_params *params)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       struct nl_msg *msg;
+       struct nl_msg *msg, *wme = NULL;
+       struct nl80211_sta_flag_update upd;
        int ret = -ENOBUFS;
 
+       if ((params->flags & WPA_STA_TDLS_PEER) &&
+           !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+               return -EOPNOTSUPP;
+
        msg = nlmsg_alloc();
        if (!msg)
                return -ENOMEM;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_NEW_STATION, 0);
+       nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION :
+                   NL80211_CMD_NEW_STATION);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
-       NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
        NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
                params->supp_rates);
-       NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
-                   params->listen_interval);
+       if (!params->set) {
+               NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+               NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
+                           params->listen_interval);
+       }
        if (params->ht_capabilities) {
                NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
                        sizeof(*params->ht_capabilities),
                        params->ht_capabilities);
        }
 
+       os_memset(&upd, 0, sizeof(upd));
+       upd.mask = sta_flags_nl80211(params->flags);
+       upd.set = upd.mask;
+       NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
+
+       if (params->flags & WPA_STA_WMM) {
+               wme = nlmsg_alloc();
+               if (!wme)
+                       goto nla_put_failure;
+
+               NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
+                               params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
+               NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
+                               (params->qosinfo > WMM_QOSINFO_STA_SP_SHIFT) &
+                               WMM_QOSINFO_STA_SP_MASK);
+               nla_put_nested(msg, NL80211_ATTR_STA_WME, wme);
+       }
+
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
        if (ret)
-               wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_NEW_STATION "
-                          "result: %d (%s)", ret, strerror(-ret));
+               wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
+                          "result: %d (%s)", params->set ? "SET" : "NEW", ret,
+                          strerror(-ret));
        if (ret == -EEXIST)
                ret = 0;
  nla_put_failure:
+       nlmsg_free(wme);
+       nlmsg_free(msg);
        return ret;
 }
 
@@ -2975,8 +5439,7 @@ static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr)
        if (!msg)
                return -ENOMEM;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_DEL_STATION, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
                    if_nametoindex(bss->ifname));
@@ -2987,6 +5450,7 @@ static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr)
                return 0;
        return ret;
  nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
@@ -2998,26 +5462,46 @@ static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
 
        wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
 
-#ifdef HOSTAPD
        /* stop listening for EAPOL on this interface */
        del_ifidx(drv, ifidx);
-#endif /* HOSTAPD */
 
        msg = nlmsg_alloc();
        if (!msg)
                goto nla_put_failure;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_DEL_INTERFACE, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
 
        if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
                return;
+       msg = NULL;
  nla_put_failure:
+       nlmsg_free(msg);
        wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
 }
 
 
+static const char * nl80211_iftype_str(enum nl80211_iftype mode)
+{
+       switch (mode) {
+       case NL80211_IFTYPE_ADHOC:
+               return "ADHOC";
+       case NL80211_IFTYPE_STATION:
+               return "STATION";
+       case NL80211_IFTYPE_AP:
+               return "AP";
+       case NL80211_IFTYPE_MONITOR:
+               return "MONITOR";
+       case NL80211_IFTYPE_P2P_CLIENT:
+               return "P2P_CLIENT";
+       case NL80211_IFTYPE_P2P_GO:
+               return "P2P_GO";
+       default:
+               return "unknown";
+       }
+}
+
+
 static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                                     const char *ifname,
                                     enum nl80211_iftype iftype,
@@ -3027,12 +5511,14 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
        int ifidx;
        int ret = -ENOBUFS;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)",
+                  iftype, nl80211_iftype_str(iftype));
+
        msg = nlmsg_alloc();
        if (!msg)
                return -1;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_NEW_INTERFACE, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
        NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
        NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
@@ -3057,8 +5543,10 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
        }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
        if (ret) {
  nla_put_failure:
+               nlmsg_free(msg);
                wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
                           ifname, ret, strerror(-ret));
                return ret;
@@ -3071,13 +5559,11 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
        if (ifidx <= 0)
                return -1;
 
-#ifdef HOSTAPD
        /* start listening for EAPOL on this interface */
        add_ifidx(drv, ifidx);
-#endif /* HOSTAPD */
 
        if (addr && iftype != NL80211_IFTYPE_MONITOR &&
-           linux_set_ifhwaddr(drv->ioctl_sock, ifname, addr)) {
+           linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) {
                nl80211_remove_iface(drv, ifidx);
                return -1;
        }
@@ -3094,7 +5580,7 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
 
        ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
 
-       /* if error occured and interface exists already */
+       /* if error occurred and interface exists already */
        if (ret == -ENFILE && if_nametoindex(ifname)) {
                wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
 
@@ -3106,7 +5592,7 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
                                                wds);
        }
 
-       if (ret >= 0 && drv->disable_11b_rates)
+       if (ret >= 0 && is_p2p_interface(iftype))
                nl80211_disable_11b_rates(drv, ret, 1);
 
        return ret;
@@ -3136,10 +5622,20 @@ static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
 static void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
                             u8 *buf, size_t len)
 {
+       struct ieee80211_hdr *hdr = (void *)buf;
+       u16 fc;
        union wpa_event_data event;
+
+       if (len < sizeof(*hdr))
+               return;
+
+       fc = le_to_host16(hdr->frame_control);
+
        os_memset(&event, 0, sizeof(event));
-       event.rx_from_unknown.frame = buf;
-       event.rx_from_unknown.len = len;
+       event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
+       event.rx_from_unknown.addr = hdr->addr2;
+       event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) ==
+               (WLAN_FC_FROMDS | WLAN_FC_TODS);
        wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
 }
 
@@ -3191,12 +5687,6 @@ static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
                return;
        }
 
-       if (drv->nlmode == NL80211_IFTYPE_STATION && !drv->probe_req_report) {
-               wpa_printf(MSG_DEBUG, "nl80211: Ignore monitor interface "
-                          "frame since Probe Request reporting is disabled");
-               return;
-       }
-
        if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) {
                printf("received invalid radiotap frame\n");
                return;
@@ -3290,8 +5780,15 @@ static struct sock_filter msock_filter_insns[] = {
         * add a filter here that filters on our DA and that flag
         * to allow us to deauth frames to that bad station.
         *
-        * Not a regression -- we didn't do it before either.
+        * For now allow all To DS data frames through.
+        */
+       /* load the IEEE 802.11 frame control field */
+       BPF_STMT(BPF_LD  | BPF_H | BPF_IND, 0),
+       /* mask off frame type, version and DS status */
+       BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03),
+       /* accept frame if version 0, type 2 and To DS, fall through otherwise
         */
+       BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0),
 
 #if 0
        /*
@@ -3396,6 +5893,10 @@ static int add_monitor_filter(int s)
 static void nl80211_remove_monitor_interface(
        struct wpa_driver_nl80211_data *drv)
 {
+       drv->monitor_refcount--;
+       if (drv->monitor_refcount > 0)
+               return;
+
        if (drv->monitor_ifidx >= 0) {
                nl80211_remove_iface(drv, drv->monitor_ifidx);
                drv->monitor_ifidx = -1;
@@ -3416,17 +5917,46 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
        int optval;
        socklen_t optlen;
 
-       snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
+       if (drv->monitor_ifidx >= 0) {
+               drv->monitor_refcount++;
+               return 0;
+       }
+
+       if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) {
+               /*
+                * P2P interface name is of the format p2p-%s-%d. For monitor
+                * interface name corresponding to P2P GO, replace "p2p-" with
+                * "mon-" to retain the same interface name length and to
+                * indicate that it is a monitor interface.
+                */
+               snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss.ifname + 4);
+       } else {
+               /* Non-P2P interface with AP functionality. */
+               snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
+       }
+
        buf[IFNAMSIZ - 1] = '\0';
 
        drv->monitor_ifidx =
                nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
                                     0);
 
+       if (drv->monitor_ifidx == -EOPNOTSUPP) {
+               /*
+                * This is backward compatibility for a few versions of
+                * the kernel only that didn't advertise the right
+                * attributes for the only driver that then supported
+                * AP mode w/o monitor -- ath6kl.
+                */
+               wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
+                          "monitor interface type - try to run without it");
+               drv->device_ap_sme = 1;
+       }
+
        if (drv->monitor_ifidx < 0)
                return -1;
 
-       if (linux_set_iface_flags(drv->ioctl_sock, buf, 1))
+       if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1))
                goto error;
 
        memset(&ll, 0, sizeof(ll));
@@ -3470,58 +6000,128 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
 }
 
 
-static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
-
-static int wpa_driver_nl80211_hapd_send_eapol(
-       void *priv, const u8 *addr, const u8 *data,
-       size_t data_len, int encrypt, const u8 *own_addr)
+static int nl80211_setup_ap(struct i802_bss *bss)
 {
-       struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       struct ieee80211_hdr *hdr;
-       size_t len;
-       u8 *pos;
-       int res;
-#if 0 /* FIX */
-       int qos = sta->flags & WPA_STA_WMM;
-#else
-       int qos = 0;
-#endif
 
-       len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
-               data_len;
-       hdr = os_zalloc(len);
-       if (hdr == NULL) {
-               printf("malloc() failed for i802_send_data(len=%lu)\n",
-                      (unsigned long) len);
+       /*
+        * Disable Probe Request reporting unless we need it in this way for
+        * devices that include the AP SME, in the other case (unless using
+        * monitor iface) we'll get it through the nl_mgmt socket instead.
+        */
+       if (!drv->device_ap_sme)
+               wpa_driver_nl80211_probe_req_report(bss, 0);
+
+       if (!drv->device_ap_sme && !drv->use_monitor)
+               if (nl80211_mgmt_subscribe_ap(bss))
+                       return -1;
+
+       if (!drv->device_ap_sme && drv->use_monitor &&
+           nl80211_create_monitor_interface(drv) &&
+           !drv->device_ap_sme)
                return -1;
+
+       if (drv->device_ap_sme &&
+           wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
+               wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
+                          "Probe Request frame reporting in AP mode");
+               /* Try to survive without this */
        }
 
-       hdr->frame_control =
-               IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
+       return 0;
+}
+
+
+static void nl80211_teardown_ap(struct i802_bss *bss)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+
+       if (drv->device_ap_sme)
+               wpa_driver_nl80211_probe_req_report(bss, 0);
+       else if (drv->use_monitor)
+               nl80211_remove_monitor_interface(drv);
+       else
+               nl80211_mgmt_unsubscribe(bss);
+
+       bss->beacon_set = 0;
+}
+
+
+static int nl80211_send_eapol_data(struct i802_bss *bss,
+                                  const u8 *addr, const u8 *data,
+                                  size_t data_len)
+{
+       struct sockaddr_ll ll;
+       int ret;
+
+       if (bss->drv->eapol_tx_sock < 0) {
+               wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL");
+               return -1;
+       }
+
+       os_memset(&ll, 0, sizeof(ll));
+       ll.sll_family = AF_PACKET;
+       ll.sll_ifindex = bss->ifindex;
+       ll.sll_protocol = htons(ETH_P_PAE);
+       ll.sll_halen = ETH_ALEN;
+       os_memcpy(ll.sll_addr, addr, ETH_ALEN);
+       ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0,
+                    (struct sockaddr *) &ll, sizeof(ll));
+       if (ret < 0)
+               wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s",
+                          strerror(errno));
+
+       return ret;
+}
+
+
+static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+static int wpa_driver_nl80211_hapd_send_eapol(
+       void *priv, const u8 *addr, const u8 *data,
+       size_t data_len, int encrypt, const u8 *own_addr, u32 flags)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct ieee80211_hdr *hdr;
+       size_t len;
+       u8 *pos;
+       int res;
+       int qos = flags & WPA_STA_WMM;
+
+       if (drv->device_ap_sme || !drv->use_monitor)
+               return nl80211_send_eapol_data(bss, addr, data, data_len);
+
+       len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
+               data_len;
+       hdr = os_zalloc(len);
+       if (hdr == NULL) {
+               printf("malloc() failed for i802_send_data(len=%lu)\n",
+                      (unsigned long) len);
+               return -1;
+       }
+
+       hdr->frame_control =
+               IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
        hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
        if (encrypt)
                hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
-#if 0 /* To be enabled if qos determination is added above */
        if (qos) {
                hdr->frame_control |=
                        host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
        }
-#endif
 
        memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
        memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
        memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
        pos = (u8 *) (hdr + 1);
 
-#if 0 /* To be enabled if qos determination is added above */
        if (qos) {
                /* add an empty QoS header if needed */
                pos[0] = 0;
                pos[1] = 0;
                pos += 2;
        }
-#endif
 
        memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
        pos += sizeof(rfc1042_header);
@@ -3529,7 +6129,7 @@ static int wpa_driver_nl80211_hapd_send_eapol(
        pos += 2;
        memcpy(pos, data, data_len);
 
-       res = wpa_driver_nl80211_send_frame(drv, (u8 *) hdr, len, encrypt);
+       res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0);
        if (res < 0) {
                wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
                           "failed: %d (%s)",
@@ -3541,23 +6141,6 @@ static int wpa_driver_nl80211_hapd_send_eapol(
 }
 
 
-static u32 sta_flags_nl80211(int flags)
-{
-       u32 f = 0;
-
-       if (flags & WPA_STA_AUTHORIZED)
-               f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
-       if (flags & WPA_STA_WMM)
-               f |= BIT(NL80211_STA_FLAG_WME);
-       if (flags & WPA_STA_SHORT_PREAMBLE)
-               f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
-       if (flags & WPA_STA_MFP)
-               f |= BIT(NL80211_STA_FLAG_MFP);
-
-       return f;
-}
-
-
 static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
                                            int total_flags,
                                            int flags_or, int flags_and)
@@ -3577,8 +6160,7 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
                return -ENOMEM;
        }
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_SET_STATION, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
                    if_nametoindex(bss->ifname));
@@ -3600,6 +6182,9 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
        if (total_flags & WPA_STA_MFP)
                NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
 
+       if (total_flags & WPA_STA_TDLS_PEER)
+               NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER);
+
        if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
                goto nla_put_failure;
 
@@ -3612,6 +6197,7 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
 
        return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
+       nlmsg_free(msg);
        nlmsg_free(flags);
        return -ENOBUFS;
 }
@@ -3620,15 +6206,21 @@ 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)
 {
-       if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode) ||
-           wpa_driver_nl80211_set_freq(drv, params->freq, 0, 0)) {
+       enum nl80211_iftype nlmode;
+
+       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;
+
+       if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode) ||
+           wpa_driver_nl80211_set_freq(&drv->first_bss, params->freq, 0, 0)) {
                nl80211_remove_monitor_interface(drv);
                return -1;
        }
 
-       /* TODO: setup monitor interface (and add code somewhere to remove this
-        * when AP mode is stopped; associate with mode != 2 or drv_deinit) */
-
        return 0;
 }
 
@@ -3642,8 +6234,7 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
        if (!msg)
                return -1;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-                   NL80211_CMD_LEAVE_IBSS, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_LEAVE_IBSS);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
@@ -3671,7 +6262,8 @@ static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
 
        wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
 
-       if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode)) {
+       if (wpa_driver_nl80211_set_mode(&drv->first_bss,
+                                       NL80211_IFTYPE_ADHOC)) {
                wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
                           "IBSS mode");
                return -1;
@@ -3682,8 +6274,7 @@ retry:
        if (!msg)
                return -1;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-                   NL80211_CMD_JOIN_IBSS, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_JOIN_IBSS);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
        if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
@@ -3736,6 +6327,55 @@ 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(
        struct wpa_driver_nl80211_data *drv,
        struct wpa_driver_associate_params *params)
@@ -3743,14 +6383,14 @@ static int wpa_driver_nl80211_connect(
        struct nl_msg *msg;
        enum nl80211_auth_type type;
        int ret = 0;
+       int algs;
 
        msg = nlmsg_alloc();
        if (!msg)
                return -1;
 
        wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-                   NL80211_CMD_CONNECT, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
        if (params->bssid) {
@@ -3777,6 +6417,19 @@ static int wpa_driver_nl80211_connect(
                NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
                        params->wpa_ie);
 
+       algs = 0;
+       if (params->auth_alg & WPA_AUTH_ALG_OPEN)
+               algs++;
+       if (params->auth_alg & WPA_AUTH_ALG_SHARED)
+               algs++;
+       if (params->auth_alg & WPA_AUTH_ALG_LEAP)
+               algs++;
+       if (algs > 1) {
+               wpa_printf(MSG_DEBUG, "  * Leave out Auth Type for automatic "
+                          "selection");
+               goto skip_auth_type;
+       }
+
        if (params->auth_alg & WPA_AUTH_ALG_OPEN)
                type = NL80211_AUTHTYPE_OPEN_SYSTEM;
        else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
@@ -3791,15 +6444,16 @@ static int wpa_driver_nl80211_connect(
        wpa_printf(MSG_DEBUG, "  * Auth Type %d", type);
        NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
 
-       if (params->wpa_ie && params->wpa_ie_len) {
-               enum nl80211_wpa_versions ver;
+skip_auth_type:
+       if (params->wpa_proto) {
+               enum nl80211_wpa_versions ver = 0;
 
-               if (params->wpa_ie[0] == WLAN_EID_RSN)
-                       ver = NL80211_WPA_VERSION_2;
-               else
-                       ver = NL80211_WPA_VERSION_1;
+               if (params->wpa_proto & WPA_PROTO_WPA)
+                       ver |= NL80211_WPA_VERSION_1;
+               if (params->wpa_proto & WPA_PROTO_RSN)
+                       ver |= NL80211_WPA_VERSION_2;
 
-               wpa_printf(MSG_DEBUG, "  * WPA Version %d", ver);
+               wpa_printf(MSG_DEBUG, "  * WPA Versions 0x%x", ver);
                NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
        }
 
@@ -3870,6 +6524,14 @@ static int wpa_driver_nl80211_connect(
        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;
@@ -3897,7 +6559,10 @@ static int wpa_driver_nl80211_associate(
                return wpa_driver_nl80211_ibss(drv, params);
 
        if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
-               if (wpa_driver_nl80211_set_mode(priv, params->mode) < 0)
+               enum nl80211_iftype nlmode = params->p2p ?
+                       NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
+
+               if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
                        return -1;
                return wpa_driver_nl80211_connect(drv, params);
        }
@@ -3910,8 +6575,7 @@ static int wpa_driver_nl80211_associate(
 
        wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
                   drv->ifindex);
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-                   NL80211_CMD_ASSOCIATE, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
        if (params->bssid) {
@@ -3940,6 +6604,50 @@ static int wpa_driver_nl80211_associate(
                NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
                        params->wpa_ie);
 
+       if (params->pairwise_suite != CIPHER_NONE) {
+               int cipher;
+
+               switch (params->pairwise_suite) {
+               case CIPHER_WEP40:
+                       cipher = WLAN_CIPHER_SUITE_WEP40;
+                       break;
+               case CIPHER_WEP104:
+                       cipher = WLAN_CIPHER_SUITE_WEP104;
+                       break;
+               case CIPHER_CCMP:
+                       cipher = WLAN_CIPHER_SUITE_CCMP;
+                       break;
+               case CIPHER_TKIP:
+               default:
+                       cipher = WLAN_CIPHER_SUITE_TKIP;
+                       break;
+               }
+               wpa_printf(MSG_DEBUG, "  * pairwise=0x%x", cipher);
+               NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
+       }
+
+       if (params->group_suite != CIPHER_NONE) {
+               int cipher;
+
+               switch (params->group_suite) {
+               case CIPHER_WEP40:
+                       cipher = WLAN_CIPHER_SUITE_WEP40;
+                       break;
+               case CIPHER_WEP104:
+                       cipher = WLAN_CIPHER_SUITE_WEP104;
+                       break;
+               case CIPHER_CCMP:
+                       cipher = WLAN_CIPHER_SUITE_CCMP;
+                       break;
+               case CIPHER_TKIP:
+               default:
+                       cipher = WLAN_CIPHER_SUITE_TKIP;
+                       break;
+               }
+               wpa_printf(MSG_DEBUG, "  * group=0x%x", cipher);
+               NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
+       }
+
 #ifdef CONFIG_IEEE80211W
        if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
                NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
@@ -3954,11 +6662,15 @@ static int wpa_driver_nl80211_associate(
                        params->prev_bssid);
        }
 
+       if (params->p2p)
+               wpa_printf(MSG_DEBUG, "  * P2P group");
+
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
        if (ret) {
-               wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
-                          "(%s)", ret, strerror(-ret));
+               wpa_dbg(drv->ctx, MSG_DEBUG,
+                       "nl80211: MLME command failed (assoc): ret=%d (%s)",
+                       ret, strerror(-ret));
                nl80211_dump_scan(drv);
                goto nla_put_failure;
        }
@@ -3973,57 +6685,53 @@ nla_put_failure:
 
 
 static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
-                           int ifindex, int mode)
+                           int ifindex, enum nl80211_iftype mode)
 {
        struct nl_msg *msg;
        int ret = -ENOBUFS;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)",
+                  ifindex, mode, nl80211_iftype_str(mode));
+
        msg = nlmsg_alloc();
        if (!msg)
                return -ENOMEM;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_SET_INTERFACE, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
        NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
        if (!ret)
                return 0;
 nla_put_failure:
+       nlmsg_free(msg);
        wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
                   " %d (%s)", ifindex, mode, ret, strerror(-ret));
        return ret;
 }
 
 
-static int wpa_driver_nl80211_set_mode(void *priv, int mode)
+static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
+                                      enum nl80211_iftype nlmode)
 {
-       struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int ret = -1;
-       int nlmode;
-
-       switch (mode) {
-       case 0:
-               nlmode = NL80211_IFTYPE_STATION;
-               break;
-       case 1:
-               nlmode = NL80211_IFTYPE_ADHOC;
-               break;
-       case 2:
-               nlmode = NL80211_IFTYPE_AP;
-               break;
-       default:
-               return -1;
-       }
+       int i;
+       int was_ap = is_ap_interface(drv->nlmode);
+       int res;
 
-       if (nl80211_set_mode(drv, drv->ifindex, nlmode) == 0) {
+       res = nl80211_set_mode(drv, drv->ifindex, nlmode);
+       if (res == 0) {
                drv->nlmode = nlmode;
                ret = 0;
                goto done;
        }
 
+       if (res == -ENODEV)
+               return -1;
+
        if (nlmode == drv->nlmode) {
                wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
                           "requested mode - ignore error");
@@ -4035,36 +6743,63 @@ static int wpa_driver_nl80211_set_mode(void *priv, int mode)
         * take the device down, try to set the mode again, and bring the
         * device back up.
         */
-       if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0) == 0) {
-               /* Try to set the mode again while the interface is down */
-               ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
-               if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1))
-                       ret = -1;
+       wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
+                  "interface down");
+       for (i = 0; i < 10; i++) {
+               res = linux_set_iface_flags(drv->global->ioctl_sock,
+                                           bss->ifname, 0);
+               if (res == -EACCES || res == -ENODEV)
+                       break;
+               if (res == 0) {
+                       /* Try to set the mode again while the interface is
+                        * down */
+                       ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
+                       if (ret == -EACCES)
+                               break;
+                       res = linux_set_iface_flags(drv->global->ioctl_sock,
+                                                   bss->ifname, 1);
+                       if (res && !ret)
+                               ret = -1;
+                       else if (ret != -EBUSY)
+                               break;
+               } else
+                       wpa_printf(MSG_DEBUG, "nl80211: Failed to set "
+                                  "interface down");
+               os_sleep(0, 100000);
        }
 
        if (!ret) {
                wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
                           "interface is down");
                drv->nlmode = nlmode;
+               drv->ignore_if_down_event = 1;
        }
 
 done:
-       if (!ret && nlmode == NL80211_IFTYPE_AP) {
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
+                          "from %d failed", nlmode, drv->nlmode);
+               return ret;
+       }
+
+       if (is_ap_interface(nlmode)) {
+               nl80211_mgmt_unsubscribe(bss);
                /* Setup additional AP mode functionality if needed */
-               if (drv->monitor_ifidx < 0 &&
-                   nl80211_create_monitor_interface(drv))
+               if (nl80211_setup_ap(bss))
                        return -1;
-       } else if (!ret && nlmode != NL80211_IFTYPE_AP) {
+       } else if (was_ap) {
                /* Remove additional AP mode functionality */
-               nl80211_remove_monitor_interface(drv);
-               bss->beacon_set = 0;
+               nl80211_teardown_ap(bss);
+       } else {
+               nl80211_mgmt_unsubscribe(bss);
        }
 
-       if (ret)
-               wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
-                          "from %d failed", nlmode, drv->nlmode);
+       if (!is_ap_interface(nlmode) &&
+           nl80211_mgmt_subscribe_non_ap(bss) < 0)
+               wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
+                          "frame processing - ignore for now");
 
-       return ret;
+       return 0;
 }
 
 
@@ -4088,7 +6823,7 @@ static int wpa_driver_nl80211_set_operstate(void *priv, int state)
        wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
                   __func__, drv->operstate, state, state ? "UP" : "DORMANT");
        drv->operstate = state;
-       return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1,
+       return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1,
                                      state ? IF_OPER_UP : IF_OPER_DORMANT);
 }
 
@@ -4104,8 +6839,7 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
        if (!msg)
                return -ENOMEM;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_SET_STATION, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
                    if_nametoindex(bss->ifname));
@@ -4119,90 +6853,37 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
 
        return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
 
-#ifdef HOSTAPD
-
-static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+/* Set kernel driver on given frequency (MHz) */
+static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
 {
-       int i;
-       int *old;
+       struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_set_freq(bss, freq->freq, freq->ht_enabled,
+                                          freq->sec_channel_offset);
+}
 
-       wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
-                  ifidx);
-       for (i = 0; i < drv->num_if_indices; i++) {
-               if (drv->if_indices[i] == 0) {
-                       drv->if_indices[i] = ifidx;
-                       return;
-               }
-       }
 
-       if (drv->if_indices != drv->default_if_indices)
-               old = drv->if_indices;
-       else
-               old = NULL;
+#if defined(HOSTAPD) || defined(CONFIG_AP)
 
-       drv->if_indices = os_realloc(old,
-                                    sizeof(int) * (drv->num_if_indices + 1));
-       if (!drv->if_indices) {
-               if (!old)
-                       drv->if_indices = drv->default_if_indices;
-               else
-                       drv->if_indices = old;
-               wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
-                          "interfaces");
-               wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
-               return;
-       } else if (!old)
-               os_memcpy(drv->if_indices, drv->default_if_indices,
-                         sizeof(drv->default_if_indices));
-       drv->if_indices[drv->num_if_indices] = ifidx;
-       drv->num_if_indices++;
+static inline int min_int(int a, int b)
+{
+       if (a < b)
+               return a;
+       return b;
 }
 
 
-static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+static int get_key_handler(struct nl_msg *msg, void *arg)
 {
-       int i;
-
-       for (i = 0; i < drv->num_if_indices; i++) {
-               if (drv->if_indices[i] == ifidx) {
-                       drv->if_indices[i] = 0;
-                       break;
-               }
-       }
-}
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
 
-
-static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-       int i;
-
-       for (i = 0; i < drv->num_if_indices; i++)
-               if (drv->if_indices[i] == ifidx)
-                       return 1;
-
-       return 0;
-}
-
-
-static inline int min_int(int a, int b)
-{
-       if (a < b)
-               return a;
-       return b;
-}
-
-
-static int get_key_handler(struct nl_msg *msg, void *arg)
-{
-       struct nlattr *tb[NL80211_ATTR_MAX + 1];
-       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-
-       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-                 genlmsg_attrlen(gnlh, 0), NULL);
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
 
        /*
         * TODO: validate the key index and mac address!
@@ -4228,8 +6909,7 @@ static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
        if (!msg)
                return -ENOMEM;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_GET_KEY, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_KEY);
 
        if (addr)
                NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
@@ -4240,54 +6920,11 @@ static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
 
        return send_and_recv_msgs(drv, msg, get_key_handler, seq);
  nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
 
-static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates,
-                             int mode)
-{
-       struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       struct nl_msg *msg;
-       u8 rates[NL80211_MAX_SUPP_RATES];
-       u8 rates_len = 0;
-       int i;
-
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
-
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-                   NL80211_CMD_SET_BSS, 0);
-
-       for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)
-               rates[rates_len++] = basic_rates[i] / 5;
-
-       NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
-
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
-       return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
-       return -ENOBUFS;
-}
-
-#endif /* HOSTAPD */
-
-
-/* Set kernel driver on given frequency (MHz) */
-static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
-{
-       struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       return wpa_driver_nl80211_set_freq(drv, freq->freq, freq->ht_enabled,
-                                          freq->sec_channel_offset);
-}
-
-
-#ifdef HOSTAPD
-
 static int i802_set_rts(void *priv, int rts)
 {
        struct i802_bss *bss = priv;
@@ -4305,15 +6942,16 @@ static int i802_set_rts(void *priv, int rts)
        else
                val = rts;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_SET_WIPHY, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
        if (!ret)
                return 0;
 nla_put_failure:
+       nlmsg_free(msg);
        wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
                   "%d (%s)", rts, ret, strerror(-ret));
        return ret;
@@ -4337,15 +6975,16 @@ static int i802_set_frag(void *priv, int frag)
        else
                val = frag;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_SET_WIPHY, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
        if (!ret)
                return 0;
 nla_put_failure:
+       nlmsg_free(msg);
        wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
                   "%d: %d (%s)", frag, ret, strerror(-ret));
        return ret;
@@ -4362,8 +7001,7 @@ static int i802_flush(void *priv)
        if (!msg)
                return -1;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_DEL_STATION, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
 
        /*
         * XXX: FIX! this needs to flush all VLANs too
@@ -4373,6 +7011,7 @@ static int i802_flush(void *priv)
 
        return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
@@ -4440,14 +7079,14 @@ static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
        if (!msg)
                return -ENOMEM;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_GET_STATION, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
 
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
 
        return send_and_recv_msgs(drv, msg, get_sta_handler, data);
  nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
@@ -4464,8 +7103,7 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
        if (!msg)
                return -1;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_SET_WIPHY, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
 
@@ -4478,7 +7116,20 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
        if (!params)
                goto nla_put_failure;
 
-       NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, queue);
+       switch (queue) {
+       case 0:
+               NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO);
+               break;
+       case 1:
+               NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI);
+               break;
+       case 2:
+               NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE);
+               break;
+       case 3:
+               NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK);
+               break;
+       }
        /* Burst time is configured in units of 0.1 msec and TXOP parameter in
         * 32 usec, so need to convert the value here. */
        NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, (burst_time * 100 + 16) / 32);
@@ -4492,57 +7143,13 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
 
        if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
                return 0;
+       msg = NULL;
  nla_put_failure:
+       nlmsg_free(msg);
        return -1;
 }
 
 
-static int i802_set_bss(void *priv, int cts, int preamble, int slot)
-{
-       struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       struct nl_msg *msg;
-
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
-
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-                   NL80211_CMD_SET_BSS, 0);
-
-       if (cts >= 0)
-               NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts);
-       if (preamble >= 0)
-               NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble);
-       if (slot >= 0)
-               NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
-
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
-       return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
-       return -ENOBUFS;
-}
-
-
-static int i802_set_cts_protect(void *priv, int value)
-{
-       return i802_set_bss(priv, value, -1, -1);
-}
-
-
-static int i802_set_preamble(void *priv, int value)
-{
-       return i802_set_bss(priv, -1, value, -1);
-}
-
-
-static int i802_set_short_slot_time(void *priv, int value)
-{
-       return i802_set_bss(priv, -1, -1, value);
-}
-
-
 static int i802_set_sta_vlan(void *priv, const u8 *addr,
                             const char *ifname, int vlan_id)
 {
@@ -4555,8 +7162,7 @@ static int i802_set_sta_vlan(void *priv, const u8 *addr,
        if (!msg)
                return -ENOMEM;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_SET_STATION, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
                    if_nametoindex(bss->ifname));
@@ -4565,6 +7171,7 @@ static int i802_set_sta_vlan(void *priv, const u8 *addr,
                    if_nametoindex(ifname));
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
        if (ret < 0) {
                wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
                           MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
@@ -4572,53 +7179,11 @@ static int i802_set_sta_vlan(void *priv, const u8 *addr,
                           strerror(-ret));
        }
  nla_put_failure:
+       nlmsg_free(msg);
        return ret;
 }
 
 
-static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val)
-{
-       struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       char name[IFNAMSIZ + 1];
-
-       os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
-       wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
-                  " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
-       if (val) {
-               if (nl80211_create_iface(drv, name, NL80211_IFTYPE_AP_VLAN,
-                                        NULL, 1) < 0)
-                       return -1;
-               linux_set_iface_flags(drv->ioctl_sock, name, 1);
-               return i802_set_sta_vlan(priv, addr, name, 0);
-       } else {
-               i802_set_sta_vlan(priv, addr, bss->ifname, 0);
-               return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
-                                                   name);
-       }
-}
-
-
-static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
-{
-       struct wpa_driver_nl80211_data *drv = eloop_ctx;
-       struct sockaddr_ll lladdr;
-       unsigned char buf[3000];
-       int len;
-       socklen_t fromlen = sizeof(lladdr);
-
-       len = recvfrom(sock, buf, sizeof(buf), 0,
-                      (struct sockaddr *)&lladdr, &fromlen);
-       if (len < 0) {
-               perror("recv");
-               return;
-       }
-
-       if (have_ifidx(drv, lladdr.sll_ifindex))
-               drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
-}
-
-
 static int i802_get_inact_sec(void *priv, const u8 *addr)
 {
        struct hostap_sta_driver_data data;
@@ -4656,7 +7221,7 @@ 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));
+                                           sizeof(mgmt.u.deauth), 0);
 }
 
 
@@ -4675,78 +7240,201 @@ 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));
+                                           sizeof(mgmt.u.disassoc), 0);
 }
 
+#endif /* HOSTAPD || CONFIG_AP */
 
-static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
-                            const char *brname, const char *ifname)
+#ifdef HOSTAPD
+
+static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
 {
-       int ifindex;
-       char in_br[IFNAMSIZ];
+       int i;
+       int *old;
 
-       os_strlcpy(drv->brname, brname, IFNAMSIZ);
-       ifindex = if_nametoindex(brname);
-       if (ifindex == 0) {
-               /*
-                * Bridge was configured, but the bridge device does
-                * not exist. Try to add it now.
-                */
-               if (linux_br_add(drv->ioctl_sock, brname) < 0) {
-                       wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
-                                  "bridge interface %s: %s",
-                                  brname, strerror(errno));
-                       return -1;
+       wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
+                  ifidx);
+       for (i = 0; i < drv->num_if_indices; i++) {
+               if (drv->if_indices[i] == 0) {
+                       drv->if_indices[i] = ifidx;
+                       return;
                }
-               drv->added_bridge = 1;
-               add_ifidx(drv, if_nametoindex(brname));
        }
 
-       if (linux_br_get(in_br, ifname) == 0) {
-               if (os_strcmp(in_br, brname) == 0)
-                       return 0; /* already in the bridge */
+       if (drv->if_indices != drv->default_if_indices)
+               old = drv->if_indices;
+       else
+               old = NULL;
 
-               wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
-                          "bridge %s", ifname, in_br);
-               if (linux_br_del_if(drv->ioctl_sock, in_br, ifname) < 0) {
-                       wpa_printf(MSG_ERROR, "nl80211: Failed to "
-                                  "remove interface %s from bridge "
-                                  "%s: %s",
-                                  ifname, brname, strerror(errno));
-                       return -1;
+       drv->if_indices = os_realloc(old,
+                                    sizeof(int) * (drv->num_if_indices + 1));
+       if (!drv->if_indices) {
+               if (!old)
+                       drv->if_indices = drv->default_if_indices;
+               else
+                       drv->if_indices = old;
+               wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
+                          "interfaces");
+               wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
+               return;
+       } else if (!old)
+               os_memcpy(drv->if_indices, drv->default_if_indices,
+                         sizeof(drv->default_if_indices));
+       drv->if_indices[drv->num_if_indices] = ifidx;
+       drv->num_if_indices++;
+}
+
+
+static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+       int i;
+
+       for (i = 0; i < drv->num_if_indices; i++) {
+               if (drv->if_indices[i] == ifidx) {
+                       drv->if_indices[i] = 0;
+                       break;
                }
        }
+}
 
-       wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
-                  ifname, brname);
-       if (linux_br_add_if(drv->ioctl_sock, brname, ifname) < 0) {
-               wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s "
-                          "into bridge %s: %s",
-                          ifname, brname, strerror(errno));
-               return -1;
-       }
-       drv->added_if_into_bridge = 1;
+
+static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+       int i;
+
+       for (i = 0; i < drv->num_if_indices; i++)
+               if (drv->if_indices[i] == ifidx)
+                       return 1;
 
        return 0;
 }
 
 
-static void *i802_init(struct hostapd_data *hapd,
-                      struct wpa_init_params *params)
+static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
+                            const char *bridge_ifname)
 {
-       struct wpa_driver_nl80211_data *drv;
-       struct i802_bss *bss;
-       size_t i;
-       char brname[IFNAMSIZ];
-       int ifindex, br_ifindex;
-       int br_added = 0;
-
-       bss = wpa_driver_nl80211_init(hapd, params->ifname);
-       if (bss == NULL)
-               return NULL;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       char name[IFNAMSIZ + 1];
 
-       drv = bss->drv;
-       if (linux_br_get(brname, params->ifname) == 0) {
+       os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
+       wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
+                  " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
+       if (val) {
+               if (!if_nametoindex(name)) {
+                       if (nl80211_create_iface(drv, name,
+                                                NL80211_IFTYPE_AP_VLAN,
+                                                NULL, 1) < 0)
+                               return -1;
+                       if (bridge_ifname &&
+                           linux_br_add_if(drv->global->ioctl_sock,
+                                           bridge_ifname, name) < 0)
+                               return -1;
+               }
+               linux_set_iface_flags(drv->global->ioctl_sock, name, 1);
+               return i802_set_sta_vlan(priv, addr, name, 0);
+       } else {
+               i802_set_sta_vlan(priv, addr, bss->ifname, 0);
+               return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
+                                                   name);
+       }
+}
+
+
+static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
+{
+       struct wpa_driver_nl80211_data *drv = eloop_ctx;
+       struct sockaddr_ll lladdr;
+       unsigned char buf[3000];
+       int len;
+       socklen_t fromlen = sizeof(lladdr);
+
+       len = recvfrom(sock, buf, sizeof(buf), 0,
+                      (struct sockaddr *)&lladdr, &fromlen);
+       if (len < 0) {
+               perror("recv");
+               return;
+       }
+
+       if (have_ifidx(drv, lladdr.sll_ifindex))
+               drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
+}
+
+
+static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
+                            struct i802_bss *bss,
+                            const char *brname, const char *ifname)
+{
+       int ifindex;
+       char in_br[IFNAMSIZ];
+
+       os_strlcpy(bss->brname, brname, IFNAMSIZ);
+       ifindex = if_nametoindex(brname);
+       if (ifindex == 0) {
+               /*
+                * Bridge was configured, but the bridge device does
+                * not exist. Try to add it now.
+                */
+               if (linux_br_add(drv->global->ioctl_sock, brname) < 0) {
+                       wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
+                                  "bridge interface %s: %s",
+                                  brname, strerror(errno));
+                       return -1;
+               }
+               bss->added_bridge = 1;
+               add_ifidx(drv, if_nametoindex(brname));
+       }
+
+       if (linux_br_get(in_br, ifname) == 0) {
+               if (os_strcmp(in_br, brname) == 0)
+                       return 0; /* already in the bridge */
+
+               wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
+                          "bridge %s", ifname, in_br);
+               if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) <
+                   0) {
+                       wpa_printf(MSG_ERROR, "nl80211: Failed to "
+                                  "remove interface %s from bridge "
+                                  "%s: %s",
+                                  ifname, brname, strerror(errno));
+                       return -1;
+               }
+       }
+
+       wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
+                  ifname, brname);
+       if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) {
+               wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s "
+                          "into bridge %s: %s",
+                          ifname, brname, strerror(errno));
+               return -1;
+       }
+       bss->added_if_into_bridge = 1;
+
+       return 0;
+}
+
+
+static void *i802_init(struct hostapd_data *hapd,
+                      struct wpa_init_params *params)
+{
+       struct wpa_driver_nl80211_data *drv;
+       struct i802_bss *bss;
+       size_t i;
+       char brname[IFNAMSIZ];
+       int ifindex, br_ifindex;
+       int br_added = 0;
+
+       bss = wpa_driver_nl80211_init(hapd, params->ifname,
+                                     params->global_priv);
+       if (bss == NULL)
+               return NULL;
+
+       drv = bss->drv;
+       drv->nlmode = NL80211_IFTYPE_AP;
+       drv->eapol_sock = -1;
+
+       if (linux_br_get(brname, params->ifname) == 0) {
                wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
                           params->ifname, brname);
                br_ifindex = if_nametoindex(brname);
@@ -4773,26 +7461,26 @@ static void *i802_init(struct hostapd_data *hapd,
        /* start listening for EAPOL on the default AP interface */
        add_ifidx(drv, drv->ifindex);
 
-       if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0))
+       if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0))
                goto failed;
 
        if (params->bssid) {
-               if (linux_set_ifhwaddr(drv->ioctl_sock, bss->ifname,
+               if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
                                       params->bssid))
                        goto failed;
        }
 
-       if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_AP)) {
+       if (wpa_driver_nl80211_set_mode(bss, drv->nlmode)) {
                wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
                           "into AP mode", bss->ifname);
                goto failed;
        }
 
        if (params->num_bridge && params->bridge[0] &&
-           i802_check_bridge(drv, params->bridge[0], params->ifname) < 0)
+           i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
                goto failed;
 
-       if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1))
+       if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1))
                goto failed;
 
        drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
@@ -4807,22 +7495,16 @@ static void *i802_init(struct hostapd_data *hapd,
                goto failed;
        }
 
-       if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, params->own_addr))
+       if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+                              params->own_addr))
                goto failed;
 
+       memcpy(bss->addr, params->own_addr, ETH_ALEN);
+
        return bss;
 
 failed:
-       nl80211_remove_monitor_interface(drv);
-       if (drv->ioctl_sock >= 0)
-               close(drv->ioctl_sock);
-
-       genl_family_put(drv->nl80211);
-       nl_cache_free(drv->nl_cache);
-       nl_handle_destroy(drv->nl_handle);
-       nl_cb_put(drv->nl_cb);
-
-       os_free(drv);
+       wpa_driver_nl80211_deinit(bss);
        return NULL;
 }
 
@@ -4841,19 +7523,66 @@ static enum nl80211_iftype wpa_driver_nl80211_if_type(
        switch (type) {
        case WPA_IF_STATION:
                return NL80211_IFTYPE_STATION;
+       case WPA_IF_P2P_CLIENT:
+       case WPA_IF_P2P_GROUP:
+               return NL80211_IFTYPE_P2P_CLIENT;
        case WPA_IF_AP_VLAN:
                return NL80211_IFTYPE_AP_VLAN;
        case WPA_IF_AP_BSS:
                return NL80211_IFTYPE_AP;
+       case WPA_IF_P2P_GO:
+               return NL80211_IFTYPE_P2P_GO;
        }
        return -1;
 }
 
 
+#ifdef CONFIG_P2P
+
+static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
+{
+       struct wpa_driver_nl80211_data *drv;
+       dl_list_for_each(drv, &global->interfaces,
+                        struct wpa_driver_nl80211_data, list) {
+               if (os_memcmp(addr, drv->first_bss.addr, ETH_ALEN) == 0)
+                       return 1;
+       }
+       return 0;
+}
+
+
+static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
+                                     u8 *new_addr)
+{
+       unsigned int idx;
+
+       if (!drv->global)
+               return -1;
+
+       os_memcpy(new_addr, drv->first_bss.addr, ETH_ALEN);
+       for (idx = 0; idx < 64; idx++) {
+               new_addr[0] = drv->first_bss.addr[0] | 0x02;
+               new_addr[0] ^= idx << 2;
+               if (!nl80211_addr_in_use(drv->global, new_addr))
+                       break;
+       }
+       if (idx == 64)
+               return -1;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Assigned new P2P Interface Address "
+                  MACSTR, MAC2STR(new_addr));
+
+       return 0;
+}
+
+#endif /* CONFIG_P2P */
+
+
 static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                                     const char *ifname, const u8 *addr,
                                     void *bss_ctx, void **drv_priv,
-                                    char *force_ifname, u8 *if_addr)
+                                    char *force_ifname, u8 *if_addr,
+                                    const char *bridge)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -4881,26 +7610,75 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
        }
 
        if (!addr &&
-           linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, if_addr) < 0)
+           linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+                              if_addr) < 0) {
+               nl80211_remove_iface(drv, ifidx);
                return -1;
+       }
+
+#ifdef CONFIG_P2P
+       if (!addr &&
+           (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
+            type == WPA_IF_P2P_GO)) {
+               /* Enforce unique P2P Interface Address */
+               u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN];
+
+               if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+                                      own_addr) < 0 ||
+                   linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
+                                      new_addr) < 0) {
+                       nl80211_remove_iface(drv, ifidx);
+                       return -1;
+               }
+               if (os_memcmp(own_addr, new_addr, ETH_ALEN) == 0) {
+                       wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
+                                  "for P2P group interface");
+                       if (nl80211_p2p_interface_addr(drv, new_addr) < 0) {
+                               nl80211_remove_iface(drv, ifidx);
+                               return -1;
+                       }
+                       if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
+                                              new_addr) < 0) {
+                               nl80211_remove_iface(drv, ifidx);
+                               return -1;
+                       }
+               }
+               os_memcpy(if_addr, new_addr, ETH_ALEN);
+       }
+#endif /* CONFIG_P2P */
 
 #ifdef HOSTAPD
+       if (bridge &&
+           i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
+               wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
+                          "interface %s to a bridge %s", ifname, bridge);
+               nl80211_remove_iface(drv, ifidx);
+               os_free(new_bss);
+               return -1;
+       }
+
        if (type == WPA_IF_AP_BSS) {
-               if (linux_set_iface_flags(drv->ioctl_sock, ifname, 1)) {
+               if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
+               {
                        nl80211_remove_iface(drv, ifidx);
                        os_free(new_bss);
                        return -1;
                }
                os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
+               os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
                new_bss->ifindex = ifidx;
                new_bss->drv = drv;
                new_bss->next = drv->first_bss.next;
                drv->first_bss.next = new_bss;
                if (drv_priv)
                        *drv_priv = new_bss;
+               nl80211_init_bss(new_bss);
        }
 #endif /* HOSTAPD */
 
+       if (drv->global)
+               drv->global->if_add_ifindex = ifidx;
+
        return 0;
 }
 
@@ -4917,6 +7695,23 @@ static int wpa_driver_nl80211_if_remove(void *priv,
                   __func__, type, ifname, ifindex);
        if (ifindex <= 0)
                return -1;
+
+#ifdef HOSTAPD
+       if (bss->added_if_into_bridge) {
+               if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
+                                   bss->ifname) < 0)
+                       wpa_printf(MSG_INFO, "nl80211: Failed to remove "
+                                  "interface %s from bridge %s: %s",
+                                  bss->ifname, bss->brname, strerror(errno));
+       }
+       if (bss->added_bridge) {
+               if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
+                       wpa_printf(MSG_INFO, "nl80211: Failed to remove "
+                                  "bridge %s: %s",
+                                  bss->brname, strerror(errno));
+       }
+#endif /* HOSTAPD */
+
        nl80211_remove_iface(drv, ifindex);
 
 #ifdef HOSTAPD
@@ -4924,16 +7719,20 @@ static int wpa_driver_nl80211_if_remove(void *priv,
                return 0;
 
        if (bss != &drv->first_bss) {
-               struct i802_bss *tbss = &drv->first_bss;
-
-               while (tbss) {
-                       if (tbss->next != bss)
-                               continue;
-
-                       tbss->next = bss->next;
-                       os_free(bss);
-                       break;
+               struct i802_bss *tbss;
+
+               for (tbss = &drv->first_bss; tbss; tbss = tbss->next) {
+                       if (tbss->next == bss) {
+                               tbss->next = bss->next;
+                               nl80211_destroy_bss(bss);
+                               os_free(bss);
+                               bss = NULL;
+                               break;
+                       }
                }
+               if (bss)
+                       wpa_printf(MSG_INFO, "nl80211: %s - could not find "
+                                  "BSS %p in the list", __func__, bss);
        }
 #endif /* HOSTAPD */
 
@@ -4954,21 +7753,73 @@ static int cookie_handler(struct nl_msg *msg, void *arg)
 }
 
 
+static int nl80211_send_frame_cmd(struct i802_bss *bss,
+                                 unsigned int freq, unsigned int wait,
+                                 const u8 *buf, size_t buf_len,
+                                 u64 *cookie_out, int no_cck, int no_ack,
+                                 int offchanok)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       u64 cookie;
+       int ret = -1;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -1;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+       if (wait)
+               NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
+       if (offchanok)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
+       if (no_cck)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
+       if (no_ack)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK);
+
+       NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf);
+
+       cookie = 0;
+       ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
+       msg = NULL;
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
+                          "(%s) (freq=%u wait=%u)", ret, strerror(-ret),
+                          freq, wait);
+               goto nla_put_failure;
+       }
+       wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted%s; "
+                  "cookie 0x%llx", no_ack ? " (no ACK)" : "",
+                  (long long unsigned int) cookie);
+
+       if (cookie_out)
+               *cookie_out = no_ack ? (u64) -1 : cookie;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return ret;
+}
+
+
 static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
+                                         unsigned int wait_time,
                                          const u8 *dst, const u8 *src,
                                          const u8 *bssid,
-                                         const u8 *data, size_t data_len)
+                                         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;
-       struct nl_msg *msg;
        u8 *buf;
        struct ieee80211_hdr *hdr;
-       u64 cookie;
 
-       wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d)",
-                  drv->ifindex);
+       wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
+                  "wait=%d ms no_cck=%d)", drv->ifindex, wait_time, no_cck);
 
        buf = os_zalloc(24 + data_len);
        if (buf == NULL)
@@ -4981,44 +7832,44 @@ static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
        os_memcpy(hdr->addr2, src, ETH_ALEN);
        os_memcpy(hdr->addr3, bssid, ETH_ALEN);
 
-       if (drv->nlmode == NL80211_IFTYPE_AP) {
-               ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len);
-               os_free(buf);
-               return ret;
-       }
+       if (is_ap_interface(drv->nlmode))
+               ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len,
+                                                  0);
+       else
+               ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
+                                            24 + data_len,
+                                            &drv->send_action_cookie,
+                                            no_cck, 0, 1);
+
+       os_free(buf);
+       return ret;
+}
+
+
+static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret;
 
        msg = nlmsg_alloc();
-       if (!msg) {
-               os_free(buf);
-               return -1;
-       }
+       if (!msg)
+               return;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-                   NL80211_CMD_ACTION, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
-       NLA_PUT(msg, NL80211_ATTR_FRAME, 24 + data_len, buf);
-       os_free(buf);
-       buf = NULL;
+       NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
 
-       cookie = 0;
-       ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
-       if (ret) {
-               wpa_printf(MSG_DEBUG, "nl80211: Action command failed: ret=%d "
+       if (ret)
+               wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
                           "(%s)", ret, strerror(-ret));
-               goto nla_put_failure;
-       }
-       wpa_printf(MSG_DEBUG, "nl80211: Action TX command accepted; "
-                  "cookie 0x%llx", (long long unsigned int) cookie);
-       drv->send_action_cookie = cookie;
-       ret = 0;
 
-nla_put_failure:
-       os_free(buf);
+ nla_put_failure:
        nlmsg_free(msg);
-       return ret;
 }
 
 
@@ -5035,8 +7886,7 @@ static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
        if (!msg)
                return -1;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-                   NL80211_CMD_REMAIN_ON_CHANNEL, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
@@ -5044,16 +7894,20 @@ static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
 
        cookie = 0;
        ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
+       msg = NULL;
        if (ret == 0) {
                wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
                           "0x%llx for freq=%u MHz duration=%u",
                           (long long unsigned int) cookie, freq, duration);
                drv->remain_on_chan_cookie = cookie;
+               drv->pending_remain_on_chan = 1;
                return 0;
        }
        wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
-                  "(freq=%d): %d (%s)", freq, ret, strerror(-ret));
+                  "(freq=%d duration=%u): %d (%s)",
+                  freq, duration, ret, strerror(-ret));
 nla_put_failure:
+       nlmsg_free(msg);
        return -1;
 }
 
@@ -5079,76 +7933,62 @@ static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
        if (!msg)
                return -1;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-                   NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
        NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
        if (ret == 0)
                return 0;
        wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
                   "%d (%s)", ret, strerror(-ret));
 nla_put_failure:
+       nlmsg_free(msg);
        return -1;
 }
 
 
-static void wpa_driver_nl80211_probe_req_report_timeout(void *eloop_ctx,
-                                                       void *timeout_ctx)
-{
-       struct wpa_driver_nl80211_data *drv = eloop_ctx;
-       if (drv->monitor_ifidx < 0)
-               return; /* monitor interface already removed */
-
-       if (drv->nlmode != NL80211_IFTYPE_STATION)
-               return; /* not in station mode anymore */
-
-       if (drv->probe_req_report)
-               return; /* reporting enabled */
-
-       wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface due to no "
-                  "Probe Request reporting needed anymore");
-       nl80211_remove_monitor_interface(drv);
-}
-
-
 static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
 
-       if (drv->nlmode != NL80211_IFTYPE_STATION) {
-               wpa_printf(MSG_DEBUG, "nl80211: probe_req_report control only "
-                          "allowed in station mode (iftype=%d)",
-                          drv->nlmode);
-               return -1;
+       if (!report) {
+               if (bss->nl_preq) {
+                       eloop_unregister_read_sock(
+                               nl_socket_get_fd(bss->nl_preq));
+                       nl_destroy_handles(&bss->nl_preq);
+               }
+               return 0;
        }
-       drv->probe_req_report = report;
 
-       if (report) {
-               eloop_cancel_timeout(
-                       wpa_driver_nl80211_probe_req_report_timeout,
-                       drv, NULL);
-               if (drv->monitor_ifidx < 0 &&
-                   nl80211_create_monitor_interface(drv))
-                       return -1;
-       } else {
-               /*
-                * It takes a while to remove the monitor interface, so try to
-                * avoid doing this if it is needed again shortly. Instead,
-                * schedule the interface to be removed later if no need for it
-                * is seen.
-                */
-               wpa_printf(MSG_DEBUG, "nl80211: Scheduling monitor interface "
-                          "to be removed after 10 seconds of no use");
-               eloop_register_timeout(
-                       10, 0, wpa_driver_nl80211_probe_req_report_timeout,
-                       drv, NULL);
+       if (bss->nl_preq) {
+               wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
+                          "already on!");
+               return 0;
        }
 
+       bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq");
+       if (bss->nl_preq == NULL)
+               return -1;
+
+       if (nl80211_register_frame(bss, bss->nl_preq,
+                                  (WLAN_FC_TYPE_MGMT << 2) |
+                                  (WLAN_FC_STYPE_PROBE_REQ << 4),
+                                  NULL, 0) < 0)
+               goto out_err;
+
+       eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq),
+                                wpa_driver_nl80211_event_receive, bss->nl_cb,
+                                bss->nl_preq);
+
        return 0;
+
+ out_err:
+       nl_destroy_handles(&bss->nl_preq);
+       return -1;
 }
 
 
@@ -5163,8 +8003,7 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
        if (!msg)
                return -1;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-                   NL80211_CMD_SET_TX_BITRATE_MASK, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_TX_BITRATE_MASK);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
 
        bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
@@ -5179,8 +8018,10 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
        band = nla_nest_start(msg, NL80211_BAND_2GHZ);
        if (!band)
                goto nla_put_failure;
-       NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
-               "\x0c\x12\x18\x24\x30\x48\x60\x6c");
+       if (disabled) {
+               NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
+                       "\x0c\x12\x18\x24\x30\x48\x60\x6c");
+       }
        nla_nest_end(msg, band);
 
        nla_nest_end(msg, bands);
@@ -5200,23 +8041,14 @@ nla_put_failure:
 }
 
 
-static int wpa_driver_nl80211_disable_11b_rates(void *priv, int disabled)
+static int wpa_driver_nl80211_deinit_ap(void *priv)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       drv->disable_11b_rates = disabled;
-       return nl80211_disable_11b_rates(drv, drv->ifindex, disabled);
-}
-
-
-static int wpa_driver_nl80211_deinit_ap(void *priv)
-{
-       struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       if (drv->nlmode != NL80211_IFTYPE_AP)
-               return -1;
-       wpa_driver_nl80211_del_beacon(drv);
-       return wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA);
+       if (!is_ap_interface(drv->nlmode))
+               return -1;
+       wpa_driver_nl80211_del_beacon(drv);
+       return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
 }
 
 
@@ -5224,7 +8056,7 @@ static void wpa_driver_nl80211_resume(void *priv)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) {
+       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");
        }
@@ -5239,10 +8071,7 @@ static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
        int ret;
        u8 *data, *pos;
        size_t data_len;
-       u8 own_addr[ETH_ALEN];
-
-       if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr) < 0)
-               return -1;
+       const u8 *own_addr = bss->addr;
 
        if (action != 1) {
                wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action "
@@ -5272,9 +8101,9 @@ static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
        pos += ETH_ALEN;
        os_memcpy(pos, ies, ies_len);
 
-       ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, drv->bssid,
-                                            own_addr, drv->bssid,
-                                            data, data_len);
+       ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0,
+                                            drv->bssid, own_addr, drv->bssid,
+                                            data, data_len, 0);
        os_free(data);
 
        return ret;
@@ -5294,8 +8123,7 @@ static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
        if (!msg)
                return -1;
 
-       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-                   0, NL80211_CMD_SET_CQM, 0);
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_CQM);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
 
@@ -5312,22 +8140,585 @@ static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
        msg = NULL;
 
 nla_put_failure:
-       if (cqm)
-               nlmsg_free(cqm);
+       nlmsg_free(cqm);
        nlmsg_free(msg);
        return -1;
 }
 
 
+static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       int res;
+
+       os_memset(si, 0, sizeof(*si));
+       res = nl80211_get_link_signal(drv, si);
+       if (res != 0)
+               return res;
+
+       return nl80211_get_link_noise(drv, si);
+}
+
+
+static int wpa_driver_nl80211_shared_freq(void *priv)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct wpa_driver_nl80211_data *driver;
+       int freq = 0;
+
+       /*
+        * If the same PHY is in connected state with some other interface,
+        * then retrieve the assoc freq.
+        */
+       wpa_printf(MSG_DEBUG, "nl80211: Get shared freq for PHY %s",
+                  drv->phyname);
+
+       dl_list_for_each(driver, &drv->global->interfaces,
+                        struct wpa_driver_nl80211_data, list) {
+               if (drv == driver ||
+                   os_strcmp(drv->phyname, driver->phyname) != 0 ||
+                   !driver->associated)
+                       continue;
+
+               wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s "
+                          MACSTR,
+                          driver->phyname, driver->first_bss.ifname,
+                          MAC2STR(driver->first_bss.addr));
+               freq = nl80211_get_assoc_freq(driver);
+               wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
+                          drv->phyname, freq);
+       }
+
+       if (!freq)
+               wpa_printf(MSG_DEBUG, "nl80211: No shared interface for "
+                          "PHY (%s) in associated state", drv->phyname);
+
+       return freq;
+}
+
+
 static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
                              int encrypt)
 {
        struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0);
+}
+
+
+static int nl80211_set_param(void *priv, const char *param)
+{
+       wpa_printf(MSG_DEBUG, "nl80211: driver param='%s'", param);
+       if (param == NULL)
+               return 0;
+
+#ifdef CONFIG_P2P
+       if (os_strstr(param, "use_p2p_group_interface=1")) {
+               struct i802_bss *bss = priv;
+               struct wpa_driver_nl80211_data *drv = bss->drv;
+
+               wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
+                          "interface");
+               drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
+               drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
+       }
+#endif /* CONFIG_P2P */
+
+       return 0;
+}
+
+
+static void * nl80211_global_init(void)
+{
+       struct nl80211_global *global;
+       struct netlink_config *cfg;
+
+       global = os_zalloc(sizeof(*global));
+       if (global == NULL)
+               return NULL;
+       global->ioctl_sock = -1;
+       dl_list_init(&global->interfaces);
+       global->if_add_ifindex = -1;
+
+       cfg = os_zalloc(sizeof(*cfg));
+       if (cfg == NULL)
+               goto err;
+
+       cfg->ctx = global;
+       cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
+       cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
+       global->netlink = netlink_init(cfg);
+       if (global->netlink == NULL) {
+               os_free(cfg);
+               goto err;
+       }
+
+       if (wpa_driver_nl80211_init_nl_global(global) < 0)
+               goto err;
+
+       global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+       if (global->ioctl_sock < 0) {
+               perror("socket(PF_INET,SOCK_DGRAM)");
+               goto err;
+       }
+
+       return global;
+
+err:
+       nl80211_global_deinit(global);
+       return NULL;
+}
+
+
+static void nl80211_global_deinit(void *priv)
+{
+       struct nl80211_global *global = priv;
+       if (global == NULL)
+               return;
+       if (!dl_list_empty(&global->interfaces)) {
+               wpa_printf(MSG_ERROR, "nl80211: %u interface(s) remain at "
+                          "nl80211_global_deinit",
+                          dl_list_len(&global->interfaces));
+       }
+
+       if (global->netlink)
+               netlink_deinit(global->netlink);
+
+       nl_destroy_handles(&global->nl);
+
+       if (global->nl_event) {
+               eloop_unregister_read_sock(
+                       nl_socket_get_fd(global->nl_event));
+               nl_destroy_handles(&global->nl_event);
+       }
+
+       nl_cb_put(global->nl_cb);
+
+       if (global->ioctl_sock >= 0)
+               close(global->ioctl_sock);
+
+       os_free(global);
+}
+
+
+static const char * nl80211_get_radio_name(void *priv)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       return drv->phyname;
+}
+
+
+static int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid,
+                        const u8 *pmkid)
+{
+       struct nl_msg *msg;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(bss->drv, msg, 0, cmd);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
+       if (pmkid)
+               NLA_PUT(msg, NL80211_ATTR_PMKID, 16, pmkid);
+       if (bssid)
+               NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
+
+       return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+
+
+static int nl80211_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
+{
+       struct i802_bss *bss = priv;
+       wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR, MAC2STR(bssid));
+       return nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, bssid, pmkid);
+}
+
+
+static int nl80211_remove_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
+{
+       struct i802_bss *bss = priv;
+       wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
+                  MAC2STR(bssid));
+       return nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, bssid, pmkid);
+}
+
+
+static int nl80211_flush_pmkid(void *priv)
+{
+       struct i802_bss *bss = priv;
+       wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
+       return nl80211_pmkid(bss, NL80211_CMD_FLUSH_PMKSA, NULL, NULL);
+}
+
+
+static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
+                                  const u8 *replay_ctr)
+{
+       struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
+       struct nlattr *replay_nested;
+       struct nl_msg *msg;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+       replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
+       if (!replay_nested)
+               goto nla_put_failure;
+
+       NLA_PUT(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek);
+       NLA_PUT(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck);
+       NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
+               replay_ctr);
+
+       nla_nest_end(msg, replay_nested);
+
+       send_and_recv_msgs(drv, msg, NULL, NULL);
+       return;
+ nla_put_failure:
+       nlmsg_free(msg);
 }
 
 
+static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
+                                   const u8 *addr, int qos)
+{
+       /* send data frame to poll STA and check whether
+        * this frame is ACKed */
+       struct {
+               struct ieee80211_hdr hdr;
+               u16 qos_ctl;
+       } STRUCT_PACKED nulldata;
+       size_t size;
+
+       /* Send data frame to poll STA and check whether this frame is ACKed */
+
+       os_memset(&nulldata, 0, sizeof(nulldata));
+
+       if (qos) {
+               nulldata.hdr.frame_control =
+                       IEEE80211_FC(WLAN_FC_TYPE_DATA,
+                                    WLAN_FC_STYPE_QOS_NULL);
+               size = sizeof(nulldata);
+       } else {
+               nulldata.hdr.frame_control =
+                       IEEE80211_FC(WLAN_FC_TYPE_DATA,
+                                    WLAN_FC_STYPE_NULLFUNC);
+               size = sizeof(struct ieee80211_hdr);
+       }
+
+       nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
+       os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+       os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+       os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
+
+       if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0) < 0)
+               wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
+                          "send poll frame");
+}
+
+static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
+                               int qos)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+
+       if (!drv->poll_command_supported) {
+               nl80211_send_null_frame(bss, own_addr, addr, qos);
+               return;
+       }
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_PROBE_CLIENT);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+       send_and_recv_msgs(drv, msg, NULL, NULL);
+       return;
+ nla_put_failure:
+       nlmsg_free(msg);
+}
+
+
+static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
+{
+       struct nl_msg *msg;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_SET_POWER_SAVE);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE,
+                   enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED);
+       return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+
+
+static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
+                                    int ctwindow)
+{
+       struct i802_bss *bss = priv;
+
+       wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
+                  "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
+
+       if (opp_ps != -1 || ctwindow != -1)
+               return -1; /* Not yet supported */
+
+       if (legacy_ps == -1)
+               return 0;
+       if (legacy_ps != 0 && legacy_ps != 1)
+               return -1; /* Not yet supported */
+
+       return nl80211_set_power_save(bss, legacy_ps);
+}
+
+
+#ifdef CONFIG_TDLS
+
+static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
+                                 u8 dialog_token, u16 status_code,
+                                 const u8 *buf, size_t len)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+
+       if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+               return -EOPNOTSUPP;
+
+       if (!dst)
+               return -EINVAL;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_MGMT);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
+       NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code);
+       NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token);
+       NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code);
+       NLA_PUT(msg, NL80211_ATTR_IE, len, buf);
+
+       return send_and_recv_msgs(drv, msg, NULL, NULL);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+
+
+static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       enum nl80211_tdls_operation nl80211_oper;
+
+       if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+               return -EOPNOTSUPP;
+
+       switch (oper) {
+       case TDLS_DISCOVERY_REQ:
+               nl80211_oper = NL80211_TDLS_DISCOVERY_REQ;
+               break;
+       case TDLS_SETUP:
+               nl80211_oper = NL80211_TDLS_SETUP;
+               break;
+       case TDLS_TEARDOWN:
+               nl80211_oper = NL80211_TDLS_TEARDOWN;
+               break;
+       case TDLS_ENABLE_LINK:
+               nl80211_oper = NL80211_TDLS_ENABLE_LINK;
+               break;
+       case TDLS_DISABLE_LINK:
+               nl80211_oper = NL80211_TDLS_DISABLE_LINK;
+               break;
+       case TDLS_ENABLE:
+               return 0;
+       case TDLS_DISABLE:
+               return 0;
+       default:
+               return -EINVAL;
+       }
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_OPER);
+       NLA_PUT_U8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer);
+
+       return send_and_recv_msgs(drv, msg, NULL, NULL);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+
+#endif /* CONFIG TDLS */
+
+
+#ifdef ANDROID
+
+typedef struct android_wifi_priv_cmd {
+       char *buf;
+       int used_len;
+       int total_len;
+} android_wifi_priv_cmd;
+
+static int drv_errors = 0;
+
+static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
+{
+       drv_errors++;
+       if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+               drv_errors = 0;
+               wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+       }
+}
+
+
+static int android_priv_cmd(struct i802_bss *bss, const char *cmd)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct ifreq ifr;
+       android_wifi_priv_cmd priv_cmd;
+       char buf[MAX_DRV_CMD_SIZE];
+       int ret;
+
+       os_memset(&ifr, 0, sizeof(ifr));
+       os_memset(&priv_cmd, 0, sizeof(priv_cmd));
+       os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+       os_memset(buf, 0, sizeof(buf));
+       os_strlcpy(buf, cmd, sizeof(buf));
+
+       priv_cmd.buf = buf;
+       priv_cmd.used_len = sizeof(buf);
+       priv_cmd.total_len = sizeof(buf);
+       ifr.ifr_data = &priv_cmd;
+
+       ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+       if (ret < 0) {
+               wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
+                          __func__);
+               wpa_driver_send_hang_msg(drv);
+               return ret;
+       }
+
+       drv_errors = 0;
+       return 0;
+}
+
+
+static int android_pno_start(struct i802_bss *bss,
+                            struct wpa_driver_scan_params *params)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct ifreq ifr;
+       android_wifi_priv_cmd priv_cmd;
+       int ret = 0, i = 0, bp;
+       char buf[WEXT_PNO_MAX_COMMAND_SIZE];
+
+       bp = WEXT_PNOSETUP_HEADER_SIZE;
+       os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
+       buf[bp++] = WEXT_PNO_TLV_PREFIX;
+       buf[bp++] = WEXT_PNO_TLV_VERSION;
+       buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
+       buf[bp++] = WEXT_PNO_TLV_RESERVED;
+
+       while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
+               /* Check that there is enough space needed for 1 more SSID, the
+                * other sections and null termination */
+               if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
+                    WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
+                       break;
+               wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
+                                 params->ssids[i].ssid,
+                                 params->ssids[i].ssid_len);
+               buf[bp++] = WEXT_PNO_SSID_SECTION;
+               buf[bp++] = params->ssids[i].ssid_len;
+               os_memcpy(&buf[bp], params->ssids[i].ssid,
+                         params->ssids[i].ssid_len);
+               bp += params->ssids[i].ssid_len;
+               i++;
+       }
+
+       buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
+       os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
+                   WEXT_PNO_SCAN_INTERVAL);
+       bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
+
+       buf[bp++] = WEXT_PNO_REPEAT_SECTION;
+       os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
+                   WEXT_PNO_REPEAT);
+       bp += WEXT_PNO_REPEAT_LENGTH;
+
+       buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
+       os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
+                   WEXT_PNO_MAX_REPEAT);
+       bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
+
+       memset(&ifr, 0, sizeof(ifr));
+       memset(&priv_cmd, 0, sizeof(priv_cmd));
+       os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+       priv_cmd.buf = buf;
+       priv_cmd.used_len = bp;
+       priv_cmd.total_len = bp;
+       ifr.ifr_data = &priv_cmd;
+
+       ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+
+       if (ret < 0) {
+               wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
+                          ret);
+               wpa_driver_send_hang_msg(drv);
+               return ret;
+       }
+
+       drv_errors = 0;
+
+       return android_priv_cmd(bss, "PNOFORCE 1");
+}
+
+
+static int android_pno_stop(struct i802_bss *bss)
+{
+       return android_priv_cmd(bss, "PNOFORCE 0");
+}
+
+#endif /* ANDROID */
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .name = "nl80211",
        .desc = "Linux nl80211/cfg80211",
@@ -5335,18 +8726,22 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .get_ssid = wpa_driver_nl80211_get_ssid,
        .set_key = wpa_driver_nl80211_set_key,
        .scan2 = wpa_driver_nl80211_scan,
+       .sched_scan = wpa_driver_nl80211_sched_scan,
+       .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
        .get_scan_results2 = wpa_driver_nl80211_get_scan_results,
        .deauthenticate = wpa_driver_nl80211_deauthenticate,
        .disassociate = wpa_driver_nl80211_disassociate,
        .authenticate = wpa_driver_nl80211_authenticate,
        .associate = wpa_driver_nl80211_associate,
-       .init = wpa_driver_nl80211_init,
+       .global_init = nl80211_global_init,
+       .global_deinit = nl80211_global_deinit,
+       .init2 = wpa_driver_nl80211_init,
        .deinit = wpa_driver_nl80211_deinit,
        .get_capa = wpa_driver_nl80211_get_capa,
        .set_operstate = wpa_driver_nl80211_set_operstate,
        .set_supp_port = wpa_driver_nl80211_set_supp_port,
        .set_country = wpa_driver_nl80211_set_country,
-       .set_beacon = wpa_driver_nl80211_set_beacon,
+       .set_ap = wpa_driver_nl80211_set_ap,
        .if_add = wpa_driver_nl80211_if_add,
        .if_remove = wpa_driver_nl80211_if_remove,
        .send_mlme = wpa_driver_nl80211_send_mlme,
@@ -5358,33 +8753,45 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 #ifdef HOSTAPD
        .hapd_init = i802_init,
        .hapd_deinit = i802_deinit,
+       .set_wds_sta = i802_set_wds_sta,
+#endif /* HOSTAPD */
+#if defined(HOSTAPD) || defined(CONFIG_AP)
        .get_seqnum = i802_get_seqnum,
        .flush = i802_flush,
        .read_sta_data = i802_read_sta_data,
-       .sta_deauth = i802_sta_deauth,
-       .sta_disassoc = i802_sta_disassoc,
        .get_inact_sec = i802_get_inact_sec,
        .sta_clear_stats = i802_sta_clear_stats,
        .set_rts = i802_set_rts,
        .set_frag = i802_set_frag,
-       .set_rate_sets = i802_set_rate_sets,
-       .set_cts_protect = i802_set_cts_protect,
-       .set_preamble = i802_set_preamble,
-       .set_short_slot_time = i802_set_short_slot_time,
        .set_tx_queue_params = i802_set_tx_queue_params,
        .set_sta_vlan = i802_set_sta_vlan,
-       .set_wds_sta = i802_set_wds_sta,
-#endif /* HOSTAPD */
+       .sta_deauth = i802_sta_deauth,
+       .sta_disassoc = i802_sta_disassoc,
+#endif /* HOSTAPD || CONFIG_AP */
        .set_freq = i802_set_freq,
        .send_action = wpa_driver_nl80211_send_action,
+       .send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
        .remain_on_channel = wpa_driver_nl80211_remain_on_channel,
        .cancel_remain_on_channel =
        wpa_driver_nl80211_cancel_remain_on_channel,
        .probe_req_report = wpa_driver_nl80211_probe_req_report,
-       .disable_11b_rates = wpa_driver_nl80211_disable_11b_rates,
        .deinit_ap = wpa_driver_nl80211_deinit_ap,
        .resume = wpa_driver_nl80211_resume,
        .send_ft_action = nl80211_send_ft_action,
        .signal_monitor = nl80211_signal_monitor,
+       .signal_poll = nl80211_signal_poll,
        .send_frame = nl80211_send_frame,
+       .shared_freq = wpa_driver_nl80211_shared_freq,
+       .set_param = nl80211_set_param,
+       .get_radio_name = nl80211_get_radio_name,
+       .add_pmkid = nl80211_add_pmkid,
+       .remove_pmkid = nl80211_remove_pmkid,
+       .flush_pmkid = nl80211_flush_pmkid,
+       .set_rekey_info = nl80211_set_rekey_info,
+       .poll_client = nl80211_poll_client,
+       .set_p2p_powersave = nl80211_set_p2p_powersave,
+#ifdef CONFIG_TDLS
+       .send_tdls_mgmt = nl80211_send_tdls_mgmt,
+       .tdls_oper = nl80211_tdls_oper,
+#endif /* CONFIG_TDLS */
 };
diff --git a/src/drivers/driver_osx.m b/src/drivers/driver_osx.m
deleted file mode 100644 (file)
index 69ca4b5..0000000
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * WPA Supplicant - Mac OS X Apple80211 driver interface
- * 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.
- */
-
-#include "includes.h"
-#define Boolean __DummyBoolean
-#include <CoreFoundation/CoreFoundation.h>
-#undef Boolean
-
-#include "common.h"
-#include "driver.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-
-#include "Apple80211.h"
-
-struct wpa_driver_osx_data {
-       void *ctx;
-       WirelessRef wireless_ctx;
-       CFArrayRef scan_results;
-};
-
-
-#ifndef CONFIG_NO_STDOUT_DEBUG
-extern int wpa_debug_level;
-
-static void dump_dict_cb(const void *key, const void *value, void *context)
-{
-        if (MSG_DEBUG < wpa_debug_level)
-                return;
-
-       wpa_printf(MSG_DEBUG, "Key:");
-       CFShow(key);
-       wpa_printf(MSG_DEBUG, "Value:");
-       CFShow(value);
-}
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-
-static void wpa_driver_osx_dump_dict(CFDictionaryRef dict, const char *title)
-{
-#ifndef CONFIG_NO_STDOUT_DEBUG
-       wpa_printf(MSG_DEBUG, "OSX: Dump dictionary %s - %u entries",
-                  title, (unsigned int) CFDictionaryGetCount(dict));
-       CFDictionaryApplyFunction(dict, dump_dict_cb, NULL);
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-}
-
-
-static int wpa_driver_osx_get_ssid(void *priv, u8 *ssid)
-{
-       struct wpa_driver_osx_data *drv = priv;
-       WirelessError err;
-       WirelessInfo info;
-       int len;
-
-       err = WirelessGetInfo(drv->wireless_ctx, &info);
-       if (err) {
-               wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
-                          (int) err);
-               return -1;
-       }
-       if (!info.power) {
-               wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
-               return -1;
-       }
-
-       for (len = 0; len < 32; len++)
-               if (info.ssid[len] == 0)
-                       break;
-
-       os_memcpy(ssid, info.ssid, len);
-       return len;
-}
-
-
-static int wpa_driver_osx_get_bssid(void *priv, u8 *bssid)
-{
-       struct wpa_driver_osx_data *drv = priv;
-       WirelessError err;
-       WirelessInfo info;
-
-       err = WirelessGetInfo(drv->wireless_ctx, &info);
-       if (err) {
-               wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
-                          (int) err);
-               return -1;
-       }
-       if (!info.power) {
-               wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
-               return -1;
-       }
-
-       os_memcpy(bssid, info.bssID, ETH_ALEN);
-       return 0;
-}
-
-
-static void wpa_driver_osx_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-       wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-static int wpa_driver_osx_scan(void *priv, struct wpa_driver_scan_params *params)
-{
-       struct wpa_driver_osx_data *drv = priv;
-       WirelessError err;
-       const u8 *ssid = params->ssids[0].ssid;
-       size_t ssid_len = params->ssids[0].ssid_len;
-
-       if (drv->scan_results) {
-               CFRelease(drv->scan_results);
-               drv->scan_results = NULL;
-       }
-
-       if (ssid) {
-               CFStringRef data;
-               data = CFStringCreateWithBytes(kCFAllocatorDefault,
-                                              ssid, ssid_len,
-                                              kCFStringEncodingISOLatin1,
-                                              FALSE);
-               if (data == NULL) {
-                       wpa_printf(MSG_DEBUG, "CFStringCreateWithBytes "
-                                  "failed");
-                       return -1;
-               }
-
-               err = WirelessDirectedScan(drv->wireless_ctx,
-                                          &drv->scan_results, 0, data);
-               CFRelease(data);
-               if (err) {
-                       wpa_printf(MSG_DEBUG, "OSX: WirelessDirectedScan "
-                                  "failed: 0x%08x", (unsigned int) err);
-                       return -1;
-               }
-       } else {
-               err = WirelessScan(drv->wireless_ctx, &drv->scan_results, 0);
-               if (err) {
-                       wpa_printf(MSG_DEBUG, "OSX: WirelessScan failed: "
-                                  "0x%08x", (unsigned int) err);
-                       return -1;
-               }
-       }
-
-       eloop_register_timeout(0, 0, wpa_driver_osx_scan_timeout, drv,
-                              drv->ctx);
-       return 0;
-}
-
-
-static void wpa_driver_osx_add_scan_entry(struct wpa_scan_results *res,
-                                         WirelessNetworkInfo *info)
-{
-       struct wpa_scan_res *result, **tmp;
-       size_t extra_len;
-       u8 *pos;
-
-       extra_len = 2 + info->ssid_len;
-
-       result = os_zalloc(sizeof(*result) + extra_len);
-       if (result == NULL)
-               return;
-       os_memcpy(result->bssid, info->bssid, ETH_ALEN);
-       result->freq = 2407 + info->channel * 5;
-       //result->beacon_int =;
-       result->caps = info->capability;
-       //result->qual = info->signal;
-       result->noise = info->noise;
-
-       pos = (u8 *)(result + 1);
-
-       *pos++ = WLAN_EID_SSID;
-       *pos++ = info->ssid_len;
-       os_memcpy(pos, info->ssid, info->ssid_len);
-       pos += info->ssid_len;
-
-       result->ie_len = pos - (u8 *)(result + 1);
-
-       tmp = os_realloc(res->res,
-                        (res->num + 1) * sizeof(struct wpa_scan_res *));
-       if (tmp == NULL) {
-               os_free(result);
-               return;
-       }
-       tmp[res->num++] = result;
-       res->res = tmp;
-}
-
-
-static struct wpa_scan_results * wpa_driver_osx_get_scan_results(void *priv)
-{
-       struct wpa_driver_osx_data *drv = priv;
-       struct wpa_scan_results *res;
-       size_t i, num;
-
-       if (drv->scan_results == NULL)
-               return 0;
-
-       num = CFArrayGetCount(drv->scan_results);
-
-       res = os_zalloc(sizeof(*res));
-       if (res == NULL)
-               return NULL;
-
-       for (i = 0; i < num; i++)
-               wpa_driver_osx_add_scan_entry(res, (WirelessNetworkInfo *)
-                       CFDataGetBytePtr(CFArrayGetValueAtIndex(
-                               drv->scan_results, i)));
-
-       return res;
-}
-
-
-static void wpa_driver_osx_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-       struct wpa_driver_osx_data *drv = eloop_ctx;
-       u8 bssid[ETH_ALEN];
-       CFDictionaryRef ai;
-
-       if (wpa_driver_osx_get_bssid(drv, bssid) != 0) {
-               eloop_register_timeout(1, 0, wpa_driver_osx_assoc_timeout,
-                                      drv, drv->ctx);
-               return;
-       }
-
-       ai = WirelessGetAssociationInfo(drv->wireless_ctx);
-       if (ai) {
-               wpa_driver_osx_dump_dict(ai, "WirelessGetAssociationInfo");
-               CFRelease(ai);
-       } else {
-               wpa_printf(MSG_DEBUG, "OSX: Failed to get association info");
-       }
-
-       wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
-}
-
-
-static int wpa_driver_osx_associate(void *priv,
-                                   struct wpa_driver_associate_params *params)
-{
-       struct wpa_driver_osx_data *drv = priv;
-       WirelessError err;
-       CFDataRef ssid;
-       CFStringRef key;
-       int assoc_type;
-
-       ssid = CFDataCreate(kCFAllocatorDefault, params->ssid,
-                           params->ssid_len);
-       if (ssid == NULL)
-               return -1;
-
-       /* TODO: support for WEP */
-       if (params->key_mgmt_suite == KEY_MGMT_PSK) {
-               if (params->passphrase == NULL)
-                       return -1;
-               key = CFStringCreateWithCString(kCFAllocatorDefault,
-                                               params->passphrase,
-                                               kCFStringEncodingISOLatin1);
-               if (key == NULL) {
-                       CFRelease(ssid);
-                       return -1;
-               }
-       } else
-               key = NULL;
-
-       if (params->key_mgmt_suite == KEY_MGMT_NONE)
-               assoc_type = 0;
-       else
-               assoc_type = 4;
-
-       wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate(type=%d key=%p)",
-                  assoc_type, key);
-       err = WirelessAssociate(drv->wireless_ctx, assoc_type, ssid, key);
-       CFRelease(ssid);
-       if (key)
-               CFRelease(key);
-       if (err) {
-               wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate failed: 0x%08x",
-                          (unsigned int) err);
-               return -1;
-       }
-
-       /*
-        * Driver is actually already associated; report association from an
-        * eloop callback.
-        */
-       eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
-       eloop_register_timeout(0, 0, wpa_driver_osx_assoc_timeout, drv,
-                              drv->ctx);
-
-       return 0;
-}
-
-
-static int wpa_driver_osx_set_key(const char *ifname, void *priv,
-                                 enum wpa_alg alg, const u8 *addr,
-                                 int key_idx, int set_tx, const u8 *seq,
-                                 size_t seq_len, const u8 *key,
-                                 size_t key_len)
-{
-       struct wpa_driver_osx_data *drv = priv;
-       WirelessError err;
-
-       if (alg == WPA_ALG_WEP) {
-               err = WirelessSetKey(drv->wireless_ctx, 1, key_idx, key_len,
-                                    key);
-               if (err != 0) {
-                       wpa_printf(MSG_DEBUG, "OSX: WirelessSetKey failed: "
-                                  "0x%08x", (unsigned int) err);
-                       return -1;
-               }
-
-               return 0;
-       }
-
-       if (alg == WPA_ALG_PMK) {
-               err = WirelessSetWPAKey(drv->wireless_ctx, 1, key_len, key);
-               if (err != 0) {
-                       wpa_printf(MSG_DEBUG, "OSX: WirelessSetWPAKey failed: "
-                                  "0x%08x", (unsigned int) err);
-                       return -1;
-               }
-               return 0;
-       }
-
-       wpa_printf(MSG_DEBUG, "OSX: Unsupported set_key alg %d", alg);
-       return -1;
-}
-
-
-static int wpa_driver_osx_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
-       os_memset(capa, 0, sizeof(*capa));
-
-       capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-               WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-               WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
-               WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
-       capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
-               WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
-       capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
-               WPA_DRIVER_AUTH_LEAP;
-       capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
-
-       return 0;
-}
-
-
-static void * wpa_driver_osx_init(void *ctx, const char *ifname)
-{
-       struct wpa_driver_osx_data *drv;
-       WirelessError err;
-       u8 enabled, power;
-
-       if (!WirelessIsAvailable()) {
-               wpa_printf(MSG_ERROR, "OSX: No wireless interface available");
-               return NULL;
-       }
-
-       drv = os_zalloc(sizeof(*drv));
-       if (drv == NULL)
-               return NULL;
-       drv->ctx = ctx;
-       err = WirelessAttach(&drv->wireless_ctx, 0);
-       if (err) {
-               wpa_printf(MSG_ERROR, "OSX: WirelessAttach failed: %d",
-                          (int) err);
-               os_free(drv);
-               return NULL;
-       }
-
-       err = WirelessGetEnabled(drv->wireless_ctx, &enabled);
-       if (err)
-               wpa_printf(MSG_DEBUG, "OSX: WirelessGetEnabled failed: 0x%08x",
-                          (unsigned int) err);
-       err = WirelessGetPower(drv->wireless_ctx, &power);
-       if (err)
-               wpa_printf(MSG_DEBUG, "OSX: WirelessGetPower failed: 0x%08x",
-                          (unsigned int) err);
-
-       wpa_printf(MSG_DEBUG, "OSX: Enabled=%d Power=%d", enabled, power);
-
-       if (!enabled) {
-               err = WirelessSetEnabled(drv->wireless_ctx, 1);
-               if (err) {
-                       wpa_printf(MSG_DEBUG, "OSX: WirelessSetEnabled failed:"
-                                  " 0x%08x", (unsigned int) err);
-                       WirelessDetach(drv->wireless_ctx);
-                       os_free(drv);
-                       return NULL;
-               }
-       }
-
-       if (!power) {
-               err = WirelessSetPower(drv->wireless_ctx, 1);
-               if (err) {
-                       wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower failed: "
-                                  "0x%08x", (unsigned int) err);
-                       WirelessDetach(drv->wireless_ctx);
-                       os_free(drv);
-                       return NULL;
-               }
-       }
-
-       return drv;
-}
-
-
-static void wpa_driver_osx_deinit(void *priv)
-{
-       struct wpa_driver_osx_data *drv = priv;
-       WirelessError err;
-
-       eloop_cancel_timeout(wpa_driver_osx_scan_timeout, drv, drv->ctx);
-       eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
-
-       err = WirelessSetPower(drv->wireless_ctx, 0);
-       if (err) {
-               wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower(0) failed: "
-                          "0x%08x", (unsigned int) err);
-       }
-
-       err = WirelessDetach(drv->wireless_ctx);
-       if (err) {
-               wpa_printf(MSG_DEBUG, "OSX: WirelessDetach failed: 0x%08x",
-                          (unsigned int) err);
-       }
-
-       if (drv->scan_results)
-               CFRelease(drv->scan_results);
-
-       os_free(drv);
-}
-
-
-const struct wpa_driver_ops wpa_driver_osx_ops = {
-       .name = "osx",
-       .desc = "Mac OS X Apple80211 driver",
-       .get_ssid = wpa_driver_osx_get_ssid,
-       .get_bssid = wpa_driver_osx_get_bssid,
-       .init = wpa_driver_osx_init,
-       .deinit = wpa_driver_osx_deinit,
-       .scan2 = wpa_driver_osx_scan,
-       .get_scan_results2 = wpa_driver_osx_get_scan_results,
-       .associate = wpa_driver_osx_associate,
-       .set_key = wpa_driver_osx_set_key,
-       .get_capa = wpa_driver_osx_get_capa,
-};
diff --git a/src/drivers/driver_ralink.c b/src/drivers/driver_ralink.c
deleted file mode 100644 (file)
index 09d1ef5..0000000
+++ /dev/null
@@ -1,1499 +0,0 @@
-/*
- * WPA Supplicant - driver interaction with Ralink Wireless Client
- * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2007, Snowpin Lee <snowpin_lee@ralinktech.com.tw>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-
-#include "wireless_copy.h"
-#include "common.h"
-#include "driver.h"
-#include "l2_packet/l2_packet.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "priv_netlink.h"
-#include "netlink.h"
-#include "linux_ioctl.h"
-#include "driver_ralink.h"
-
-static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx);
-
-#define MAX_SSID_LEN 32
-
-struct wpa_driver_ralink_data {
-       void *ctx;
-       int ioctl_sock;
-       struct netlink_data *netlink;
-       char ifname[IFNAMSIZ + 1];
-       u8 *assoc_req_ies;
-       size_t assoc_req_ies_len;
-       u8 *assoc_resp_ies;
-       size_t assoc_resp_ies_len;
-       int no_of_pmkid;
-       struct ndis_pmkid_entry *pmkid;
-       int we_version_compiled;
-       int ap_scan;
-       int scanning_done;
-       u8 g_driver_down;
-       BOOLEAN bAddWepKey;
-};
-
-static int ralink_set_oid(struct wpa_driver_ralink_data *drv,
-                         unsigned short oid, char *data, int len)
-{
-       char *buf;
-       struct iwreq iwr;
-
-       buf = os_zalloc(len);
-       if (buf == NULL)
-               return -1;
-       os_memset(&iwr, 0, sizeof(iwr));
-       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-       iwr.u.data.flags = oid;
-       iwr.u.data.flags |= OID_GET_SET_TOGGLE;
-
-       if (data)
-               os_memcpy(buf, data, len);
-
-       iwr.u.data.pointer = (caddr_t) buf;
-       iwr.u.data.length = len;
-
-       if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
-               wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
-                          __func__, oid, len);
-               os_free(buf);
-               return -1;
-       }
-       os_free(buf);
-       return 0;
-}
-
-static int
-ralink_get_new_driver_flag(struct wpa_driver_ralink_data *drv)
-{
-       struct iwreq iwr;
-       UCHAR enabled = 0;
-
-       os_memset(&iwr, 0, sizeof(iwr));
-       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-       iwr.u.data.pointer = (UCHAR*) &enabled;
-       iwr.u.data.flags = RT_OID_NEW_DRIVER;
-
-       if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
-               wpa_printf(MSG_DEBUG, "%s: failed", __func__);
-               return 0;
-       }
-
-       return (enabled == 1) ? 1 : 0;
-}
-
-static int wpa_driver_ralink_get_bssid(void *priv, u8 *bssid)
-{
-       struct wpa_driver_ralink_data *drv = priv;
-       struct iwreq iwr;
-       int ret = 0;
-
-       if (drv->g_driver_down == 1)
-               return -1;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       os_memset(&iwr, 0, sizeof(iwr));
-       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-       if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
-               perror("ioctl[SIOCGIWAP]");
-               ret = -1;
-       }
-       os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
-
-       return ret;
-}
-
-static int wpa_driver_ralink_get_ssid(void *priv, u8 *ssid)
-{
-       struct wpa_driver_ralink_data *drv = priv;
-#if 0
-       struct wpa_supplicant *wpa_s = drv->ctx;
-       struct wpa_ssid *entry;
-#endif
-       int ssid_len;
-       u8 bssid[ETH_ALEN];
-       u8 ssid_str[MAX_SSID_LEN];
-       struct iwreq iwr;
-#if 0
-       int result = 0;
-#endif
-       int ret = 0;
-#if 0
-       BOOLEAN ieee8021x_mode = FALSE;
-       BOOLEAN ieee8021x_required_key = FALSE;
-#endif
-
-       if (drv->g_driver_down == 1)
-               return -1;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       os_memset(&iwr, 0, sizeof(iwr));
-       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-       iwr.u.essid.pointer = (caddr_t) ssid;
-       iwr.u.essid.length = 32;
-
-       if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
-               perror("ioctl[SIOCGIWESSID]");
-               ret = -1;
-       } else
-               ret = iwr.u.essid.length;
-
-       if (ret <= 0)
-               return ret;
-
-       ssid_len = ret;
-       os_memset(ssid_str, 0, MAX_SSID_LEN);
-       os_memcpy(ssid_str, ssid, ssid_len);
-
-       if (drv->ap_scan == 0) {
-               /* Read BSSID form driver */
-               if (wpa_driver_ralink_get_bssid(priv, bssid) < 0) {
-                       wpa_printf(MSG_WARNING, "Could not read BSSID from "
-                                  "driver.");
-                       return ret;
-               }
-
-#if 0
-               entry = wpa_s->conf->ssid;
-               while (entry) {
-                       if (!entry->disabled && ssid_len == entry->ssid_len &&
-                           os_memcmp(ssid_str, entry->ssid, ssid_len) == 0 &&
-                           (!entry->bssid_set ||
-                            os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)) {
-                               /* match the config of driver */
-                               result = 1;
-                               break;
-                       }
-                       entry = entry->next;
-               }
-
-               if (result) {
-                       wpa_printf(MSG_DEBUG, "Ready to set 802.1x mode and "
-                                  "ieee_required_keys parameters to driver");
-
-                       /* set 802.1x mode and ieee_required_keys parameter */
-                       if (entry->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
-                               if ((entry->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST | EAPOL_FLAG_REQUIRE_KEY_BROADCAST)))
-                                               ieee8021x_required_key = TRUE;
-                               ieee8021x_mode = TRUE;
-                       }
-
-                       if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X, (char *) &ieee8021x_mode, sizeof(BOOLEAN)) < 0)
-                       {
-                               wpa_printf(MSG_DEBUG, "RALINK: Failed to set OID_802_11_SET_IEEE8021X(%d)", (int) ieee8021x_mode);
-                       }
-                       else
-                       {
-                               wpa_printf(MSG_DEBUG, "ieee8021x_mode is %s", ieee8021x_mode ? "TRUE" : "FALSE");
-                       }
-
-                       if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY, (char *) &ieee8021x_required_key, sizeof(BOOLEAN)) < 0)
-                       {
-                               wpa_printf(MSG_DEBUG, "ERROR: Failed to set OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)", (int) ieee8021x_required_key);
-                       }
-                       else
-                       {
-                               wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s and eapol_flag(%d)", ieee8021x_required_key ? "TRUE" : "FALSE",
-                                                                                                                                                                                               entry->eapol_flags);
-                       }
-               }
-#endif
-       }
-
-       return ret;
-}
-
-static int wpa_driver_ralink_set_ssid(struct wpa_driver_ralink_data *drv,
-                                     const u8 *ssid, size_t ssid_len)
-{
-       NDIS_802_11_SSID *buf;
-       int ret = 0;
-       struct iwreq iwr;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       buf = os_zalloc(sizeof(NDIS_802_11_SSID));
-       if (buf == NULL)
-               return -1;
-       os_memset(buf, 0, sizeof(buf));
-       buf->SsidLength = ssid_len;
-       os_memcpy(buf->Ssid, ssid, ssid_len);
-       os_memset(&iwr, 0, sizeof(iwr));
-       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-       iwr.u.data.flags = OID_802_11_SSID;
-       iwr.u.data.flags |= OID_GET_SET_TOGGLE;
-       iwr.u.data.pointer = (caddr_t) buf;
-       iwr.u.data.length = sizeof(NDIS_802_11_SSID);
-
-       if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
-               perror("ioctl[RT_PRIV_IOCTL] -- OID_802_11_SSID");
-               ret = -1;
-       }
-       os_free(buf);
-       return ret;
-}
-
-static void wpa_driver_ralink_event_pmkid(struct wpa_driver_ralink_data *drv,
-                                         const u8 *data, size_t data_len)
-{
-       NDIS_802_11_PMKID_CANDIDATE_LIST *pmkid;
-       size_t i;
-       union wpa_event_data event;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       if (data_len < 8) {
-               wpa_printf(MSG_DEBUG, "RALINK: Too short PMKID Candidate List "
-                          "Event (len=%lu)", (unsigned long) data_len);
-               return;
-       }
-       pmkid = (NDIS_802_11_PMKID_CANDIDATE_LIST *) data;
-       wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List Event - Version %d"
-                  " NumCandidates %d",
-                  (int) pmkid->Version, (int) pmkid->NumCandidates);
-
-       if (pmkid->Version != 1) {
-               wpa_printf(MSG_DEBUG, "RALINK: Unsupported PMKID Candidate "
-                          "List Version %d", (int) pmkid->Version);
-               return;
-       }
-
-       if (data_len < 8 + pmkid->NumCandidates * sizeof(PMKID_CANDIDATE)) {
-               wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List "
-                          "underflow");
-
-               return;
-       }
-
-
-
-       os_memset(&event, 0, sizeof(event));
-       for (i = 0; i < pmkid->NumCandidates; i++) {
-               PMKID_CANDIDATE *p = &pmkid->CandidateList[i];
-               wpa_printf(MSG_DEBUG, "RALINK: %lu: " MACSTR " Flags 0x%x",
-                          (unsigned long) i, MAC2STR(p->BSSID),
-                          (int) p->Flags);
-               os_memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN);
-               event.pmkid_candidate.index = i;
-               event.pmkid_candidate.preauth =
-                       p->Flags & NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
-               wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE,
-                                    &event);
-       }
-}
-
-static int wpa_driver_ralink_set_pmkid(struct wpa_driver_ralink_data *drv)
-{
-       int len, count, i, ret;
-       struct ndis_pmkid_entry *entry;
-       NDIS_802_11_PMKID *p;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       count = 0;
-       entry = drv->pmkid;
-       while (entry) {
-               count++;
-               if (count >= drv->no_of_pmkid)
-                       break;
-               entry = entry->next;
-       }
-       len = 8 + count * sizeof(BSSID_INFO);
-       p = os_zalloc(len);
-       if (p == NULL)
-               return -1;
-       p->Length = len;
-       p->BSSIDInfoCount = count;
-       entry = drv->pmkid;
-       for (i = 0; i < count; i++) {
-               os_memcpy(&p->BSSIDInfo[i].BSSID, entry->bssid, ETH_ALEN);
-               os_memcpy(&p->BSSIDInfo[i].PMKID, entry->pmkid, 16);
-               entry = entry->next;
-       }
-       wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID",
-                   (const u8 *) p, len);
-       ret = ralink_set_oid(drv, OID_802_11_PMKID, (char *) p, len);
-       os_free(p);
-       return ret;
-}
-
-static int wpa_driver_ralink_add_pmkid(void *priv, const u8 *bssid,
-                                      const u8 *pmkid)
-{
-       struct wpa_driver_ralink_data *drv = priv;
-       struct ndis_pmkid_entry *entry, *prev;
-
-       if (drv->g_driver_down == 1)
-               return -1;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       if (drv->no_of_pmkid == 0)
-               return 0;
-
-       prev = NULL;
-       entry = drv->pmkid;
-       while (entry) {
-               if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0)
-                       break;
-               prev = entry;
-               entry = entry->next;
-       }
-
-       if (entry) {
-               /* Replace existing entry for this BSSID and move it into the
-                * beginning of the list. */
-               os_memcpy(entry->pmkid, pmkid, 16);
-               if (prev) {
-                       prev->next = entry->next;
-                       entry->next = drv->pmkid;
-                       drv->pmkid = entry;
-               }
-       } else {
-               entry = os_malloc(sizeof(*entry));
-               if (entry) {
-                       os_memcpy(entry->bssid, bssid, ETH_ALEN);
-                       os_memcpy(entry->pmkid, pmkid, 16);
-                       entry->next = drv->pmkid;
-                       drv->pmkid = entry;
-               }
-       }
-
-       return wpa_driver_ralink_set_pmkid(drv);
-}
-
-
-static int wpa_driver_ralink_remove_pmkid(void *priv, const u8 *bssid,
-                                         const u8 *pmkid)
-{
-       struct wpa_driver_ralink_data *drv = priv;
-       struct ndis_pmkid_entry *entry, *prev;
-
-       if (drv->g_driver_down == 1)
-               return -1;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       if (drv->no_of_pmkid == 0)
-               return 0;
-
-       entry = drv->pmkid;
-       prev = NULL;
-       drv->pmkid = NULL;
-       while (entry) {
-               if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0 &&
-                   os_memcmp(entry->pmkid, pmkid, 16) == 0) {
-                       if (prev)
-                               prev->next = entry->next;
-                       else
-                               drv->pmkid = entry->next;
-                       os_free(entry);
-                       break;
-               }
-               prev = entry;
-               entry = entry->next;
-       }
-       return wpa_driver_ralink_set_pmkid(drv);
-}
-
-
-static int wpa_driver_ralink_flush_pmkid(void *priv)
-{
-       struct wpa_driver_ralink_data *drv = priv;
-       NDIS_802_11_PMKID p;
-       struct ndis_pmkid_entry *pmkid, *prev;
-
-       if (drv->g_driver_down == 1)
-               return -1;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       if (drv->no_of_pmkid == 0)
-               return 0;
-
-       pmkid = drv->pmkid;
-       drv->pmkid = NULL;
-       while (pmkid) {
-               prev = pmkid;
-               pmkid = pmkid->next;
-               os_free(prev);
-       }
-
-       os_memset(&p, 0, sizeof(p));
-       p.Length = 8;
-       p.BSSIDInfoCount = 0;
-       wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID (flush)",
-                   (const u8 *) &p, 8);
-       return ralink_set_oid(drv, OID_802_11_PMKID, (char *) &p, 8);
-}
-
-static void
-wpa_driver_ralink_event_wireless_custom(struct wpa_driver_ralink_data *drv,
-                                       void *ctx, char *custom)
-{
-       union wpa_event_data data;
-       u8 *req_ies = NULL, *resp_ies = NULL;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
-
-       os_memset(&data, 0, sizeof(data));
-       /* Host AP driver */
-       if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
-               /* receive a MICFAILURE report */
-               data.michael_mic_failure.unicast =
-                       os_strstr(custom, " unicast") != NULL;
-               /* TODO: parse parameters(?) */
-               wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
-       } else if (os_strncmp(custom, "ASSOCINFO_ReqIEs=", 17) == 0) {
-               /* receive assoc. req. IEs */
-               char *spos;
-               int bytes;
-
-               spos = custom + 17;
-               /*get IE's length */
-               /*
-                * bytes = strlen(spos); ==> bug, bytes may less than original
-                * size by using this way to get size. snowpin 20070312
-                * if (!bytes)
-                *      return;
-                */
-               bytes = drv->assoc_req_ies_len;
-
-               req_ies = os_malloc(bytes);
-               if (req_ies == NULL)
-                       return;
-               os_memcpy(req_ies, spos, bytes);
-               data.assoc_info.req_ies = req_ies;
-               data.assoc_info.req_ies_len = bytes;
-
-               /* skip the '\0' byte */
-               spos += bytes + 1;
-
-               data.assoc_info.resp_ies = NULL;
-               data.assoc_info.resp_ies_len = 0;
-
-               if (os_strncmp(spos, " RespIEs=", 9) == 0) {
-                       /* receive assoc. resp. IEs */
-                       spos += 9;
-                       /* get IE's length */
-                       bytes = os_strlen(spos);
-                       if (!bytes)
-                               goto done;
-
-                       resp_ies = os_malloc(bytes);
-                       if (resp_ies == NULL)
-                               goto done;
-                       os_memcpy(resp_ies, spos, bytes);
-                       data.assoc_info.resp_ies = resp_ies;
-                       data.assoc_info.resp_ies_len = bytes;
-               }
-
-               wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
-
-       done:
-               /* free allocated memory */
-               os_free(resp_ies);
-               os_free(req_ies);
-       }
-}
-
-static void ralink_interface_up(struct wpa_driver_ralink_data *drv)
-{
-       union wpa_event_data event;
-       int enable_wpa_supplicant = 0;
-       drv->g_driver_down = 0;
-       os_memset(&event, 0, sizeof(event));
-       os_snprintf(event.interface_status.ifname,
-                   sizeof(event.interface_status.ifname), "%s", drv->ifname);
-
-       event.interface_status.ievent = EVENT_INTERFACE_ADDED;
-       wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
-
-       if (drv->ap_scan == 1)
-               enable_wpa_supplicant = 1;
-       else
-               enable_wpa_supplicant = 2;
-       /* trigger driver support wpa_supplicant */
-       if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-                          (PCHAR) &enable_wpa_supplicant, sizeof(UCHAR)) < 0)
-       {
-               wpa_printf(MSG_INFO, "RALINK: Failed to set "
-                          "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
-                          (int) enable_wpa_supplicant);
-               wpa_printf(MSG_ERROR, "ralink. Driver does not support "
-                          "wpa_supplicant");
-       }
-}
-
-static void
-wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv,
-                                void *ctx, char *data, int len)
-{
-       struct iw_event iwe_buf, *iwe = &iwe_buf;
-       char *pos, *end, *custom, *buf, *assoc_info_buf, *info_pos;
-#if 0
-       BOOLEAN ieee8021x_required_key = FALSE;
-#endif
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       assoc_info_buf = info_pos = NULL;
-       pos = data;
-       end = data + len;
-
-       while (pos + IW_EV_LCP_LEN <= end) {
-               /* Event data may be unaligned, so make a local, aligned copy
-                * before processing. */
-               os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
-               wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
-                          iwe->cmd, iwe->len);
-               if (iwe->len <= IW_EV_LCP_LEN)
-                       return;
-
-               custom = pos + IW_EV_POINT_LEN;
-
-               if (drv->we_version_compiled > 18 && iwe->cmd == IWEVCUSTOM) {
-                       /* WE-19 removed the pointer from struct iw_point */
-                       char *dpos = (char *) &iwe_buf.u.data.length;
-                       int dlen = dpos - (char *) &iwe_buf;
-                       os_memcpy(dpos, pos + IW_EV_LCP_LEN,
-                                 sizeof(struct iw_event) - dlen);
-               } else {
-                       os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
-                       custom += IW_EV_POINT_OFF;
-               }
-
-               switch (iwe->cmd) {
-               case IWEVCUSTOM:
-                       if (custom + iwe->u.data.length > end)
-                               return;
-                       buf = os_malloc(iwe->u.data.length + 1);
-                       if (buf == NULL)
-                               return;
-                       os_memcpy(buf, custom, iwe->u.data.length);
-                       buf[iwe->u.data.length] = '\0';
-
-                       if (drv->ap_scan == 1) {
-                               if ((iwe->u.data.flags == RT_ASSOC_EVENT_FLAG)
-                                   || (iwe->u.data.flags ==
-                                       RT_REQIE_EVENT_FLAG) ||
-                                   (iwe->u.data.flags == RT_RESPIE_EVENT_FLAG)
-                                   || (iwe->u.data.flags ==
-                                       RT_ASSOCINFO_EVENT_FLAG)) {
-                                       if (drv->scanning_done == 0) {
-                                               os_free(buf);
-                                               return;
-                                       }
-                               }
-                       }
-
-                       if (iwe->u.data.flags == RT_ASSOC_EVENT_FLAG) {
-                               wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
-                               wpa_printf(MSG_DEBUG, "Custom wireless event: "
-                                          "receive ASSOCIATED_EVENT !!!");
-                       } else if (iwe->u.data.flags == RT_REQIE_EVENT_FLAG) {
-                               wpa_printf(MSG_DEBUG, "Custom wireless event: "
-                                          "receive ReqIEs !!!");
-                               drv->assoc_req_ies =
-                                       os_malloc(iwe->u.data.length);
-                               if (drv->assoc_req_ies == NULL) {
-                                       os_free(buf);
-                                       return;
-                               }
-
-                               drv->assoc_req_ies_len = iwe->u.data.length;
-                               os_memcpy(drv->assoc_req_ies, custom,
-                                         iwe->u.data.length);
-                       } else if (iwe->u.data.flags == RT_RESPIE_EVENT_FLAG) {
-                               wpa_printf(MSG_DEBUG, "Custom wireless event: "
-                                          "receive RespIEs !!!");
-                               drv->assoc_resp_ies =
-                                       os_malloc(iwe->u.data.length);
-                               if (drv->assoc_resp_ies == NULL) {
-                                       os_free(drv->assoc_req_ies);
-                                       drv->assoc_req_ies = NULL;
-                                       os_free(buf);
-                                       return;
-                               }
-
-                               drv->assoc_resp_ies_len = iwe->u.data.length;
-                               os_memcpy(drv->assoc_resp_ies, custom,
-                                         iwe->u.data.length);
-                       } else if (iwe->u.data.flags ==
-                                  RT_ASSOCINFO_EVENT_FLAG) {
-                               wpa_printf(MSG_DEBUG, "Custom wireless event: "
-                                          "receive ASSOCINFO_EVENT !!!");
-
-                               assoc_info_buf =
-                                       os_zalloc(drv->assoc_req_ies_len +
-                                                 drv->assoc_resp_ies_len + 1);
-
-                               if (assoc_info_buf == NULL) {
-                                       os_free(drv->assoc_req_ies);
-                                       drv->assoc_req_ies = NULL;
-                                       os_free(drv->assoc_resp_ies);
-                                       drv->assoc_resp_ies = NULL;
-                                       os_free(buf);
-                                       return;
-                               }
-
-                               if (drv->assoc_req_ies) {
-                                       os_memcpy(assoc_info_buf,
-                                                 drv->assoc_req_ies,
-                                                 drv->assoc_req_ies_len);
-                               }
-                               info_pos = assoc_info_buf +
-                                       drv->assoc_req_ies_len;
-                               if (drv->assoc_resp_ies) {
-                                       os_memcpy(info_pos,
-                                                 drv->assoc_resp_ies,
-                                                 drv->assoc_resp_ies_len);
-                               }
-                               assoc_info_buf[drv->assoc_req_ies_len +
-                                              drv->assoc_resp_ies_len] = '\0';
-                               wpa_driver_ralink_event_wireless_custom(
-                                       drv, ctx, assoc_info_buf);
-                               os_free(drv->assoc_req_ies);
-                               drv->assoc_req_ies = NULL;
-                               os_free(drv->assoc_resp_ies);
-                               drv->assoc_resp_ies = NULL;
-                               os_free(assoc_info_buf);
-                       } else if (iwe->u.data.flags == RT_DISASSOC_EVENT_FLAG)
-                       {
-                               wpa_printf(MSG_DEBUG, "Custom wireless event: "
-                                          "receive DISASSOCIATED_EVENT !!!");
-                               wpa_supplicant_event(ctx, EVENT_DISASSOC,
-                                                    NULL);
-                       } else if (iwe->u.data.flags == RT_PMKIDCAND_FLAG) {
-                               wpa_printf(MSG_DEBUG, "Custom wireless event: "
-                                          "receive PMKIDCAND_EVENT !!!");
-                               wpa_driver_ralink_event_pmkid(
-                                       drv, (const u8 *) custom,
-                                       iwe->u.data.length);
-                       } else if (iwe->u.data.flags == RT_INTERFACE_DOWN) {
-                               drv->g_driver_down = 1;
-                               eloop_terminate();
-                       } else if (iwe->u.data.flags == RT_INTERFACE_UP) {
-                               ralink_interface_up(drv);
-                       } else {
-                               wpa_driver_ralink_event_wireless_custom(
-                                       drv, ctx, buf);
-                       }
-                       os_free(buf);
-                       break;
-               }
-
-               pos += iwe->len;
-       }
-}
-
-static void
-wpa_driver_ralink_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, 
-                                   u8 *buf, size_t len)
-{
-       struct wpa_driver_ralink_data *drv = ctx;
-       int attrlen, rta_len;
-       struct rtattr *attr;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       wpa_hexdump(MSG_DEBUG, "ifi: ", (u8 *) ifi, sizeof(struct ifinfomsg));
-
-       attrlen = len;
-       wpa_printf(MSG_DEBUG, "attrlen=%d", attrlen);
-       attr = (struct rtattr *) buf;
-       wpa_hexdump(MSG_DEBUG, "attr1: ", (u8 *) attr, sizeof(struct rtattr));
-       rta_len = RTA_ALIGN(sizeof(struct rtattr));
-       wpa_hexdump(MSG_DEBUG, "attr2: ", (u8 *)attr,rta_len);
-       while (RTA_OK(attr, attrlen)) {
-               wpa_printf(MSG_DEBUG, "rta_type=%02x\n", attr->rta_type);
-               if (attr->rta_type == IFLA_WIRELESS) {
-                       wpa_driver_ralink_event_wireless(
-                               drv, ctx,
-                               ((char *) attr) + rta_len,
-                               attr->rta_len - rta_len);
-               }
-               attr = RTA_NEXT(attr, attrlen);
-               wpa_hexdump(MSG_DEBUG, "attr3: ",
-                           (u8 *) attr, sizeof(struct rtattr));
-       }
-}
-
-static int
-ralink_get_we_version_compiled(struct wpa_driver_ralink_data *drv)
-{
-       struct iwreq iwr;
-       UINT we_version_compiled = 0;
-
-       os_memset(&iwr, 0, sizeof(iwr));
-       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-       iwr.u.data.pointer = (caddr_t) &we_version_compiled;
-       iwr.u.data.flags = RT_OID_WE_VERSION_COMPILED;
-
-       if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
-               wpa_printf(MSG_DEBUG, "%s: failed", __func__);
-               return -1;
-       }
-
-       drv->we_version_compiled = we_version_compiled;
-
-       return 0;
-}
-
-static void * wpa_driver_ralink_init(void *ctx, const char *ifname)
-{
-       int s;
-       struct wpa_driver_ralink_data *drv;
-       struct ifreq ifr;
-       UCHAR enable_wpa_supplicant = 0;
-       struct netlink_config *cfg;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       /* open socket to kernel */
-       if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-               perror("socket");
-               return NULL;
-       }
-       /* do it */
-       os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-
-       if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
-               perror(ifr.ifr_name);
-               return NULL;
-       }
-
-       drv = os_zalloc(sizeof(*drv));
-       if (drv == NULL)
-               return NULL;
-
-       drv->scanning_done = 1;
-       drv->ap_scan = 1; /* for now - let's assume ap_scan=1 is used */
-       drv->ctx = ctx;
-       os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-       drv->ioctl_sock = s;
-       drv->g_driver_down = 0;
-
-       cfg = os_zalloc(sizeof(*cfg));
-       if (cfg == NULL) {
-               close(drv->ioctl_sock);
-               os_free(drv);
-               return NULL;
-       }
-       cfg->ctx = drv;
-       cfg->newlink_cb = wpa_driver_ralink_event_rtm_newlink;
-       drv->netlink = netlink_init(cfg);
-       if (drv->netlink == NULL) {
-               os_free(cfg);
-               close(drv->ioctl_sock);
-               os_free(drv);
-               return NULL;
-       }
-
-       drv->no_of_pmkid = 4; /* Number of PMKID saved supported */
-
-       linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1);
-       ralink_get_we_version_compiled(drv);
-       wpa_driver_ralink_flush_pmkid(drv);
-
-       if (drv->ap_scan == 1)
-               enable_wpa_supplicant = 1;
-       else
-               enable_wpa_supplicant = 2;
-       /* trigger driver support wpa_supplicant */
-       if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-                          (PCHAR) &enable_wpa_supplicant, sizeof(UCHAR)) < 0)
-       {
-               wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-                          "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
-                          (int) enable_wpa_supplicant);
-               wpa_printf(MSG_ERROR, "RALINK: Driver does not support "
-                          "wpa_supplicant");
-               close(s);
-               close(drv->ioctl_sock);
-               os_free(drv);
-               return NULL;
-       }
-
-       if (drv->ap_scan == 1)
-               drv->scanning_done = 0;
-
-       return drv;
-}
-
-static void wpa_driver_ralink_deinit(void *priv)
-{
-       struct wpa_driver_ralink_data *drv = priv;
-       UCHAR enable_wpa_supplicant;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       enable_wpa_supplicant = 0;
-
-       if (drv->g_driver_down == 0) {
-               /* trigger driver disable wpa_supplicant support */
-               if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-                                  (char *) &enable_wpa_supplicant,
-                                  sizeof(BOOLEAN)) < 0) {
-                       wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-                                  "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
-                                  (int) enable_wpa_supplicant);
-               }
-
-               wpa_driver_ralink_flush_pmkid(drv);
-
-               sleep(1);
-               /* linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0); */
-       }
-
-       eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx);
-       netlink_deinit(drv->netlink);
-       close(drv->ioctl_sock);
-       os_free(drv);
-}
-
-static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-       struct wpa_driver_ralink_data *drv = eloop_ctx;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
-       wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-
-       drv->scanning_done = 1;
-
-}
-
-static int wpa_driver_ralink_scan(void *priv,
-                                 struct wpa_driver_scan_params *params)
-{
-       struct wpa_driver_ralink_data *drv = priv;
-       struct iwreq iwr;
-       int ret = 0;
-
-       if (drv->g_driver_down == 1)
-               return -1;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-#if 0
-       if (ssid_len > IW_ESSID_MAX_SIZE) {
-               wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
-                          __FUNCTION__, (unsigned long) ssid_len);
-               return -1;
-       }
-
-       /* wpa_driver_ralink_set_ssid(drv, ssid, ssid_len); */
-#endif
-
-       if (ralink_set_oid(drv, RT_OID_WPS_PROBE_REQ_IE,
-                          (char *) params->extra_ies, params->extra_ies_len) <
-           0) {
-               wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-                          "RT_OID_WPS_PROBE_REQ_IE");
-       }
-
-       os_memset(&iwr, 0, sizeof(iwr));
-       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-       if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
-               perror("ioctl[SIOCSIWSCAN]");
-               ret = -1;
-       }
-
-       /* Not all drivers generate "scan completed" wireless event, so try to
-        * read results after a timeout. */
-       eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx);
-       eloop_register_timeout(4, 0, wpa_driver_ralink_scan_timeout, drv,
-                              drv->ctx);
-
-       drv->scanning_done = 0;
-
-       return ret;
-}
-
-static struct wpa_scan_results *
-wpa_driver_ralink_get_scan_results(void *priv)
-{
-       struct wpa_driver_ralink_data *drv = priv;
-       UCHAR *buf = NULL;
-       size_t buf_len;
-       NDIS_802_11_BSSID_LIST_EX *wsr;
-       NDIS_WLAN_BSSID_EX *wbi;
-       struct iwreq iwr;
-       size_t ap_num;
-       u8 *pos;
-       struct wpa_scan_results *res;
-
-       if (drv->g_driver_down == 1)
-               return NULL;
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       if (drv->we_version_compiled >= 17)
-               buf_len = 8192;
-       else
-               buf_len = 4096;
-
-       for (;;) {
-               buf = os_zalloc(buf_len);
-               iwr.u.data.length = buf_len;
-               if (buf == NULL)
-                       return NULL;
-
-               wsr = (NDIS_802_11_BSSID_LIST_EX *) buf;
-
-               wsr->NumberOfItems = 0;
-               os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-               iwr.u.data.pointer = (void *) buf;
-               iwr.u.data.flags = OID_802_11_BSSID_LIST;
-
-               if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) == 0)
-                       break;
-
-               if (errno == E2BIG && buf_len < 65535) {
-                       os_free(buf);
-                       buf = NULL;
-                       buf_len *= 2;
-                       if (buf_len > 65535)
-                               buf_len = 65535; /* 16-bit length field */
-                       wpa_printf(MSG_DEBUG, "Scan results did not fit - "
-                                  "trying larger buffer (%lu bytes)",
-                                  (unsigned long) buf_len);
-               } else {
-                       perror("ioctl[RT_PRIV_IOCTL]");
-                       os_free(buf);
-                       return NULL;
-               }
-       }
-
-       res = os_zalloc(sizeof(*res));
-       if (res == NULL) {
-               os_free(buf);
-               return NULL;
-       }
-
-       res->res = os_zalloc(wsr->NumberOfItems *
-                            sizeof(struct wpa_scan_res *));
-       if (res->res == NULL) {
-               os_free(res);
-               os_free(buf);
-               return NULL;
-       }
-
-       for (ap_num = 0, wbi = wsr->Bssid; ap_num < wsr->NumberOfItems;
-            ++ap_num) {
-               struct wpa_scan_res *r = NULL;
-               size_t extra_len = 0, var_ie_len = 0;
-               u8 *pos2;
-
-               /* SSID data element */
-               extra_len += 2 + wbi->Ssid.SsidLength;
-               var_ie_len = wbi->IELength - sizeof(NDIS_802_11_FIXED_IEs);
-               r = os_zalloc(sizeof(*r) + extra_len + var_ie_len);
-               if (r == NULL)
-                       break;
-               res->res[res->num++] = r;
-
-               wpa_printf(MSG_DEBUG, "SSID - %s", wbi->Ssid.Ssid);
-               /* get ie's */
-               wpa_hexdump(MSG_DEBUG, "RALINK: AP IEs",
-                           (u8 *) &wbi->IEs[0], wbi->IELength);
-
-               os_memcpy(r->bssid, wbi->MacAddress, ETH_ALEN);
-
-               extra_len += (2 + wbi->Ssid.SsidLength);
-               r->ie_len = extra_len + var_ie_len;
-               pos2 = (u8 *) (r + 1);
-
-               /*
-                * Generate a fake SSID IE since the driver did not report
-                * a full IE list.
-                */
-               *pos2++ = WLAN_EID_SSID;
-               *pos2++ = wbi->Ssid.SsidLength;
-               os_memcpy(pos2, wbi->Ssid.Ssid, wbi->Ssid.SsidLength);
-               pos2 += wbi->Ssid.SsidLength;
-
-               r->freq = (wbi->Configuration.DSConfig / 1000);
-
-               pos = (u8 *) wbi + sizeof(*wbi) - 1;
-
-               pos += sizeof(NDIS_802_11_FIXED_IEs) - 2;
-               os_memcpy(&(r->caps), pos, 2);
-               pos += 2;
-
-               if (wbi->IELength > sizeof(NDIS_802_11_FIXED_IEs))
-                       os_memcpy(pos2, pos, var_ie_len);
-
-               wbi = (NDIS_WLAN_BSSID_EX *) ((u8 *) wbi + wbi->Length);
-       }
-
-       os_free(buf);
-       return res;
-}
-
-static int ralink_set_auth_mode(struct wpa_driver_ralink_data *drv,
-                               NDIS_802_11_AUTHENTICATION_MODE mode)
-{
-       NDIS_802_11_AUTHENTICATION_MODE auth_mode = mode;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       if (ralink_set_oid(drv, OID_802_11_AUTHENTICATION_MODE,
-                          (char *) &auth_mode, sizeof(auth_mode)) < 0) {
-               wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-                          "OID_802_11_AUTHENTICATION_MODE (%d)",
-                          (int) auth_mode);
-               return -1;
-       }
-       return 0;
-}
-
-static int ralink_set_encr_type(struct wpa_driver_ralink_data *drv,
-                               NDIS_802_11_WEP_STATUS encr_type)
-{
-       NDIS_802_11_WEP_STATUS wep_status = encr_type;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       if (ralink_set_oid(drv, OID_802_11_WEP_STATUS,
-                          (char *) &wep_status, sizeof(wep_status)) < 0) {
-               wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-                          "OID_802_11_WEP_STATUS (%d)",
-                          (int) wep_status);
-               return -1;
-       }
-       return 0;
-}
-
-
-static int wpa_driver_ralink_remove_key(struct wpa_driver_ralink_data *drv,
-                                       int key_idx, const u8 *addr,
-                                       const u8 *bssid, int pairwise)
-{
-       NDIS_802_11_REMOVE_KEY rkey;
-       NDIS_802_11_KEY_INDEX _index;
-       int res, res2;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       os_memset(&rkey, 0, sizeof(rkey));
-
-       rkey.Length = sizeof(rkey);
-       rkey.KeyIndex = key_idx;
-
-       if (pairwise)
-               rkey.KeyIndex |= 1 << 30;
-
-       os_memcpy(rkey.BSSID, bssid, ETH_ALEN);
-
-       res = ralink_set_oid(drv, OID_802_11_REMOVE_KEY, (char *) &rkey,
-                            sizeof(rkey));
-
-       /* AlbertY@20060210 removed it */
-       if (0 /* !pairwise */) {
-               res2 = ralink_set_oid(drv, OID_802_11_REMOVE_WEP,
-                                     (char *) &_index, sizeof(_index));
-       } else
-               res2 = 0;
-
-       if (res < 0 && res2 < 0)
-               return res;
-       return 0;
-}
-
-static int wpa_driver_ralink_add_wep(struct wpa_driver_ralink_data *drv,
-                                    int pairwise, int key_idx, int set_tx,
-                                    const u8 *key, size_t key_len)
-{
-       NDIS_802_11_WEP *wep;
-       size_t len;
-       int res;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       len = 12 + key_len;
-       wep = os_zalloc(len);
-       if (wep == NULL)
-               return -1;
-
-       wep->Length = len;
-       wep->KeyIndex = key_idx;
-
-       if (set_tx)
-               wep->KeyIndex |= 0x80000000;
-
-       wep->KeyLength = key_len;
-       os_memcpy(wep->KeyMaterial, key, key_len);
-
-       wpa_hexdump_key(MSG_MSGDUMP, "RALINK: OID_802_11_ADD_WEP",
-                       (const u8 *) wep, len);
-       res = ralink_set_oid(drv, OID_802_11_ADD_WEP, (char *) wep, len);
-
-       os_free(wep);
-
-       return res;
-}
-
-static int wpa_driver_ralink_set_key(const char *ifname, void *priv,
-                                    enum wpa_alg alg, const u8 *addr,
-                                    int key_idx, int set_tx,
-                                    const u8 *seq, size_t seq_len,
-                                    const u8 *key, size_t key_len)
-{
-       struct wpa_driver_ralink_data *drv = priv;
-       size_t len, i;
-       NDIS_802_11_KEY *nkey;
-       int res, pairwise;
-       u8 bssid[ETH_ALEN];
-
-       if (drv->g_driver_down == 1)
-               return -1;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       drv->bAddWepKey = FALSE;
-
-       if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
-                                     ETH_ALEN) == 0) {
-               /* Group Key */
-               pairwise = 0;
-               wpa_driver_ralink_get_bssid(drv, bssid);
-       } else {
-               /* Pairwise Key */
-               pairwise = 1;
-               os_memcpy(bssid, addr, ETH_ALEN);
-       }
-
-       if (alg == WPA_ALG_NONE || key_len == 0) {
-               return wpa_driver_ralink_remove_key(drv, key_idx, addr, bssid,
-                                                   pairwise);
-       }
-
-       if (alg == WPA_ALG_WEP) {
-               drv->bAddWepKey = TRUE;
-               return wpa_driver_ralink_add_wep(drv, pairwise, key_idx,
-                                                set_tx, key, key_len);
-       }
-
-       len = 12 + 6 + 6 + 8 + key_len;
-
-       nkey = os_zalloc(len);
-       if (nkey == NULL)
-               return -1;
-
-       nkey->Length = len;
-       nkey->KeyIndex = key_idx;
-
-       if (set_tx)
-               nkey->KeyIndex |= 1 << 31;
-
-       if (pairwise)
-               nkey->KeyIndex |= 1 << 30;
-
-       if (seq && seq_len)
-               nkey->KeyIndex |= 1 << 29;
-
-       nkey->KeyLength = key_len;
-       os_memcpy(nkey->BSSID, bssid, ETH_ALEN);
-
-       if (seq && seq_len) {
-               for (i = 0; i < seq_len; i++)
-                       nkey->KeyRSC |= seq[i] << (i * 8);
-       }
-       if (alg == WPA_ALG_TKIP && key_len == 32) {
-               os_memcpy(nkey->KeyMaterial, key, 16);
-               os_memcpy(nkey->KeyMaterial + 16, key + 24, 8);
-               os_memcpy(nkey->KeyMaterial + 24, key + 16, 8);
-       } else {
-               os_memcpy(nkey->KeyMaterial, key, key_len);
-       }
-
-       wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
-                  "key_len=%lu", __FUNCTION__, alg, key_idx, set_tx,
-                  (unsigned long) seq_len, (unsigned long) key_len);
-
-       wpa_hexdump_key(MSG_MSGDUMP, "RALINK: OID_802_11_ADD_KEY",
-                       (const u8 *) nkey, len);
-       res = ralink_set_oid(drv, OID_802_11_ADD_KEY, (char *) nkey, len);
-       os_free(nkey);
-
-       return res;
-}
-
-static int wpa_driver_ralink_disassociate(void *priv, const u8 *addr,
-                                       int reason_code)
-{
-       struct wpa_driver_ralink_data *drv = priv;
-
-       if (drv->g_driver_down == 1)
-               return -1;
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-       if (ralink_set_oid(drv, OID_802_11_DISASSOCIATE, "    ", 4) < 0) {
-               wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-                          "OID_802_11_DISASSOCIATE");
-       }
-
-       return 0;
-}
-
-static int wpa_driver_ralink_deauthenticate(void *priv, const u8 *addr,
-                                         int reason_code)
-{
-       struct wpa_driver_ralink_data *drv = priv;
-
-       wpa_printf(MSG_DEBUG, "g_driver_down = %d", drv->g_driver_down);
-
-       if (drv->g_driver_down == 1)
-               return -1;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-       if (ralink_get_new_driver_flag(drv) == 0) {
-               return wpa_driver_ralink_disassociate(priv, addr, reason_code);
-       } else {
-               MLME_DEAUTH_REQ_STRUCT mlme;
-               os_memset(&mlme, 0, sizeof(MLME_DEAUTH_REQ_STRUCT));
-               mlme.Reason = reason_code;
-               os_memcpy(mlme.Addr, addr, MAC_ADDR_LEN);
-               return ralink_set_oid(drv, OID_802_11_DEAUTHENTICATION,
-                                     (char *) &mlme,
-                                     sizeof(MLME_DEAUTH_REQ_STRUCT));
-       }
-}
-
-static int wpa_driver_ralink_set_gen_ie(void *priv, const u8 *ie,
-                                       size_t ie_len)
-{
-       struct wpa_driver_ralink_data *drv = priv;
-       struct iwreq iwr;
-       int ret = 0;
-
-       os_memset(&iwr, 0, sizeof(iwr));
-       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-       iwr.u.data.pointer = (caddr_t) ie;
-       iwr.u.data.length = ie_len;
-
-       wpa_hexdump(MSG_DEBUG, "wpa_driver_ralink_set_gen_ie: ",
-                   (u8 *) ie, ie_len);
-
-       if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
-               perror("ioctl[SIOCSIWGENIE]");
-               ret = -1;
-       }
-
-       return ret;
-}
-
-static int
-wpa_driver_ralink_associate(void *priv,
-                           struct wpa_driver_associate_params *params)
-{
-       struct wpa_driver_ralink_data *drv = priv;
-
-       NDIS_802_11_NETWORK_INFRASTRUCTURE mode;
-       NDIS_802_11_AUTHENTICATION_MODE auth_mode;
-       NDIS_802_11_WEP_STATUS encr;
-       BOOLEAN         ieee8021xMode;
-       BOOLEAN         ieee8021x_required_key = TRUE;
-
-       if (drv->g_driver_down == 1)
-               return -1;
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       if (params->mode == IEEE80211_MODE_IBSS)
-               mode = Ndis802_11IBSS;
-       else
-               mode = Ndis802_11Infrastructure;
-
-       if (ralink_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE,
-                        (char *) &mode, sizeof(mode)) < 0) {
-               wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-                          "OID_802_11_INFRASTRUCTURE_MODE (%d)",
-                          (int) mode);
-               /* Try to continue anyway */
-       }
-
-       if (params->key_mgmt_suite == KEY_MGMT_WPS) {
-               UCHAR enable_wps = 0x80;
-               /* trigger driver support wpa_supplicant */
-               if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-                                  (PCHAR) &enable_wps, sizeof(UCHAR)) < 0) {
-                       wpa_printf(MSG_INFO, "RALINK: Failed to set "
-                                  "RT_OID_WPA_SUPPLICANT_SUPPORT (%d)",
-                                  (int) enable_wps);
-               }
-
-               wpa_driver_ralink_set_gen_ie(priv, params->wpa_ie,
-                                            params->wpa_ie_len);
-
-               ralink_set_auth_mode(drv, Ndis802_11AuthModeOpen);
-
-               ralink_set_encr_type(drv, Ndis802_11EncryptionDisabled);
-       } else {
-#ifdef CONFIG_WPS
-               UCHAR enable_wpa_supplicant;
-
-               if (drv->ap_scan == 1)
-                       enable_wpa_supplicant = 0x01;
-               else
-                       enable_wpa_supplicant = 0x02;
-
-               /* trigger driver support wpa_supplicant */
-               if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-                                  (PCHAR) &enable_wpa_supplicant,
-                                  sizeof(UCHAR)) < 0) {
-                       wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-                                  "RT_OID_WPA_SUPPLICANT_SUPPORT (%d)",
-                                  (int) enable_wpa_supplicant);
-               }
-
-               wpa_driver_ralink_set_gen_ie(priv, (u8 *) "", 0);
-#endif /* CONFIG_WPS */
-
-               if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
-                       if (params->auth_alg & WPA_AUTH_ALG_SHARED) {
-                               if (params->auth_alg & WPA_AUTH_ALG_OPEN)
-                                       auth_mode = Ndis802_11AuthModeAutoSwitch;
-                               else
-                                       auth_mode = Ndis802_11AuthModeShared;
-                       } else
-                               auth_mode = Ndis802_11AuthModeOpen;
-               } else if (params->wpa_ie[0] == WLAN_EID_RSN) {
-                       if (params->key_mgmt_suite == KEY_MGMT_PSK)
-                               auth_mode = Ndis802_11AuthModeWPA2PSK;
-                       else
-                               auth_mode = Ndis802_11AuthModeWPA2;
-               } else {
-                       if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE)
-                               auth_mode = Ndis802_11AuthModeWPANone;
-                       else if (params->key_mgmt_suite == KEY_MGMT_PSK)
-                               auth_mode = Ndis802_11AuthModeWPAPSK;
-                       else
-                               auth_mode = Ndis802_11AuthModeWPA;
-               }
-
-               switch (params->pairwise_suite) {
-               case CIPHER_CCMP:
-                       encr = Ndis802_11Encryption3Enabled;
-                       break;
-               case CIPHER_TKIP:
-                       encr = Ndis802_11Encryption2Enabled;
-                       break;
-               case CIPHER_WEP40:
-               case CIPHER_WEP104:
-                       encr = Ndis802_11Encryption1Enabled;
-                       break;
-               case CIPHER_NONE:
-                       if (params->group_suite == CIPHER_CCMP)
-                               encr = Ndis802_11Encryption3Enabled;
-                       else if (params->group_suite == CIPHER_TKIP)
-                               encr = Ndis802_11Encryption2Enabled;
-                       else
-                               encr = Ndis802_11EncryptionDisabled;
-                       break;
-               default:
-                       encr = Ndis802_11EncryptionDisabled;
-                       break;
-               }
-
-               ralink_set_auth_mode(drv, auth_mode);
-
-               /* notify driver that IEEE8021x mode is enabled */
-               if (params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) {
-                       ieee8021xMode = TRUE;
-                       if (drv->bAddWepKey)
-                               ieee8021x_required_key = FALSE;
-               } else
-                       ieee8021xMode = FALSE;
-
-               if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY,
-                                  (char *) &ieee8021x_required_key,
-                                  sizeof(BOOLEAN)) < 0) {
-                       wpa_printf(MSG_DEBUG, "ERROR: Failed to set "
-                                  "OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)",
-                                  (int) ieee8021x_required_key);
-               } else {
-                       wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s",
-                                  ieee8021x_required_key ? "TRUE" : "FALSE");
-               }
-
-               if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X,
-                                  (char *) &ieee8021xMode, sizeof(BOOLEAN)) <
-                   0) {
-                       wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-                                  "OID_802_11_SET_IEEE8021X(%d)",
-                                  (int) ieee8021xMode);
-               }
-
-               ralink_set_encr_type(drv, encr);
-
-               if ((ieee8021xMode == FALSE) &&
-                   (encr == Ndis802_11Encryption1Enabled)) {
-                       /* static WEP */
-                       int enabled = 0;
-                       if (ralink_set_oid(drv, OID_802_11_DROP_UNENCRYPTED,
-                                          (char *) &enabled, sizeof(enabled))
-                           < 0) {
-                               wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-                                          "OID_802_11_DROP_UNENCRYPTED(%d)",
-                                          (int) encr);
-                       }
-               }
-       }
-
-       return wpa_driver_ralink_set_ssid(drv, params->ssid, params->ssid_len);
-}
-
-static int
-wpa_driver_ralink_set_countermeasures(void *priv, int enabled)
-{
-       struct wpa_driver_ralink_data *drv = priv;
-       if (drv->g_driver_down == 1)
-               return -1;
-       wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-       return ralink_set_oid(drv, OID_SET_COUNTERMEASURES, (char *) &enabled,
-                             sizeof(int));
-}
-
-const struct wpa_driver_ops wpa_driver_ralink_ops = {
-       .name = "ralink",
-       .desc = "Ralink Wireless Client driver",
-       .get_bssid = wpa_driver_ralink_get_bssid,
-       .get_ssid = wpa_driver_ralink_get_ssid,
-       .set_key = wpa_driver_ralink_set_key,
-       .init = wpa_driver_ralink_init,
-       .deinit = wpa_driver_ralink_deinit,
-       .set_countermeasures    = wpa_driver_ralink_set_countermeasures,
-       .scan2 = wpa_driver_ralink_scan,
-       .get_scan_results2 = wpa_driver_ralink_get_scan_results,
-       .deauthenticate = wpa_driver_ralink_deauthenticate,
-       .disassociate = wpa_driver_ralink_disassociate,
-       .associate = wpa_driver_ralink_associate,
-       .add_pmkid = wpa_driver_ralink_add_pmkid,
-       .remove_pmkid = wpa_driver_ralink_remove_pmkid,
-       .flush_pmkid = wpa_driver_ralink_flush_pmkid,
-};
diff --git a/src/drivers/driver_ralink.h b/src/drivers/driver_ralink.h
deleted file mode 100644 (file)
index d13df28..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * WPA Supplicant - driver_ralink exported functions
- * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2007, Snowpin Lee <snowpin_lee@ralinktech.com.tw>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-// Ralink defined OIDs
-#if WIRELESS_EXT <= 11
-#ifndef SIOCDEVPRIVATE
-#define SIOCDEVPRIVATE                              0x8BE0
-#endif
-#define SIOCIWFIRSTPRIV                                                                SIOCDEVPRIVATE
-#endif
-
-#define RT_PRIV_IOCTL                                                          (SIOCIWFIRSTPRIV + 0x0E)  
-#define RTPRIV_IOCTL_SET                                                       (SIOCIWFIRSTPRIV + 0x02)
-
-// IEEE 802.11 OIDs  &  Ralink defined OIDs  ******
-
-// (RaConfig Set/QueryInform) ==>
-#define OID_GET_SET_TOGGLE                                                     0x8000
-
-#define OID_802_11_ADD_WEP                          0x0112
-#define OID_802_11_REMOVE_WEP                       0x0113
-#define OID_802_11_DISASSOCIATE                     0x0114
-#define OID_802_11_PRIVACY_FILTER                   0x0118
-#define OID_802_11_ASSOCIATION_INFORMATION          0x011E
-#define OID_802_11_BSSID_LIST_SCAN                  0x0508
-#define OID_802_11_SSID                             0x0509
-#define OID_802_11_BSSID                            0x050A
-#define OID_802_11_WEP_STATUS                       0x0510
-#define OID_802_11_AUTHENTICATION_MODE              0x0511
-#define OID_802_11_INFRASTRUCTURE_MODE              0x0512
-#define OID_802_11_TX_POWER_LEVEL                   0x0517
-#define OID_802_11_REMOVE_KEY                       0x0519
-#define OID_802_11_ADD_KEY                          0x0520
-#define OID_802_11_DEAUTHENTICATION                 0x0526
-#define OID_802_11_DROP_UNENCRYPTED                 0x0527
-#define OID_802_11_BSSID_LIST                       0x0609
-#define OID_802_3_CURRENT_ADDRESS                   0x060A
-#define OID_SET_COUNTERMEASURES                     0x0616
-#define OID_802_11_SET_IEEE8021X                    0x0617     // For IEEE8021x mode 
-#define OID_802_11_SET_IEEE8021X_REQUIRE_KEY        0x0618  // For DynamicWEP in IEEE802.1x mode
-#define OID_802_11_PMKID                            0x0620
-#define RT_OID_WPA_SUPPLICANT_SUPPORT               0x0621  // for trigger driver enable/disable wpa_supplicant support 
-#define RT_OID_WE_VERSION_COMPILED                  0x0622
-#define RT_OID_NEW_DRIVER                           0x0623
-#define RT_OID_WPS_PROBE_REQ_IE                                                0x0625
-
-#define PACKED  __attribute__ ((packed))
-
-//wpa_supplicant event flags
-#define        RT_ASSOC_EVENT_FLAG                         0x0101
-#define        RT_DISASSOC_EVENT_FLAG                      0x0102
-#define        RT_REQIE_EVENT_FLAG                         0x0103
-#define        RT_RESPIE_EVENT_FLAG                        0x0104
-#define        RT_ASSOCINFO_EVENT_FLAG                     0x0105
-#define RT_PMKIDCAND_FLAG                           0x0106
-#define RT_INTERFACE_DOWN                           0x0107
-#define RT_INTERFACE_UP                                0x0108
-
-//
-// IEEE 802.11 Structures and definitions
-//
-// new types for Media Specific Indications
-
-#ifndef ULONG
-#define CHAR            char
-#define INT             int
-#define SHORT           int
-#define UINT            u32
-#undef  ULONG           
-//#define ULONG           u32
-#define ULONG           unsigned long /* 32-bit in 32-bit CPU or 64-bit in 64-bit CPU */
-#define USHORT          unsigned short
-#define UCHAR           unsigned char
-
-#define uint32         u32
-#define uint8          u8
-
-
-#define BOOLEAN         u8
-//#define LARGE_INTEGER s64
-#define VOID            void
-#define LONG            long
-#define LONGLONG        s64
-#define ULONGLONG       u64
-typedef VOID            *PVOID;
-typedef CHAR            *PCHAR;
-typedef UCHAR           *PUCHAR;
-typedef USHORT          *PUSHORT;
-typedef LONG            *PLONG;
-typedef ULONG           *PULONG;
-
-typedef union _LARGE_INTEGER {
-    struct {
-        ULONG LowPart;
-        LONG HighPart;
-    }vv;
-    struct {
-        ULONG LowPart;
-        LONG HighPart;
-    } u;
-    s64 QuadPart;
-} LARGE_INTEGER;
-
-#endif
-
-#define NDIS_802_11_LENGTH_SSID         32
-#define NDIS_802_11_LENGTH_RATES        8
-#define NDIS_802_11_LENGTH_RATES_EX     16
-#define MAX_LEN_OF_SSID                 32
-#define MAC_ADDR_LEN                    6
-
-typedef UCHAR   NDIS_802_11_MAC_ADDRESS[6];
-
-// mask for authentication/integrity fields
-#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS        0x0f
-
-#define NDIS_802_11_AUTH_REQUEST_REAUTH             0x01
-#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE          0x02
-#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR     0x06
-#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR        0x0E
-
-// Added new types for OFDM 5G and 2.4G
-typedef enum _NDIS_802_11_NETWORK_TYPE
-{
-    Ndis802_11FH, 
-    Ndis802_11DS, 
-    Ndis802_11OFDM5,
-    Ndis802_11OFDM24,
-    Ndis802_11Automode,
-    Ndis802_11NetworkTypeMax    // not a real type, defined as an upper bound
-} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE;
-
-//
-// Received Signal Strength Indication
-//
-typedef LONG    NDIS_802_11_RSSI;           // in dBm
-
-typedef struct _NDIS_802_11_CONFIGURATION_FH
-{
-   ULONG           Length;            // Length of structure
-   ULONG           HopPattern;        // As defined by 802.11, MSB set 
-   ULONG           HopSet;            // to one if non-802.11
-   ULONG           DwellTime;         // units are Kusec
-} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH;
-
-typedef struct _NDIS_802_11_CONFIGURATION
-{
-   ULONG                           Length;             // Length of structure
-   ULONG                           BeaconPeriod;       // units are Kusec
-   ULONG                           ATIMWindow;         // units are Kusec
-   ULONG                           DSConfig;           // Frequency, units are kHz
-   NDIS_802_11_CONFIGURATION_FH    FHConfig;
-} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION;
-
-typedef  ULONG  NDIS_802_11_KEY_INDEX;
-typedef ULONGLONG   NDIS_802_11_KEY_RSC;
-
-// Key mapping keys require a BSSID
-typedef struct _NDIS_802_11_KEY
-{
-    UINT           Length;             // Length of this structure
-    UINT           KeyIndex;           
-    UINT           KeyLength;          // length of key in bytes
-    NDIS_802_11_MAC_ADDRESS BSSID;
-    NDIS_802_11_KEY_RSC KeyRSC;
-    UCHAR           KeyMaterial[1];     // variable length depending on above field
-} NDIS_802_11_KEY, *PNDIS_802_11_KEY;
-
-typedef struct _NDIS_802_11_REMOVE_KEY
-{
-    UINT                   Length;        // Length of this structure
-    UINT                   KeyIndex;           
-    NDIS_802_11_MAC_ADDRESS BSSID;      
-} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY;
-
-typedef struct PACKED _NDIS_802_11_WEP
-{
-   UINT     Length;        // Length of this structure
-   UINT           KeyIndex;           // 0 is the per-client key, 1-N are the
-                                        // global keys
-   UINT     KeyLength;     // length of key in bytes
-   UCHAR     KeyMaterial[1];// variable length depending on above field
-} NDIS_802_11_WEP, *PNDIS_802_11_WEP;
-
-
-typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE
-{
-   Ndis802_11IBSS,
-   Ndis802_11Infrastructure,
-   Ndis802_11AutoUnknown,
-   Ndis802_11InfrastructureMax     // Not a real value, defined as upper bound
-} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE;
-
-// PMKID Structures
-typedef UCHAR   NDIS_802_11_PMKID_VALUE[16];
-
-typedef struct _BSSID_INFO
-{
-       NDIS_802_11_MAC_ADDRESS BSSID;
-       NDIS_802_11_PMKID_VALUE PMKID;
-} BSSID_INFO, *PBSSID_INFO;
-
-typedef struct _NDIS_802_11_PMKID
-{
-       ULONG Length;
-       ULONG BSSIDInfoCount;
-       BSSID_INFO BSSIDInfo[1];
-} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID;
-
-//Added new types for PMKID Candidate lists.
-typedef struct _PMKID_CANDIDATE {
-       NDIS_802_11_MAC_ADDRESS BSSID;
-       ULONG Flags;
-} PMKID_CANDIDATE, *PPMKID_CANDIDATE;
-
-typedef struct _NDIS_802_11_PMKID_CANDIDATE_LIST
-{
-       ULONG Version;       // Version of the structure
-       ULONG NumCandidates; // No. of pmkid candidates
-       PMKID_CANDIDATE CandidateList[1];
-} NDIS_802_11_PMKID_CANDIDATE_LIST, *PNDIS_802_11_PMKID_CANDIDATE_LIST;
-
-//Flags for PMKID Candidate list structure
-#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED    0x01
-
-// Add new authentication modes
-typedef enum _NDIS_802_11_AUTHENTICATION_MODE
-{
-   Ndis802_11AuthModeOpen,
-   Ndis802_11AuthModeShared,
-   Ndis802_11AuthModeAutoSwitch,
-   Ndis802_11AuthModeWPA,
-   Ndis802_11AuthModeWPAPSK,
-   Ndis802_11AuthModeWPANone,
-   Ndis802_11AuthModeWPA2,
-   Ndis802_11AuthModeWPA2PSK,    
-   Ndis802_11AuthModeMax           // Not a real mode, defined as upper bound
-} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE;
-
-typedef UCHAR  NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES];        // Set of 8 data rates
-typedef UCHAR  NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX];  // Set of 16 data rates
-
-typedef struct PACKED _NDIS_802_11_SSID 
-{
-    INT   SsidLength;         // length of SSID field below, in bytes;
-                                // this can be zero.
-    UCHAR   Ssid[NDIS_802_11_LENGTH_SSID];           // SSID information field
-} NDIS_802_11_SSID, *PNDIS_802_11_SSID;
-
-
-typedef struct PACKED _NDIS_WLAN_BSSID
-{
-   ULONG                               Length;     // Length of this structure
-   NDIS_802_11_MAC_ADDRESS             MacAddress; // BSSID
-   UCHAR                               Reserved[2];
-   NDIS_802_11_SSID                    Ssid;       // SSID
-   ULONG                               Privacy;    // WEP encryption requirement
-    NDIS_802_11_RSSI                    Rssi;               // receive signal
-                                                            // strength in dBm
-   NDIS_802_11_NETWORK_TYPE            NetworkTypeInUse;
-   NDIS_802_11_CONFIGURATION           Configuration;
-   NDIS_802_11_NETWORK_INFRASTRUCTURE  InfrastructureMode;
-   NDIS_802_11_RATES                   SupportedRates;
-} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID;
-
-typedef struct PACKED _NDIS_802_11_BSSID_LIST
-{
-   UINT             NumberOfItems;      // in list below, at least 1
-   NDIS_WLAN_BSSID Bssid[1];
-} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST;
-
-// Added Capabilities, IELength and IEs for each BSSID
-typedef struct PACKED _NDIS_WLAN_BSSID_EX
-{
-    ULONG                               Length;             // Length of this structure
-    NDIS_802_11_MAC_ADDRESS             MacAddress;         // BSSID
-    UCHAR                               Reserved[2];
-    NDIS_802_11_SSID                    Ssid;               // SSID
-    UINT                                Privacy;            // WEP encryption requirement
-    NDIS_802_11_RSSI                    Rssi;               // receive signal
-                                                            // strength in dBm
-    NDIS_802_11_NETWORK_TYPE            NetworkTypeInUse;
-    NDIS_802_11_CONFIGURATION           Configuration;
-    NDIS_802_11_NETWORK_INFRASTRUCTURE  InfrastructureMode;
-    NDIS_802_11_RATES_EX                SupportedRates;
-    ULONG                               IELength;
-    UCHAR                               IEs[1];
-} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX;
-
-typedef struct PACKED _NDIS_802_11_BSSID_LIST_EX
-{
-    UINT                   NumberOfItems;      // in list below, at least 1
-    NDIS_WLAN_BSSID_EX      Bssid[1];
-} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX;
-
-typedef struct PACKED _NDIS_802_11_FIXED_IEs 
-{
-    UCHAR Timestamp[8];
-    USHORT BeaconInterval;
-    USHORT Capabilities;
-} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs;
-
-// Added new encryption types
-// Also aliased typedef to new name
-typedef enum _NDIS_802_11_WEP_STATUS
-{
-   Ndis802_11WEPEnabled,
-   Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
-   Ndis802_11WEPDisabled,
-   Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
-   Ndis802_11WEPKeyAbsent,
-   Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
-   Ndis802_11WEPNotSupported,
-   Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
-   Ndis802_11Encryption2Enabled,
-   Ndis802_11Encryption2KeyAbsent,
-   Ndis802_11Encryption3Enabled,
-   Ndis802_11Encryption3KeyAbsent
-} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS,
-  NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS;
-
-typedef enum _NDIS_802_11_RELOAD_DEFAULTS
-{
-   Ndis802_11ReloadWEPKeys
-} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS;
-
-#define NDIS_802_11_AI_REQFI_CAPABILITIES      1
-#define NDIS_802_11_AI_REQFI_LISTENINTERVAL    2
-#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS  4
-
-#define NDIS_802_11_AI_RESFI_CAPABILITIES      1
-#define NDIS_802_11_AI_RESFI_STATUSCODE        2
-#define NDIS_802_11_AI_RESFI_ASSOCIATIONID     4
-
-typedef struct _NDIS_802_11_AI_REQFI
-{
-    USHORT Capabilities;
-    USHORT ListenInterval;
-    NDIS_802_11_MAC_ADDRESS  CurrentAPAddress;
-} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI;
-
-typedef struct _NDIS_802_11_AI_RESFI
-{
-    USHORT Capabilities;
-    USHORT StatusCode;
-    USHORT AssociationId;
-} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI;
-
-typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION
-{
-    ULONG                   Length;
-    USHORT                  AvailableRequestFixedIEs;
-    NDIS_802_11_AI_REQFI    RequestFixedIEs;
-    ULONG                   RequestIELength;
-    ULONG                   OffsetRequestIEs;
-    USHORT                  AvailableResponseFixedIEs;
-    NDIS_802_11_AI_RESFI    ResponseFixedIEs;
-    ULONG                   ResponseIELength;
-    ULONG                   OffsetResponseIEs;
-} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION;
-
-struct ndis_pmkid_entry {
-       struct ndis_pmkid_entry *next;
-       u8 bssid[ETH_ALEN];
-       u8 pmkid[16];
-};
-
-typedef struct _MLME_DEAUTH_REQ_STRUCT {
-    UCHAR        Addr[MAC_ADDR_LEN];
-    USHORT       Reason;
-} MLME_DEAUTH_REQ_STRUCT, *PMLME_DEAUTH_REQ_STRUCT;
index 6877eda..61b75b1 100644 (file)
 
 #include "includes.h"
 #include <sys/ioctl.h>
-#include <linux/if.h>
 #include <linux/sockios.h>
 #include <linux/if_ether.h>
 #include <linux/mii.h>
+#include <net/if.h>
 
 #include "common.h"
 #include "driver.h"
@@ -364,7 +364,7 @@ static void * wpa_driver_roboswitch_init(void *ctx, const char *ifname)
        /* copy ifname and take a pointer to the second to last character */
        sep = drv->ifname +
              os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)) - 2;
-       /* find the '.' seperating <interface> and <vlan> */
+       /* find the '.' separating <interface> and <vlan> */
        while (sep > drv->ifname && *sep != '.') sep--;
        if (sep <= drv->ifname) {
                wpa_printf(MSG_INFO, "%s: No <interface>.<vlan> pair in "
index fb24673..f8e314b 100644 (file)
@@ -34,6 +34,8 @@
 #include "common/ieee802_11_defs.h"
 #include "crypto/sha1.h"
 #include "l2_packet/l2_packet.h"
+#include "p2p/p2p.h"
+#include "wps/wps.h"
 #include "driver.h"
 
 
@@ -87,7 +89,6 @@ struct wpa_driver_test_data {
        int use_associnfo;
        u8 assoc_wpa_ie[80];
        size_t assoc_wpa_ie_len;
-       int use_mlme;
        int associated;
        u8 *probe_req_ie;
        size_t probe_req_ie_len;
@@ -107,6 +108,20 @@ struct wpa_driver_test_data {
        unsigned int remain_on_channel_duration;
 
        int current_freq;
+
+       struct p2p_data *p2p;
+       unsigned int off_channel_freq;
+       struct wpabuf *pending_action_tx;
+       u8 pending_action_src[ETH_ALEN];
+       u8 pending_action_dst[ETH_ALEN];
+       u8 pending_action_bssid[ETH_ALEN];
+       unsigned int pending_action_freq;
+       unsigned int pending_action_no_cck;
+       unsigned int pending_listen_freq;
+       unsigned int pending_listen_duration;
+       int pending_p2p_scan;
+       struct sockaddr *probe_from;
+       socklen_t probe_from_len;
 };
 
 
@@ -116,6 +131,7 @@ static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
 static void wpa_driver_test_close_test_socket(
        struct wpa_driver_test_data *drv);
 static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx);
+static int wpa_driver_test_init_p2p(struct wpa_driver_test_data *drv);
 
 
 static void test_driver_free_bss(struct test_driver_bss *bss)
@@ -159,7 +175,7 @@ test_driver_get_cli(struct wpa_driver_test_data *drv, struct sockaddr_un *from,
 
 static int test_driver_send_eapol(void *priv, const u8 *addr, const u8 *data,
                                  size_t data_len, int encrypt,
-                                 const u8 *own_addr)
+                                 const u8 *own_addr, u32 flags)
 {
        struct test_driver_bss *dbss = priv;
        struct wpa_driver_test_data *drv = dbss->drv;
@@ -293,7 +309,7 @@ static int test_driver_send_ether(void *priv, const u8 *dst, const u8 *src,
 
 
 static int wpa_driver_test_send_mlme(void *priv, const u8 *data,
-                                    size_t data_len)
+                                    size_t data_len, int noack)
 {
        struct test_driver_bss *dbss = priv;
        struct wpa_driver_test_data *drv = dbss->drv;
@@ -469,6 +485,34 @@ static int wpa_driver_test_send_mlme(void *priv, const u8 *data,
        event.tx_status.ack = ret >= 0;
        wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
 
+#ifdef CONFIG_P2P
+       if (drv->p2p &&
+           WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+           WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
+               if (drv->pending_action_tx == NULL) {
+                       wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - "
+                                  "no pending operation");
+                       return ret;
+               }
+
+               if (os_memcmp(hdr->addr1, drv->pending_action_dst, ETH_ALEN) !=
+                   0) {
+                       wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - "
+                                  "unknown destination address");
+                       return ret;
+               }
+
+               wpabuf_free(drv->pending_action_tx);
+               drv->pending_action_tx = NULL;
+
+               p2p_send_action_cb(drv->p2p, drv->pending_action_freq,
+                                  drv->pending_action_dst,
+                                  drv->pending_action_src,
+                                  drv->pending_action_bssid,
+                                  ret >= 0);
+       }
+#endif /* CONFIG_P2P */
+
        return ret;
 }
 
@@ -515,6 +559,10 @@ static void test_driver_scan(struct wpa_driver_test_data *drv,
                event.rx_probe_req.ie = ie;
                event.rx_probe_req.ie_len = ielen;
                wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event);
+#ifdef CONFIG_P2P
+               if (drv->p2p)
+                       p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen);
+#endif /* CONFIG_P2P */
        }
 
        dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) {
@@ -624,7 +672,7 @@ static void test_driver_assoc(struct wpa_driver_test_data *drv,
        sendto(drv->test_socket, cmd, strlen(cmd), 0,
               (struct sockaddr *) from, fromlen);
 
-       drv_event_assoc(bss->bss_ctx, cli->addr, ie, ielen);
+       drv_event_assoc(bss->bss_ctx, cli->addr, ie, ielen, 0);
 }
 
 
@@ -841,7 +889,8 @@ static int test_driver_set_generic_elem(void *priv,
 
 
 static int test_driver_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
-                                    const struct wpabuf *proberesp)
+                                    const struct wpabuf *proberesp,
+                                    const struct wpabuf *assocresp)
 {
        struct test_driver_bss *bss = priv;
 
@@ -1015,7 +1064,8 @@ static int test_driver_bss_remove(void *priv, const char *ifname)
 static int test_driver_if_add(void *priv, enum wpa_driver_if_type type,
                              const char *ifname, const u8 *addr,
                              void *bss_ctx, void **drv_priv,
-                             char *force_ifname, u8 *if_addr)
+                             char *force_ifname, u8 *if_addr,
+                             const char *bridge)
 {
        struct test_driver_bss *dbss = priv;
        struct wpa_driver_test_data *drv = dbss->drv;
@@ -1033,7 +1083,8 @@ static int test_driver_if_add(void *priv, enum wpa_driver_if_type type,
                         sizeof(drv->alloc_iface_idx),
                         if_addr + 1, ETH_ALEN - 1);
        }
-       if (type == WPA_IF_AP_BSS)
+       if (type == WPA_IF_AP_BSS || type == WPA_IF_P2P_GO ||
+           type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP)
                return test_driver_bss_add(priv, ifname, if_addr, bss_ctx,
                                           drv_priv);
        return 0;
@@ -1044,27 +1095,23 @@ static int test_driver_if_remove(void *priv, enum wpa_driver_if_type type,
                                 const char *ifname)
 {
        wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s)", __func__, type, ifname);
-       if (type == WPA_IF_AP_BSS)
+       if (type == WPA_IF_AP_BSS || type == WPA_IF_P2P_GO ||
+           type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP)
                return test_driver_bss_remove(priv, ifname);
        return 0;
 }
 
 
-static int test_driver_valid_bss_mask(void *priv, const u8 *addr,
-                                     const u8 *mask)
-{
-       return 0;
-}
-
-
 static int test_driver_set_ssid(void *priv, const u8 *buf, int len)
 {
        struct test_driver_bss *bss = priv;
 
        wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, bss->ifname);
+       if (len < 0)
+               return -1;
        wpa_hexdump_ascii(MSG_DEBUG, "test_driver_set_ssid: SSID", buf, len);
 
-       if (len < 0 || (size_t) len > sizeof(bss->ssid))
+       if ((size_t) len > sizeof(bss->ssid))
                return -1;
 
        os_memcpy(bss->ssid, buf, len);
@@ -1178,6 +1225,7 @@ static void * test_driver_init(struct hostapd_data *hapd,
                return NULL;
        drv->ap = 1;
        bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
+       drv->global = params->global_priv;
 
        bss->bss_ctx = hapd;
        os_memcpy(bss->bssid, drv->own_addr, ETH_ALEN);
@@ -1271,7 +1319,23 @@ static void wpa_driver_test_poll(void *eloop_ctx, void *timeout_ctx)
 
 static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 {
+       struct wpa_driver_test_data *drv = eloop_ctx;
        wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+       if (drv->pending_p2p_scan && drv->p2p) {
+#ifdef CONFIG_P2P
+               size_t i;
+               for (i = 0; i < drv->num_scanres; i++) {
+                       struct wpa_scan_res *bss = drv->scanres[i];
+                       if (p2p_scan_res_handler(drv->p2p, bss->bssid,
+                                                bss->freq, bss->level,
+                                                (const u8 *) (bss + 1),
+                                                bss->ie_len) > 0)
+                               return;
+               }
+               p2p_scan_res_handled(drv->p2p);
+#endif /* CONFIG_P2P */
+               return;
+       }
        wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
 }
 
@@ -1487,6 +1551,7 @@ static int wpa_driver_test_associate(
                   __func__, priv, params->freq, params->pairwise_suite,
                   params->group_suite, params->key_mgmt_suite,
                   params->auth_alg, params->mode);
+       wpa_driver_update_mode(drv, params->mode == IEEE80211_MODE_AP);
        if (params->bssid) {
                wpa_printf(MSG_DEBUG, "   bssid=" MACSTR,
                           MAC2STR(params->bssid));
@@ -1848,6 +1913,8 @@ static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv,
 {
        int freq = 0, own_freq;
        union wpa_event_data event;
+       const struct ieee80211_mgmt *mgmt;
+       u16 fc;
        struct test_driver_bss *bss;
 
        bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
@@ -1885,23 +1952,45 @@ static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv,
        event.mlme_rx.freq = freq;
        wpa_supplicant_event(drv->ctx, EVENT_MLME_RX, &event);
 
-       if (drv->probe_req_report && data_len >= 24) {
-               const struct ieee80211_mgmt *mgmt;
-               u16 fc;
+       mgmt = (const struct ieee80211_mgmt *) data;
+       fc = le_to_host16(mgmt->frame_control);
 
-               mgmt = (const struct ieee80211_mgmt *) data;
-               fc = le_to_host16(mgmt->frame_control);
+       if (drv->probe_req_report && data_len >= 24) {
                if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
                    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) {
                        os_memset(&event, 0, sizeof(event));
                        event.rx_probe_req.sa = mgmt->sa;
+                       event.rx_probe_req.da = mgmt->da;
+                       event.rx_probe_req.bssid = mgmt->bssid;
                        event.rx_probe_req.ie = mgmt->u.probe_req.variable;
                        event.rx_probe_req.ie_len =
                                data_len - (mgmt->u.probe_req.variable - data);
                        wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ,
                                             &event);
+#ifdef CONFIG_P2P
+                       if (drv->p2p)
+                               p2p_probe_req_rx(drv->p2p, mgmt->sa,
+                                                mgmt->da, mgmt->bssid,
+                                                event.rx_probe_req.ie,
+                                                event.rx_probe_req.ie_len);
+#endif /* CONFIG_P2P */
                }
        }
+
+#ifdef CONFIG_P2P
+       if (drv->p2p &&
+           WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+           WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
+               size_t hdr_len;
+               hdr_len = (const u8 *)
+                       &mgmt->u.action.u.vs_public_action.action - data;
+               p2p_rx_action(drv->p2p, mgmt->da, mgmt->sa, mgmt->bssid,
+                             mgmt->u.action.category,
+                             &mgmt->u.action.u.vs_public_action.action,
+                             data_len - hdr_len, freq);
+       }
+#endif /* CONFIG_P2P */
+
 }
 
 
@@ -1917,6 +2006,29 @@ static void wpa_driver_test_scan_cmd(struct wpa_driver_test_data *drv,
        bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
 
        /* data: optional [ STA-addr | ' ' | IEs(hex) ] */
+#ifdef CONFIG_P2P
+       if (drv->probe_req_report && drv->p2p && data_len) {
+               const char *d = (const char *) data;
+               u8 sa[ETH_ALEN];
+               u8 ie[512];
+               size_t ielen;
+
+               if (hwaddr_aton(d, sa))
+                       return;
+               d += 18;
+               while (*d == ' ')
+                       d++;
+               ielen = os_strlen(d) / 2;
+               if (ielen > sizeof(ie))
+                       ielen = sizeof(ie);
+               if (hexstr2bin(d, ie, ielen) < 0)
+                       ielen = 0;
+               drv->probe_from = from;
+               drv->probe_from_len = fromlen;
+               p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen);
+               drv->probe_from = NULL;
+       }
+#endif /* CONFIG_P2P */
 
        if (!drv->ibss)
                return;
@@ -2073,6 +2185,12 @@ static void wpa_driver_test_deinit(void *priv)
        struct test_client_socket *cli, *prev;
        int i;
 
+#ifdef CONFIG_P2P
+       if (drv->p2p)
+               p2p_deinit(drv->p2p);
+       wpabuf_free(drv->pending_action_tx);
+#endif /* CONFIG_P2P */
+
        cli = drv->cli;
        while (cli) {
                prev = cli;
@@ -2269,12 +2387,12 @@ static int wpa_driver_test_set_param(void *priv, const char *param)
                drv->use_associnfo = 1;
        }
 
-#ifdef CONFIG_CLIENT_MLME
-       if (os_strstr(param, "use_mlme=1")) {
-               wpa_printf(MSG_DEBUG, "test_driver: Use internal MLME");
-               drv->use_mlme = 1;
+       if (os_strstr(param, "p2p_mgmt=1")) {
+               wpa_printf(MSG_DEBUG, "test_driver: Use internal P2P "
+                          "management");
+               if (wpa_driver_test_init_p2p(drv) < 0)
+                       return -1;
        }
-#endif /* CONFIG_CLIENT_MLME */
 
        return 0;
 }
@@ -2382,9 +2500,12 @@ static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa)
        capa->auth = WPA_DRIVER_AUTH_OPEN |
                WPA_DRIVER_AUTH_SHARED |
                WPA_DRIVER_AUTH_LEAP;
-       if (drv->use_mlme)
-               capa->flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME;
+       if (drv->p2p)
+               capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT;
        capa->flags |= WPA_DRIVER_FLAGS_AP;
+       capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
+       capa->flags |= WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE;
+       capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
        capa->max_scan_ssids = 2;
        capa->max_remain_on_chan = 60000;
 
@@ -2408,50 +2529,6 @@ static int wpa_driver_test_mlme_setprotection(void *priv, const u8 *addr,
 }
 
 
-static int wpa_driver_test_set_channel(void *priv,
-                                      enum hostapd_hw_mode phymode,
-                                      int chan, int freq)
-{
-       struct test_driver_bss *dbss = priv;
-       struct wpa_driver_test_data *drv = dbss->drv;
-       wpa_printf(MSG_DEBUG, "%s: phymode=%d chan=%d freq=%d",
-                  __func__, phymode, chan, freq);
-       drv->current_freq = freq;
-       return 0;
-}
-
-
-static int wpa_driver_test_mlme_add_sta(void *priv, const u8 *addr,
-                                       const u8 *supp_rates,
-                                       size_t supp_rates_len)
-{
-       wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr));
-       return 0;
-}
-
-
-static int wpa_driver_test_mlme_remove_sta(void *priv, const u8 *addr)
-{
-       wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr));
-       return 0;
-}
-
-
-static int wpa_driver_test_set_ssid(void *priv, const u8 *ssid,
-                                   size_t ssid_len)
-{
-       wpa_printf(MSG_DEBUG, "%s", __func__);
-       return 0;
-}
-
-
-static int wpa_driver_test_set_bssid(void *priv, const u8 *bssid)
-{
-       wpa_printf(MSG_DEBUG, "%s: bssid=" MACSTR, __func__, MAC2STR(bssid));
-       return 0;
-}
-
-
 static void * wpa_driver_test_global_init(void)
 {
        struct wpa_driver_test_global *global;
@@ -2591,9 +2668,11 @@ static int wpa_driver_test_set_freq(void *priv,
 
 
 static int wpa_driver_test_send_action(void *priv, unsigned int freq,
+                                      unsigned int wait,
                                       const u8 *dst, const u8 *src,
                                       const u8 *bssid,
-                                      const u8 *data, size_t data_len)
+                                      const u8 *data, size_t data_len,
+                                      int no_cck)
 {
        struct test_driver_bss *dbss = priv;
        struct wpa_driver_test_data *drv = dbss->drv;
@@ -2626,12 +2705,39 @@ static int wpa_driver_test_send_action(void *priv, unsigned int freq,
        os_memcpy(hdr->addr2, src, ETH_ALEN);
        os_memcpy(hdr->addr3, bssid, ETH_ALEN);
 
-       ret = wpa_driver_test_send_mlme(priv, buf, 24 + data_len);
+       ret = wpa_driver_test_send_mlme(priv, buf, 24 + data_len, 0);
        os_free(buf);
        return ret;
 }
 
 
+#ifdef CONFIG_P2P
+static void test_send_action_cb(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_driver_test_data *drv = eloop_ctx;
+
+       if (drv->pending_action_tx == NULL)
+               return;
+
+       if (drv->off_channel_freq != drv->pending_action_freq) {
+               wpa_printf(MSG_DEBUG, "P2P: Pending Action frame TX "
+                          "waiting for another freq=%u",
+                          drv->pending_action_freq);
+               return;
+       }
+       wpa_printf(MSG_DEBUG, "P2P: Sending pending Action frame to "
+                  MACSTR, MAC2STR(drv->pending_action_dst));
+       wpa_driver_test_send_action(drv, drv->pending_action_freq, 0,
+                                   drv->pending_action_dst,
+                                   drv->pending_action_src,
+                                   drv->pending_action_bssid,
+                                   wpabuf_head(drv->pending_action_tx),
+                                   wpabuf_len(drv->pending_action_tx),
+                                   drv->pending_action_no_cck);
+}
+#endif /* CONFIG_P2P */
+
+
 static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx)
 {
        struct wpa_driver_test_data *drv = eloop_ctx;
@@ -2642,9 +2748,13 @@ static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx)
        os_memset(&data, 0, sizeof(data));
        data.remain_on_channel.freq = drv->remain_on_channel_freq;
        data.remain_on_channel.duration = drv->remain_on_channel_duration;
-       wpa_supplicant_event(drv->ctx, EVENT_CANCEL_REMAIN_ON_CHANNEL, &data);
+
+       if (drv->p2p)
+               drv->off_channel_freq = 0;
 
        drv->remain_on_channel_freq = 0;
+
+       wpa_supplicant_event(drv->ctx, EVENT_CANCEL_REMAIN_ON_CHANNEL, &data);
 }
 
 
@@ -2675,6 +2785,18 @@ static int wpa_driver_test_remain_on_channel(void *priv, unsigned int freq,
        data.remain_on_channel.duration = duration;
        wpa_supplicant_event(drv->ctx, EVENT_REMAIN_ON_CHANNEL, &data);
 
+#ifdef CONFIG_P2P
+       if (drv->p2p) {
+               drv->off_channel_freq = drv->remain_on_channel_freq;
+               test_send_action_cb(drv, NULL);
+               if (drv->off_channel_freq == drv->pending_listen_freq) {
+                       p2p_listen_cb(drv->p2p, drv->pending_listen_freq,
+                                     drv->pending_listen_duration);
+                       drv->pending_listen_freq = 0;
+               }
+       }
+#endif /* CONFIG_P2P */
+
        return 0;
 }
 
@@ -2702,6 +2824,461 @@ static int wpa_driver_test_probe_req_report(void *priv, int report)
 }
 
 
+#ifdef CONFIG_P2P
+
+static int wpa_driver_test_p2p_find(void *priv, unsigned int timeout, int type)
+{
+       struct wpa_driver_test_data *drv = priv;
+       wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout);
+       if (!drv->p2p)
+               return -1;
+       return p2p_find(drv->p2p, timeout, type, 0, NULL);
+}
+
+
+static int wpa_driver_test_p2p_stop_find(void *priv)
+{
+       struct wpa_driver_test_data *drv = priv;
+       wpa_printf(MSG_DEBUG, "%s", __func__);
+       if (!drv->p2p)
+               return -1;
+       p2p_stop_find(drv->p2p);
+       return 0;
+}
+
+
+static int wpa_driver_test_p2p_listen(void *priv, unsigned int timeout)
+{
+       struct wpa_driver_test_data *drv = priv;
+       wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout);
+       if (!drv->p2p)
+               return -1;
+       return p2p_listen(drv->p2p, timeout);
+}
+
+
+static int wpa_driver_test_p2p_connect(void *priv, const u8 *peer_addr,
+                                      int wps_method, int go_intent,
+                                      const u8 *own_interface_addr,
+                                      unsigned int force_freq,
+                                      int persistent_group)
+{
+       struct wpa_driver_test_data *drv = priv;
+       wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR " wps_method=%d "
+                  "go_intent=%d "
+                  "own_interface_addr=" MACSTR " force_freq=%u "
+                  "persistent_group=%d)",
+                  __func__, MAC2STR(peer_addr), wps_method, go_intent,
+                  MAC2STR(own_interface_addr), force_freq, persistent_group);
+       if (!drv->p2p)
+               return -1;
+       return p2p_connect(drv->p2p, peer_addr, wps_method, go_intent,
+                          own_interface_addr, force_freq, persistent_group);
+}
+
+
+static int wpa_driver_test_wps_success_cb(void *priv, const u8 *peer_addr)
+{
+       struct wpa_driver_test_data *drv = priv;
+       wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR ")",
+                  __func__, MAC2STR(peer_addr));
+       if (!drv->p2p)
+               return -1;
+       p2p_wps_success_cb(drv->p2p, peer_addr);
+       return 0;
+}
+
+
+static int wpa_driver_test_p2p_group_formation_failed(void *priv)
+{
+       struct wpa_driver_test_data *drv = priv;
+       wpa_printf(MSG_DEBUG, "%s", __func__);
+       if (!drv->p2p)
+               return -1;
+       p2p_group_formation_failed(drv->p2p);
+       return 0;
+}
+
+
+static int wpa_driver_test_p2p_set_params(void *priv,
+                                         const struct p2p_params *params)
+{
+       struct wpa_driver_test_data *drv = priv;
+       wpa_printf(MSG_DEBUG, "%s", __func__);
+       if (!drv->p2p)
+               return -1;
+       if (p2p_set_dev_name(drv->p2p, params->dev_name) < 0 ||
+           p2p_set_pri_dev_type(drv->p2p, params->pri_dev_type) < 0 ||
+           p2p_set_sec_dev_types(drv->p2p, params->sec_dev_type,
+                                 params->num_sec_dev_types) < 0)
+               return -1;
+       return 0;
+}
+
+
+static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
+                        unsigned int num_req_dev_types,
+                        const u8 *req_dev_types)
+{
+       struct wpa_driver_test_data *drv = ctx;
+       struct wpa_driver_scan_params params;
+       int ret;
+       struct wpabuf *wps_ie, *ies;
+       int social_channels[] = { 2412, 2437, 2462, 0, 0 };
+       size_t ielen;
+
+       wpa_printf(MSG_DEBUG, "%s(type=%d freq=%d)",
+                  __func__, type, freq);
+
+       os_memset(&params, 0, sizeof(params));
+
+       /* P2P Wildcard SSID */
+       params.num_ssids = 1;
+       params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
+       params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+
+#if 0 /* TODO: WPS IE */
+       wpa_s->wps->dev.p2p = 1;
+       wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
+                                       WPS_REQ_ENROLLEE);
+#else
+       wps_ie = wpabuf_alloc(1);
+#endif
+       if (wps_ie == NULL)
+               return -1;
+
+       ielen = p2p_scan_ie_buf_len(drv->p2p);
+       ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
+       if (ies == NULL) {
+               wpabuf_free(wps_ie);
+               return -1;
+       }
+       wpabuf_put_buf(ies, wps_ie);
+       wpabuf_free(wps_ie);
+
+       p2p_scan_ie(drv->p2p, ies);
+
+       params.extra_ies = wpabuf_head(ies);
+       params.extra_ies_len = wpabuf_len(ies);
+
+       switch (type) {
+       case P2P_SCAN_SOCIAL:
+               params.freqs = social_channels;
+               break;
+       case P2P_SCAN_FULL:
+               break;
+       case P2P_SCAN_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;
+       }
+
+       drv->pending_p2p_scan = 1;
+       ret = wpa_driver_test_scan(drv, &params);
+
+       wpabuf_free(ies);
+
+       return ret;
+}
+
+
+static int test_send_action(void *ctx, unsigned int freq, const u8 *dst,
+                           const u8 *src, const u8 *bssid, const u8 *buf,
+                           size_t len, unsigned int wait_time)
+{
+       struct wpa_driver_test_data *drv = ctx;
+
+       wpa_printf(MSG_DEBUG, "%s(freq=%u dst=" MACSTR " src=" MACSTR
+                  " bssid=" MACSTR " len=%d",
+                  __func__, freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
+                  (int) len);
+       if (freq <= 0) {
+               wpa_printf(MSG_WARNING, "P2P: No frequency specified for "
+                          "action frame TX");
+               return -1;
+       }
+
+       if (drv->pending_action_tx) {
+               wpa_printf(MSG_DEBUG, "P2P: Dropped pending Action frame TX "
+                          "to " MACSTR, MAC2STR(drv->pending_action_dst));
+               wpabuf_free(drv->pending_action_tx);
+       }
+       drv->pending_action_tx = wpabuf_alloc(len);
+       if (drv->pending_action_tx == NULL)
+               return -1;
+       wpabuf_put_data(drv->pending_action_tx, buf, len);
+       os_memcpy(drv->pending_action_src, src, ETH_ALEN);
+       os_memcpy(drv->pending_action_dst, dst, ETH_ALEN);
+       os_memcpy(drv->pending_action_bssid, bssid, ETH_ALEN);
+       drv->pending_action_freq = freq;
+       drv->pending_action_no_cck = 1;
+
+       if (drv->off_channel_freq == freq) {
+               /* Already on requested channel; send immediately */
+               /* TODO: Would there ever be need to extend the current
+                * duration on the channel? */
+               eloop_cancel_timeout(test_send_action_cb, drv, NULL);
+               eloop_register_timeout(0, 0, test_send_action_cb, drv, NULL);
+               return 0;
+       }
+
+       wpa_printf(MSG_DEBUG, "P2P: Schedule Action frame to be transmitted "
+                  "once the driver gets to the requested channel");
+       if (wpa_driver_test_remain_on_channel(drv, freq, wait_time) < 0) {
+               wpa_printf(MSG_DEBUG, "P2P: Failed to request driver "
+                          "to remain on channel (%u MHz) for Action "
+                          "Frame TX", freq);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+static void test_send_action_done(void *ctx)
+{
+       wpa_printf(MSG_DEBUG, "%s", __func__);
+       /* TODO */
+}
+
+
+static void test_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
+{
+       struct wpa_driver_test_data *drv = ctx;
+       union wpa_event_data event;
+       wpa_printf(MSG_DEBUG, "%s", __func__);
+       os_memset(&event, 0, sizeof(event));
+       event.p2p_go_neg_completed.res = res;
+       wpa_supplicant_event(drv->ctx, EVENT_P2P_GO_NEG_COMPLETED, &event);
+}
+
+
+static void test_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id)
+{
+       struct wpa_driver_test_data *drv = ctx;
+       union wpa_event_data event;
+       wpa_printf(MSG_DEBUG, "%s(src=" MACSTR ")", __func__, MAC2STR(src));
+       os_memset(&event, 0, sizeof(event));
+       event.p2p_go_neg_req_rx.src = src;
+       event.p2p_go_neg_req_rx.dev_passwd_id = dev_passwd_id;
+       wpa_supplicant_event(drv->ctx, EVENT_P2P_GO_NEG_REQ_RX, &event);
+}
+
+
+static void test_dev_found(void *ctx, const u8 *addr,
+                          const struct p2p_peer_info *info, int new_device)
+{
+       struct wpa_driver_test_data *drv = ctx;
+       union wpa_event_data event;
+       char devtype[WPS_DEV_TYPE_BUFSIZE];
+       wpa_printf(MSG_DEBUG, "%s(" MACSTR " p2p_dev_addr=" MACSTR
+                  " pri_dev_type=%s name='%s' config_methods=0x%x "
+                  "dev_capab=0x%x group_capab=0x%x)",
+                  __func__, MAC2STR(addr), MAC2STR(info->p2p_device_addr),
+                  wps_dev_type_bin2str(info->pri_dev_type, devtype,
+                                       sizeof(devtype)),
+                  info->device_name, info->config_methods, info->dev_capab,
+                  info->group_capab);
+
+       os_memset(&event, 0, sizeof(event));
+       event.p2p_dev_found.addr = addr;
+       event.p2p_dev_found.dev_addr = info->p2p_device_addr;
+       event.p2p_dev_found.pri_dev_type = info->pri_dev_type;
+       event.p2p_dev_found.dev_name = info->device_name;
+       event.p2p_dev_found.config_methods = info->config_methods;
+       event.p2p_dev_found.dev_capab = info->dev_capab;
+       event.p2p_dev_found.group_capab = info->group_capab;
+       wpa_supplicant_event(drv->ctx, EVENT_P2P_DEV_FOUND, &event);
+}
+
+
+static int test_start_listen(void *ctx, unsigned int freq,
+                            unsigned int duration,
+                            const struct wpabuf *probe_resp_ie)
+{
+       struct wpa_driver_test_data *drv = ctx;
+
+       wpa_printf(MSG_DEBUG, "%s(freq=%u duration=%u)",
+                  __func__, freq, duration);
+
+       if (wpa_driver_test_probe_req_report(drv, 1) < 0)
+               return -1;
+
+       drv->pending_listen_freq = freq;
+       drv->pending_listen_duration = duration;
+
+       if (wpa_driver_test_remain_on_channel(drv, freq, duration) < 0) {
+               drv->pending_listen_freq = 0;
+               return -1;
+       }
+
+       return 0;
+}
+
+
+static void test_stop_listen(void *ctx)
+{
+       wpa_printf(MSG_DEBUG, "%s", __func__);
+       /* TODO */
+}
+
+
+static int test_send_probe_resp(void *ctx, const struct wpabuf *buf)
+{
+       struct wpa_driver_test_data *drv = ctx;
+       char resp[512], *pos, *end;
+       int ret;
+       const struct ieee80211_mgmt *mgmt;
+       const u8 *ie, *ie_end;
+
+       wpa_printf(MSG_DEBUG, "%s", __func__);
+       wpa_hexdump_buf(MSG_MSGDUMP, "Probe Response", buf);
+       if (wpabuf_len(buf) < 24)
+               return -1;
+       if (!drv->probe_from) {
+               wpa_printf(MSG_DEBUG, "%s: probe_from not set", __func__);
+               return -1;
+       }
+
+       pos = resp;
+       end = resp + sizeof(resp);
+
+       mgmt = wpabuf_head(buf);
+
+       /* reply: SCANRESP BSSID SSID IEs */
+       ret = os_snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
+                         MAC2STR(mgmt->bssid));
+       if (ret < 0 || ret >= end - pos)
+               return -1;
+       pos += ret;
+
+       ie = mgmt->u.probe_resp.variable;
+       ie_end = wpabuf_head_u8(buf) + wpabuf_len(buf);
+       if (ie_end - ie < 2 || ie[0] != WLAN_EID_SSID ||
+           ie + 2 + ie[1] > ie_end)
+               return -1;
+       pos += wpa_snprintf_hex(pos, end - pos, ie + 2, ie[1]);
+
+       ret = os_snprintf(pos, end - pos, " ");
+       if (ret < 0 || ret >= end - pos)
+               return -1;
+       pos += ret;
+       pos += wpa_snprintf_hex(pos, end - pos, ie, ie_end - ie);
+
+       sendto(drv->test_socket, resp, pos - resp, 0,
+              drv->probe_from, drv->probe_from_len);
+
+       return 0;
+}
+
+
+static void test_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
+                           u16 update_indic, const u8 *tlvs, size_t tlvs_len)
+{
+       wpa_printf(MSG_DEBUG, "%s", __func__);
+       /* TODO */
+}
+
+
+static void test_sd_response(void *ctx, const u8 *sa, u16 update_indic,
+                            const u8 *tlvs, size_t tlvs_len)
+{
+       wpa_printf(MSG_DEBUG, "%s", __func__);
+       /* TODO */
+}
+
+
+static void test_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
+                              const u8 *dev_addr, const u8 *pri_dev_type,
+                              const char *dev_name, u16 supp_config_methods,
+                              u8 dev_capab, u8 group_capab,
+                              const u8 *group_id, size_t group_id_len)
+{
+       wpa_printf(MSG_DEBUG, "%s(peer=" MACSTR " config_methods=0x%x)",
+                  __func__, MAC2STR(peer), config_methods);
+       /* TODO */
+}
+
+
+static void test_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
+{
+       wpa_printf(MSG_DEBUG, "%s(peer=" MACSTR " config_methods=0x%x)",
+                  __func__, MAC2STR(peer), config_methods);
+       /* TODO */
+}
+
+#endif /* CONFIG_P2P */
+
+
+static int wpa_driver_test_init_p2p(struct wpa_driver_test_data *drv)
+{
+#ifdef CONFIG_P2P
+       struct p2p_config p2p;
+       unsigned int r;
+       int i;
+
+       os_memset(&p2p, 0, sizeof(p2p));
+       p2p.msg_ctx = drv->ctx;
+       p2p.cb_ctx = drv;
+       p2p.p2p_scan = test_p2p_scan;
+       p2p.send_action = test_send_action;
+       p2p.send_action_done = test_send_action_done;
+       p2p.go_neg_completed = test_go_neg_completed;
+       p2p.go_neg_req_rx = test_go_neg_req_rx;
+       p2p.dev_found = test_dev_found;
+       p2p.start_listen = test_start_listen;
+       p2p.stop_listen = test_stop_listen;
+       p2p.send_probe_resp = test_send_probe_resp;
+       p2p.sd_request = test_sd_request;
+       p2p.sd_response = test_sd_response;
+       p2p.prov_disc_req = test_prov_disc_req;
+       p2p.prov_disc_resp = test_prov_disc_resp;
+
+       os_memcpy(p2p.dev_addr, drv->own_addr, ETH_ALEN);
+
+       p2p.reg_class = 12; /* TODO: change depending on location */
+       /*
+        * Pick one of the social channels randomly as the listen
+        * channel.
+        */
+       os_get_random((u8 *) &r, sizeof(r));
+       p2p.channel = 1 + (r % 3) * 5;
+
+       /* TODO: change depending on location */
+       p2p.op_reg_class = 12;
+       /*
+        * For initial tests, pick the operation channel randomly.
+        * TODO: Use scan results (etc.) to select the best channel.
+        */
+       p2p.op_channel = 1 + r % 11;
+
+       os_memcpy(p2p.country, "US ", 3);
+
+       /* FIX: fetch available channels from the driver */
+       p2p.channels.reg_classes = 1;
+       p2p.channels.reg_class[0].reg_class = 12; /* US/12 = 2.4 GHz band */
+       p2p.channels.reg_class[0].channels = 11;
+       for (i = 0; i < 11; i++)
+               p2p.channels.reg_class[0].channel[i] = i + 1;
+
+       p2p.max_peers = 100;
+
+       drv->p2p = p2p_init(&p2p);
+       if (drv->p2p == NULL)
+               return -1;
+       return 0;
+#else /* CONFIG_P2P */
+       wpa_printf(MSG_INFO, "driver_test: P2P support not included");
+       return -1;
+#endif /* CONFIG_P2P */
+}
+
+
 const struct wpa_driver_ops wpa_driver_test_ops = {
        "test",
        "wpa_supplicant test driver",
@@ -2715,7 +3292,6 @@ const struct wpa_driver_ops wpa_driver_test_ops = {
        .get_hw_feature_data = wpa_driver_test_get_hw_feature_data,
        .if_add = test_driver_if_add,
        .if_remove = test_driver_if_remove,
-       .valid_bss_mask = test_driver_valid_bss_mask,
        .hapd_set_ssid = test_driver_set_ssid,
        .set_privacy = test_driver_set_privacy,
        .set_sta_vlan = test_driver_set_sta_vlan,
@@ -2734,11 +3310,6 @@ const struct wpa_driver_ops wpa_driver_test_ops = {
        .get_mac_addr = wpa_driver_test_get_mac_addr,
        .send_eapol = wpa_driver_test_send_eapol,
        .mlme_setprotection = wpa_driver_test_mlme_setprotection,
-       .set_channel = wpa_driver_test_set_channel,
-       .set_ssid = wpa_driver_test_set_ssid,
-       .set_bssid = wpa_driver_test_set_bssid,
-       .mlme_add_sta = wpa_driver_test_mlme_add_sta,
-       .mlme_remove_sta = wpa_driver_test_mlme_remove_sta,
        .get_scan_results2 = wpa_driver_test_get_scan_results2,
        .global_init = wpa_driver_test_global_init,
        .global_deinit = wpa_driver_test_global_deinit,
@@ -2750,4 +3321,14 @@ const struct wpa_driver_ops wpa_driver_test_ops = {
        .remain_on_channel = wpa_driver_test_remain_on_channel,
        .cancel_remain_on_channel = wpa_driver_test_cancel_remain_on_channel,
        .probe_req_report = wpa_driver_test_probe_req_report,
+#ifdef CONFIG_P2P
+       .p2p_find = wpa_driver_test_p2p_find,
+       .p2p_stop_find = wpa_driver_test_p2p_stop_find,
+       .p2p_listen = wpa_driver_test_p2p_listen,
+       .p2p_connect = wpa_driver_test_p2p_connect,
+       .wps_success_cb = wpa_driver_test_wps_success_cb,
+       .p2p_group_formation_failed =
+       wpa_driver_test_p2p_group_formation_failed,
+       .p2p_set_params = wpa_driver_test_p2p_set_params,
+#endif /* CONFIG_P2P */
 };
index de304ba..c11ee75 100644 (file)
 
 #include "includes.h"
 #include <sys/ioctl.h>
+#include <sys/types.h>
 #include <sys/stat.h>
+#include <fcntl.h>
 #include <net/if_arp.h>
 
-#include "wireless_copy.h"
+#include "linux_wext.h"
 #include "common.h"
 #include "eloop.h"
 #include "common/ieee802_11_defs.h"
 #include "priv_netlink.h"
 #include "netlink.h"
 #include "linux_ioctl.h"
+#include "rfkill.h"
 #include "driver.h"
 #include "driver_wext.h"
 
+#ifdef ANDROID
+#include "android_drv.h"
+#endif /* ANDROID */
 
 static int wpa_driver_wext_flush_pmkid(void *priv);
 static int wpa_driver_wext_get_range(void *priv);
@@ -299,6 +305,14 @@ wpa_driver_wext_event_wireless_custom(void *ctx, char *custom)
                }
                wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
 #endif /* CONFIG_PEERKEY */
+#ifdef ANDROID
+       } else if (os_strncmp(custom, "STOP", 4) == 0) {
+               wpa_msg(ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED");
+       } else if (os_strncmp(custom, "START", 5) == 0) {
+               wpa_msg(ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED");
+       } else if (os_strncmp(custom, "HANG", 4) == 0) {
+               wpa_msg(ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+#endif /* ANDROID */
        }
 }
 
@@ -634,6 +648,19 @@ static void wpa_driver_wext_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi,
                   (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
                   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
                   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+
+       if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
+               wpa_printf(MSG_DEBUG, "WEXT: Interface down");
+               drv->if_disabled = 1;
+               wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL);
+       }
+
+       if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
+               wpa_printf(MSG_DEBUG, "WEXT: Interface up");
+               drv->if_disabled = 0;
+               wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL);
+       }
+
        /*
         * Some drivers send the association event before the operup event--in
         * this case, lifting operstate in wpa_driver_wext_set_operstate()
@@ -687,6 +714,62 @@ static void wpa_driver_wext_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi,
 }
 
 
+static void wpa_driver_wext_rfkill_blocked(void *ctx)
+{
+       wpa_printf(MSG_DEBUG, "WEXT: RFKILL blocked");
+       /*
+        * This may be for any interface; use ifdown event to disable
+        * interface.
+        */
+}
+
+
+static void wpa_driver_wext_rfkill_unblocked(void *ctx)
+{
+       struct wpa_driver_wext_data *drv = ctx;
+       wpa_printf(MSG_DEBUG, "WEXT: RFKILL unblocked");
+       if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1)) {
+               wpa_printf(MSG_DEBUG, "WEXT: Could not set interface UP "
+                          "after rfkill unblock");
+               return;
+       }
+       /* rtnetlink ifup handler will report interface as enabled */
+}
+
+
+static void wext_get_phy_name(struct wpa_driver_wext_data *drv)
+{
+       /* Find phy (radio) to which this interface belongs */
+       char buf[90], *pos;
+       int f, rv;
+
+       drv->phyname[0] = '\0';
+       snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name",
+                drv->ifname);
+       f = open(buf, O_RDONLY);
+       if (f < 0) {
+               wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
+                          buf, strerror(errno));
+               return;
+       }
+
+       rv = read(f, drv->phyname, sizeof(drv->phyname) - 1);
+       close(f);
+       if (rv < 0) {
+               wpa_printf(MSG_DEBUG, "Could not read file %s: %s",
+                          buf, strerror(errno));
+               return;
+       }
+
+       drv->phyname[rv] = '\0';
+       pos = os_strchr(drv->phyname, '\n');
+       if (pos)
+               *pos = '\0';
+       wpa_printf(MSG_DEBUG, "wext: interface %s phy: %s",
+                  drv->ifname, drv->phyname);
+}
+
+
 /**
  * wpa_driver_wext_init - Initialize WE driver interface
  * @ctx: context to be used when calling wpa_supplicant functions,
@@ -698,6 +781,7 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname)
 {
        struct wpa_driver_wext_data *drv;
        struct netlink_config *cfg;
+       struct rfkill_config *rcfg;
        char path[128];
        struct stat buf;
 
@@ -711,6 +795,7 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname)
        if (stat(path, &buf) == 0) {
                wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected");
                drv->cfg80211 = 1;
+               wext_get_phy_name(drv);
        }
 
        drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
@@ -731,8 +816,27 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname)
                goto err2;
        }
 
+       rcfg = os_zalloc(sizeof(*rcfg));
+       if (rcfg == NULL)
+               goto err3;
+       rcfg->ctx = drv;
+       os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname));
+       rcfg->blocked_cb = wpa_driver_wext_rfkill_blocked;
+       rcfg->unblocked_cb = wpa_driver_wext_rfkill_unblocked;
+       drv->rfkill = rfkill_init(rcfg);
+       if (drv->rfkill == NULL) {
+               wpa_printf(MSG_DEBUG, "WEXT: RFKILL status not available");
+               os_free(rcfg);
+       }
+
        drv->mlme_sock = -1;
 
+#ifdef ANDROID
+       drv->errors = 0;
+       drv->driver_is_started = TRUE;
+       drv->bgscan_enabled = 0;
+#endif /* ANDROID */
+
        if (wpa_driver_wext_finish_drv_init(drv) < 0)
                goto err3;
 
@@ -741,6 +845,7 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname)
        return drv;
 
 err3:
+       rfkill_deinit(drv->rfkill);
        netlink_deinit(drv->netlink);
 err2:
        close(drv->ioctl_sock);
@@ -750,10 +855,29 @@ err1:
 }
 
 
+static void wpa_driver_wext_send_rfkill(void *eloop_ctx, void *timeout_ctx)
+{
+       wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
+}
+
+
 static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
 {
-       if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0)
-               return -1;
+       int send_rfkill_event = 0;
+
+       if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0) {
+               if (rfkill_is_blocked(drv->rfkill)) {
+                       wpa_printf(MSG_DEBUG, "WEXT: Could not yet enable "
+                                  "interface '%s' due to rfkill",
+                                  drv->ifname);
+                       drv->if_disabled = 1;
+                       send_rfkill_event = 1;
+               } else {
+                       wpa_printf(MSG_ERROR, "WEXT: Could not set "
+                                  "interface '%s' UP", drv->ifname);
+                       return -1;
+               }
+       }
 
        /*
         * Make sure that the driver does not have any obsolete PMKID entries.
@@ -773,13 +897,7 @@ static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
         * previous association the driver might have when the supplicant
         * starts up.
         */
-
-       /*
-        * August, 5th 2011. TIZEN
-        * broadcom driver returns scan abort due to disconnect after driver initialization
-        * Therefore, disconnect operation is blocked when initialization 
-        */
-       //wpa_driver_wext_disconnect(drv);
+       wpa_driver_wext_disconnect(drv);
 
        drv->ifindex = if_nametoindex(drv->ifname);
 
@@ -801,6 +919,11 @@ static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
        netlink_send_oper_ifla(drv->netlink, drv->ifindex,
                               1, IF_OPER_DORMANT);
 
+       if (send_rfkill_event) {
+               eloop_register_timeout(0, 0, wpa_driver_wext_send_rfkill,
+                                      drv, drv->ctx);
+       }
+
        return 0;
 }
 
@@ -828,6 +951,7 @@ void wpa_driver_wext_deinit(void *priv)
 
        netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
        netlink_deinit(drv->netlink);
+       rfkill_deinit(drv->rfkill);
 
        if (drv->mlme_sock >= 0)
                eloop_unregister_read_sock(drv->mlme_sock);
@@ -900,7 +1024,7 @@ int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params)
 
        /* Not all drivers generate "scan completed" wireless event, so try to
         * read results after a timeout. */
-       timeout = 5;
+       timeout = 10;
        if (drv->scan_complete_events) {
                /*
                 * The driver seems to deliver SIOCGIWSCAN events to notify
@@ -1046,7 +1170,8 @@ static void wext_get_scan_freq(struct iw_event *iwe,
 }
 
 
-static void wext_get_scan_qual(struct iw_event *iwe,
+static void wext_get_scan_qual(struct wpa_driver_wext_data *drv,
+                              struct iw_event *iwe,
                               struct wext_scan_data *res)
 {
        res->res.qual = iwe->u.qual.qual;
@@ -1060,6 +1185,14 @@ static void wext_get_scan_qual(struct iw_event *iwe,
                res->res.flags |= WPA_SCAN_NOISE_INVALID;
        if (iwe->u.qual.updated & IW_QUAL_DBM)
                res->res.flags |= WPA_SCAN_LEVEL_DBM;
+       if ((iwe->u.qual.updated & IW_QUAL_DBM) ||
+           ((iwe->u.qual.level != 0) &&
+            (iwe->u.qual.level > drv->max_level))) {
+               if (iwe->u.qual.level >= 64)
+                       res->res.level -= 0x100;
+               if (iwe->u.qual.noise >= 64)
+                       res->res.noise -= 0x100;
+       }
 }
 
 
@@ -1261,7 +1394,7 @@ static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res,
        tmp[res->num++] = r;
        res->res = tmp;
 }
-                                     
+
 
 /**
  * wpa_driver_wext_get_scan_results - Fetch the latest scan results
@@ -1271,7 +1404,7 @@ static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res,
 struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv)
 {
        struct wpa_driver_wext_data *drv = priv;
-       size_t ap_num = 0, len;
+       size_t len;
        int first;
        u8 *res_buf;
        struct iw_event iwe_buf, *iwe = &iwe_buf;
@@ -1283,7 +1416,6 @@ struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv)
        if (res_buf == NULL)
                return NULL;
 
-       ap_num = 0;
        first = 1;
 
        res = os_zalloc(sizeof(*res));
@@ -1335,7 +1467,7 @@ struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv)
                        wext_get_scan_freq(iwe, &data);
                        break;
                case IWEVQUAL:
-                       wext_get_scan_qual(iwe, &data);
+                       wext_get_scan_qual(drv, iwe, &data);
                        break;
                case SIOCGIWENCODE:
                        wext_get_scan_encode(iwe, &data);
@@ -1433,6 +1565,8 @@ static int wpa_driver_wext_get_range(void *priv)
                           "assuming WPA is not supported");
        }
 
+       drv->max_level = range->max_qual.level;
+
        os_free(range);
        return 0;
 }
@@ -1465,13 +1599,10 @@ static int wpa_driver_wext_set_psk(struct wpa_driver_wext_data *drv,
        ext->key_len = PMK_LEN;
        os_memcpy(&ext->key, psk, ext->key_len);
        ext->alg = IW_ENCODE_ALG_PMK;
-       errno =0;
+
        ret = ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr);
        if (ret < 0)
-       {
                perror("ioctl[SIOCSIWENCODEEXT] PMK");
-               wpa_printf(MSG_DEBUG, "ioctl [SIOCSIWENCODEEXT] error is [%s]",strerror(errno));
-       }
        os_free(ext);
 
        return ret;
@@ -1507,8 +1638,7 @@ static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg,
        iwr.u.encoding.pointer = (caddr_t) ext;
        iwr.u.encoding.length = sizeof(*ext) + key_len;
 
-       if (addr == NULL ||
-           os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
+       if (addr == NULL || is_broadcast_ether_addr(addr))
                ext->ext_flags |= IW_ENCODE_EXT_GROUP_KEY;
        if (set_tx)
                ext->ext_flags |= IW_ENCODE_EXT_SET_TX_KEY;
@@ -1711,8 +1841,10 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
 {
        struct iwreq iwr;
        const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+#ifndef ANDROID
        u8 ssid[32];
        int i;
+#endif /* ANDROID */
 
        /*
         * Only force-disconnect when the card is in infrastructure mode,
@@ -1727,46 +1859,47 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
        }
 
        if (iwr.u.mode == IW_MODE_INFRA) {
+               /* Clear the BSSID selection */
+               if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0) {
+                       wpa_printf(MSG_DEBUG, "WEXT: Failed to clear BSSID "
+                                  "selection on disconnect");
+               }
+
+               /*
+                * 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) {
                        /*
                         * cfg80211 supports SIOCSIWMLME commands, so there is
                         * no need for the random SSID hack, but clear the
-                        * BSSID and SSID.
+                        * SSID.
                         */
-                       if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 ||
-                           wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
+                       if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
                                wpa_printf(MSG_DEBUG, "WEXT: Failed to clear "
-                                          "to disconnect");
+                                          "SSID on disconnect");
                        }
                        return;
                }
-               /*
-                * Clear the BSSID selection and set a random SSID to make sure
-                * the driver will not be trying to associate with something
-                * even if it does not understand SIOCSIWMLME commands (or
-                * tries to associate automatically after deauth/disassoc).
-                */
 
                /*
-                * Oct, 21st. 2011. TIZEN
-                * broadcom driver returns scan abort due to disconnect
-                * Therefore, disconnect operation is blocked by using set_ssid
+                * Set a random SSID to make sure the driver will not be trying
+                * to associate with something even if it does not understand
+                * SIOCSIWMLME commands (or tries to associate automatically
+                * after deauth/disassoc).
                 */
-               /*
                for (i = 0; i < 32; i++)
                        ssid[i] = rand() & 0xFF;
-               */
-               /*
-               if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 ||
-                       wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) {
+               if (wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) {
                        wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus "
-                                  "BSSID/SSID to disconnect");
-               }
-               */
-               if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0) {
-                       wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus "
-                                          "BSSID/SSID to disconnect");
+                                  "SSID to disconnect");
                }
+#endif /* ANDROID */
+#endif
        }
 }
 
@@ -1913,20 +2046,11 @@ int wpa_driver_wext_associate(void *priv,
 
        if (wpa_driver_wext_set_drop_unencrypted(drv, params->drop_unencrypted)
            < 0)
-       {
-               wpa_printf(MSG_DEBUG, "wpa_driver_wext_set_drop_unencrypted fail");
                ret = -1;
-       }
        if (wpa_driver_wext_set_auth_alg(drv, params->auth_alg) < 0)
-       {
-               wpa_printf(MSG_DEBUG, "wpa_driver_wext_set_auth_alg fail");
                ret = -1;
-       }
        if (wpa_driver_wext_set_mode(drv, params->mode) < 0)
-       {
-               wpa_printf(MSG_DEBUG, "wpa_driver_wext_set_mode fail");
-               //ret = -1;
-       }
+               ret = -1;
 
        /*
         * If the driver did not support SIOCSIWAUTH, fallback to
@@ -1934,27 +2058,18 @@ int wpa_driver_wext_associate(void *priv,
         */
        if (drv->auth_alg_fallback &&
            wpa_driver_wext_auth_alg_fallback(drv, params) < 0)
-       {
-               wpa_printf(MSG_DEBUG, "wpa_driver_wext_auth_alg_fallback fail");
                ret = -1;
-       }
 
        if (!params->bssid &&
            wpa_driver_wext_set_bssid(drv, NULL) < 0)
-       {
-               wpa_printf(MSG_DEBUG, "wpa_driver_wext_set_bssid fail");
                ret = -1;
-       }
 
        /* TODO: should consider getting wpa version and cipher/key_mgmt suites
         * from configuration, not from here, where only the selected suite is
         * available */
        if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
            < 0)
-       {
-               wpa_printf(MSG_DEBUG, "wpa_driver_wext_set_gen_ie fail");
                ret = -1;
-       }
        if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
                value = IW_AUTH_WPA_VERSION_DISABLED;
        else if (params->wpa_ie[0] == WLAN_EID_RSN)
@@ -1963,41 +2078,26 @@ int wpa_driver_wext_associate(void *priv,
                value = IW_AUTH_WPA_VERSION_WPA;
        if (wpa_driver_wext_set_auth_param(drv,
                                           IW_AUTH_WPA_VERSION, value) < 0)
-       {
-               wpa_printf(MSG_DEBUG, "wpa_driver_wext_set_auth_param fail");
                ret = -1;
-       }
        value = wpa_driver_wext_cipher2wext(params->pairwise_suite);
        if (wpa_driver_wext_set_auth_param(drv,
                                           IW_AUTH_CIPHER_PAIRWISE, value) < 0)
-       {
-               wpa_printf(MSG_DEBUG, "wpa_driver_wext_set_auth_param fail");
                ret = -1;
-       }
        value = wpa_driver_wext_cipher2wext(params->group_suite);
        if (wpa_driver_wext_set_auth_param(drv,
                                           IW_AUTH_CIPHER_GROUP, value) < 0)
-       {
-               wpa_printf(MSG_DEBUG, "wpa_driver_wext_set_auth_param fail");
                ret = -1;
-       }
        value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite);
        if (wpa_driver_wext_set_auth_param(drv,
                                           IW_AUTH_KEY_MGMT, value) < 0)
-       {
-               wpa_printf(MSG_DEBUG, "wpa_driver_wext_set_auth_param fail");
                ret = -1;
-       }
        value = params->key_mgmt_suite != KEY_MGMT_NONE ||
                params->pairwise_suite != CIPHER_NONE ||
                params->group_suite != CIPHER_NONE ||
                params->wpa_ie_len;
        if (wpa_driver_wext_set_auth_param(drv,
                                           IW_AUTH_PRIVACY_INVOKED, value) < 0)
-       {
-               wpa_printf(MSG_DEBUG, "wpa_driver_wext_set_auth_param fail");
                ret = -1;
-       }
 
        /* Allow unencrypted EAPOL messages even if pairwise keys are set when
         * not using WPA. IEEE 802.1X specifies that these frames are not
@@ -2009,17 +2109,11 @@ int wpa_driver_wext_associate(void *priv,
                allow_unencrypted_eapol = 1;
 
        if (wpa_driver_wext_set_psk(drv, params->psk) < 0)
-       {
-               wpa_printf(MSG_DEBUG, "wpa_driver_wext_set_psk fail");
                ret = -1;
-       }
        if (wpa_driver_wext_set_auth_param(drv,
                                           IW_AUTH_RX_UNENCRYPTED_EAPOL,
                                           allow_unencrypted_eapol) < 0)
-       {
-               wpa_printf(MSG_DEBUG, "wpa_driver_wext_set_auth_param fail");
                ret = -1;
-       }
 #ifdef CONFIG_IEEE80211W
        switch (params->mgmt_frame_protection) {
        case NO_MGMT_FRAME_PROTECTION:
@@ -2033,34 +2127,19 @@ int wpa_driver_wext_associate(void *priv,
                break;
        };
        if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0)
-       {
-               wpa_printf(MSG_DEBUG, "wpa_driver_wext_set_auth_param fail");
                ret = -1;
-       }
 #endif /* CONFIG_IEEE80211W */
        if (params->freq && wpa_driver_wext_set_freq(drv, params->freq) < 0)
-       {
-               wpa_printf(MSG_DEBUG, "wpa_driver_wext_set_freq fail");
                ret = -1;
-       }
        if (!drv->cfg80211 &&
            wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
-       {
-               wpa_printf(MSG_DEBUG, "wpa_driver_wext_set_ssid fail");
                ret = -1;
-       }
        if (params->bssid &&
            wpa_driver_wext_set_bssid(drv, params->bssid) < 0)
-       {
-               wpa_printf(MSG_DEBUG, "wpa_driver_wext_set_bssid fail");
                ret = -1;
-       }
        if (drv->cfg80211 &&
            wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
-       {
-               wpa_printf(MSG_DEBUG, "wpa_driver_wext_set_ssid fail");
                ret = -1;
-       }
 
        return ret;
 }
@@ -2105,9 +2184,6 @@ int wpa_driver_wext_set_mode(void *priv, int mode)
        os_memset(&iwr, 0, sizeof(iwr));
        os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
        iwr.u.mode = new_mode;
-
-       wpa_printf(MSG_DEBUG, "[%s][%d] WiFi mode is [%s]",__FUNCTION__,__LINE__, (new_mode==IW_MODE_ADHOC)?"ADHOC":"INFRA");
-       
        if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) == 0) {
                ret = 0;
                goto done;
@@ -2115,7 +2191,6 @@ int wpa_driver_wext_set_mode(void *priv, int mode)
 
        if (errno != EBUSY) {
                perror("ioctl[SIOCSIWMODE]");
-               wpa_printf(MSG_DEBUG, "[%s][%d] error is [%d][%s]",__FUNCTION__,__LINE__,errno, strerror(errno));
                goto done;
        }
 
@@ -2125,13 +2200,11 @@ int wpa_driver_wext_set_mode(void *priv, int mode)
         */
        if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
                perror("ioctl[SIOCGIWMODE]");
-               wpa_printf(MSG_DEBUG, "[%s][%d]",__FUNCTION__,__LINE__);
                goto done;
        }
 
        if (iwr.u.mode == new_mode) {
                ret = 0;
-               wpa_printf(MSG_DEBUG, "[%s][%d]",__FUNCTION__,__LINE__);
                goto done;
        }
 
@@ -2139,10 +2212,7 @@ int wpa_driver_wext_set_mode(void *priv, int mode)
                /* Try to set the mode again while the interface is down */
                iwr.u.mode = new_mode;
                if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0)
-               {
-                       wpa_printf(MSG_DEBUG, "[%s][%d]",__FUNCTION__,__LINE__);
                        perror("ioctl[SIOCSIWMODE]");
-               }
                else
                        ret = 0;
 
@@ -2253,6 +2323,136 @@ int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv)
 }
 
 
+static const char * wext_get_radio_name(void *priv)
+{
+       struct wpa_driver_wext_data *drv = priv;
+       return drv->phyname;
+}
+
+
+#ifdef ANDROID
+
+static int android_wext_cmd(struct wpa_driver_wext_data *drv, const char *cmd)
+{
+       struct iwreq iwr;
+       char buf[MAX_DRV_CMD_SIZE];
+       int ret;
+
+       os_memset(&iwr, 0, sizeof(iwr));
+       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+       os_memset(buf, 0, sizeof(buf));
+       os_strlcpy(buf, cmd, sizeof(buf));
+
+       iwr.u.data.pointer = buf;
+       iwr.u.data.length = sizeof(buf);
+
+       ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr);
+
+       if (ret < 0) {
+               wpa_printf(MSG_ERROR, "%s failed (%d): %s", __func__, ret,
+                          cmd);
+               drv->errors++;
+               if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+                       drv->errors = 0;
+                       wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE
+                               "HANGED");
+               }
+               return ret;
+       }
+
+       drv->errors = 0;
+       return 0;
+}
+
+
+static int wext_sched_scan(void *priv, struct wpa_driver_scan_params *params,
+                          u32 interval)
+{
+       struct wpa_driver_wext_data *drv = priv;
+       struct iwreq iwr;
+       int ret = 0, i = 0, bp;
+       char buf[WEXT_PNO_MAX_COMMAND_SIZE];
+
+       bp = WEXT_PNOSETUP_HEADER_SIZE;
+       os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
+       buf[bp++] = WEXT_PNO_TLV_PREFIX;
+       buf[bp++] = WEXT_PNO_TLV_VERSION;
+       buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
+       buf[bp++] = WEXT_PNO_TLV_RESERVED;
+
+       while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
+               /*
+                * Check that there is enough space needed for 1 more SSID, the
+                * other sections and null termination.
+                */
+               if ((bp + WEXT_PNO_SSID_HEADER_SIZE + IW_ESSID_MAX_SIZE +
+                    WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
+                       break;
+
+               wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
+                                 params->ssids[i].ssid,
+                                 params->ssids[i].ssid_len);
+               buf[bp++] = WEXT_PNO_SSID_SECTION;
+               buf[bp++] = params->ssids[i].ssid_len;
+               os_memcpy(&buf[bp], params->ssids[i].ssid,
+                         params->ssids[i].ssid_len);
+               bp += params->ssids[i].ssid_len;
+               i++;
+       }
+
+       buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
+       /* TODO: consider using interval parameter (interval in msec) instead
+        * of hardcoded value here */
+       os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
+                   WEXT_PNO_SCAN_INTERVAL);
+       bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
+
+       buf[bp++] = WEXT_PNO_REPEAT_SECTION;
+       os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
+                   WEXT_PNO_REPEAT);
+       bp += WEXT_PNO_REPEAT_LENGTH;
+
+       buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
+       os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
+                   WEXT_PNO_MAX_REPEAT);
+       bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
+
+       os_memset(&iwr, 0, sizeof(iwr));
+       os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+       iwr.u.data.pointer = buf;
+       iwr.u.data.length = bp;
+
+       ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr);
+       if (ret < 0) {
+               wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
+                          ret);
+               drv->errors++;
+               if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+                       drv->errors = 0;
+                       wpa_msg(drv->ctx, MSG_INFO,
+                               WPA_EVENT_DRIVER_STATE "HANGED");
+               }
+               return ret;
+       }
+
+       drv->errors = 0;
+       drv->bgscan_enabled = 1;
+
+       return android_wext_cmd(drv, "PNOFORCE 1");
+}
+
+
+static int wext_stop_sched_scan(void *priv)
+{
+       struct wpa_driver_wext_data *drv = priv;
+       drv->bgscan_enabled = 0;
+       return android_wext_cmd(drv, "PNOFORCE 0");
+}
+
+#endif /* ANDROID */
+
+
 const struct wpa_driver_ops wpa_driver_wext_ops = {
        .name = "wext",
        .desc = "Linux wireless extensions (generic)",
@@ -2272,4 +2472,9 @@ const struct wpa_driver_ops wpa_driver_wext_ops = {
        .flush_pmkid = wpa_driver_wext_flush_pmkid,
        .get_capa = wpa_driver_wext_get_capa,
        .set_operstate = wpa_driver_wext_set_operstate,
+       .get_radio_name = wext_get_radio_name,
+#ifdef ANDROID
+       .sched_scan = wext_sched_scan,
+       .stop_sched_scan = wext_stop_sched_scan,
+#endif /* ANDROID */
 };
index 602c7e1..8bcbee6 100644 (file)
@@ -23,9 +23,12 @@ struct wpa_driver_wext_data {
        int ioctl_sock;
        int mlme_sock;
        char ifname[IFNAMSIZ + 1];
+       char phyname[32];
        int ifindex;
        int ifindex2;
        int if_removed;
+       int if_disabled;
+       struct rfkill_data *rfkill;
        u8 *assoc_req_ies;
        size_t assoc_req_ies_len;
        u8 *assoc_resp_ies;
@@ -45,6 +48,14 @@ struct wpa_driver_wext_data {
        int scan_complete_events;
 
        int cfg80211; /* whether driver is using cfg80211 */
+
+       u8 max_level;
+
+#ifdef ANDROID
+       int errors;
+       int driver_is_started;
+       int bgscan_enabled;
+#endif /* ANDROID */
 };
 
 int wpa_driver_wext_get_bssid(void *priv, u8 *bssid);
index 2b197f0..618db26 100644 (file)
@@ -24,6 +24,9 @@
 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
 #include <net/if_dl.h>
 #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */
+#ifdef __sun__
+#include <sys/sockio.h>
+#endif /* __sun__ */
 
 #include "common.h"
 #include "eloop.h"
@@ -311,7 +314,7 @@ static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr)
 
 static int wired_send_eapol(void *priv, const u8 *addr,
                            const u8 *data, size_t data_len, int encrypt,
-                           const u8 *own_addr)
+                           const u8 *own_addr, u32 flags)
 {
        struct wpa_driver_wired_data *drv = priv;
        struct ieee8023_hdr *hdr;
@@ -462,6 +465,10 @@ static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
        struct ifreq ifr;
        int s;
 
+#ifdef __sun__
+       return -1;
+#endif /* __sun__ */
+
        s = socket(PF_INET, SOCK_DGRAM, 0);
        if (s < 0) {
                perror("socket");
index bffbbde..667ea22 100644 (file)
@@ -24,25 +24,9 @@ extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */
 #ifdef CONFIG_DRIVER_HOSTAP
 extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
 #endif /* CONFIG_DRIVER_HOSTAP */
-#ifdef CONFIG_DRIVER_HERMES
-extern struct wpa_driver_ops wpa_driver_hermes_ops; /* driver_hermes.c */
-#endif /* CONFIG_DRIVER_HERMES */
 #ifdef CONFIG_DRIVER_MADWIFI
 extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */
 #endif /* CONFIG_DRIVER_MADWIFI */
-#ifdef CONFIG_DRIVER_ATMEL
-extern struct wpa_driver_ops wpa_driver_atmel_ops; /* driver_atmel.c */
-#endif /* CONFIG_DRIVER_ATMEL */
-#ifdef CONFIG_DRIVER_NDISWRAPPER
-/* driver_ndiswrapper.c */
-extern struct wpa_driver_ops wpa_driver_ndiswrapper_ops;
-#endif /* CONFIG_DRIVER_NDISWRAPPER */
-#ifdef CONFIG_DRIVER_BROADCOM
-extern struct wpa_driver_ops wpa_driver_broadcom_ops; /* driver_broadcom.c */
-#endif /* CONFIG_DRIVER_BROADCOM */
-#ifdef CONFIG_DRIVER_IPW
-extern struct wpa_driver_ops wpa_driver_ipw_ops; /* driver_ipw.c */
-#endif /* CONFIG_DRIVER_IPW */
 #ifdef CONFIG_DRIVER_BSD
 extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
 #endif /* CONFIG_DRIVER_BSD */
@@ -55,15 +39,6 @@ extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */
 #ifdef CONFIG_DRIVER_TEST
 extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */
 #endif /* CONFIG_DRIVER_TEST */
-#ifdef CONFIG_DRIVER_RALINK
-extern struct wpa_driver_ops wpa_driver_ralink_ops; /* driver_ralink.c */
-#endif /* CONFIG_DRIVER_RALINK */
-#ifdef CONFIG_DRIVER_OSX
-extern struct wpa_driver_ops wpa_driver_osx_ops; /* driver_osx.m */
-#endif /* CONFIG_DRIVER_OSX */
-#ifdef CONFIG_DRIVER_IPHONE
-extern struct wpa_driver_ops wpa_driver_iphone_ops; /* driver_iphone.m */
-#endif /* CONFIG_DRIVER_IPHONE */
 #ifdef CONFIG_DRIVER_ROBOSWITCH
 /* driver_roboswitch.c */
 extern struct wpa_driver_ops wpa_driver_roboswitch_ops;
@@ -87,24 +62,9 @@ struct wpa_driver_ops *wpa_drivers[] =
 #ifdef CONFIG_DRIVER_HOSTAP
        &wpa_driver_hostap_ops,
 #endif /* CONFIG_DRIVER_HOSTAP */
-#ifdef CONFIG_DRIVER_HERMES
-       &wpa_driver_hermes_ops,
-#endif /* CONFIG_DRIVER_HERMES */
 #ifdef CONFIG_DRIVER_MADWIFI
        &wpa_driver_madwifi_ops,
 #endif /* CONFIG_DRIVER_MADWIFI */
-#ifdef CONFIG_DRIVER_ATMEL
-       &wpa_driver_atmel_ops,
-#endif /* CONFIG_DRIVER_ATMEL */
-#ifdef CONFIG_DRIVER_NDISWRAPPER
-       &wpa_driver_ndiswrapper_ops,
-#endif /* CONFIG_DRIVER_NDISWRAPPER */
-#ifdef CONFIG_DRIVER_BROADCOM
-       &wpa_driver_broadcom_ops,
-#endif /* CONFIG_DRIVER_BROADCOM */
-#ifdef CONFIG_DRIVER_IPW
-       &wpa_driver_ipw_ops,
-#endif /* CONFIG_DRIVER_IPW */
 #ifdef CONFIG_DRIVER_BSD
        &wpa_driver_bsd_ops,
 #endif /* CONFIG_DRIVER_BSD */
@@ -117,15 +77,6 @@ struct wpa_driver_ops *wpa_drivers[] =
 #ifdef CONFIG_DRIVER_TEST
        &wpa_driver_test_ops,
 #endif /* CONFIG_DRIVER_TEST */
-#ifdef CONFIG_DRIVER_RALINK
-       &wpa_driver_ralink_ops,
-#endif /* CONFIG_DRIVER_RALINK */
-#ifdef CONFIG_DRIVER_OSX
-       &wpa_driver_osx_ops,
-#endif /* CONFIG_DRIVER_OSX */
-#ifdef CONFIG_DRIVER_IPHONE
-       &wpa_driver_iphone_ops,
-#endif /* CONFIG_DRIVER_IPHONE */
 #ifdef CONFIG_DRIVER_ROBOSWITCH
        &wpa_driver_roboswitch_ops,
 #endif /* CONFIG_DRIVER_ROBOSWITCH */
index b76b229..0cc81f9 100644 (file)
@@ -1,28 +1,22 @@
-##### COMMON DRIVERS
+##### CLEAR VARS
+
+DRV_CFLAGS =
+DRV_WPA_CFLAGS =
+DRV_AP_CFLAGS =
+DRV_OBJS =
+DRV_WPA_OBJS =
+DRV_AP_OBJS =
+DRV_LIBS =
+DRV_WPA_LIBS =
+DRV_AP_LIBS =
 
-ifdef CONFIG_DRIVER_HOSTAP
-DRV_CFLAGS += -DCONFIG_DRIVER_HOSTAP
-DRV_OBJS += ../src/drivers/driver_hostap.o
-CONFIG_WIRELESS_EXTENSION=y
-NEED_AP_MLME=y
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
+##### COMMON DRIVERS
 
 ifdef CONFIG_DRIVER_WIRED
 DRV_CFLAGS += -DCONFIG_DRIVER_WIRED
 DRV_OBJS += ../src/drivers/driver_wired.o
 endif
 
-ifdef CONFIG_DRIVER_MADWIFI
-DRV_CFLAGS += -DCONFIG_DRIVER_MADWIFI
-DRV_OBJS += ../src/drivers/driver_madwifi.o
-CONFIG_WIRELESS_EXTENSION=y
-CONFIG_L2_PACKET=linux
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
 ifdef CONFIG_DRIVER_NL80211
 DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
 DRV_OBJS += ../src/drivers/driver_nl80211.o
@@ -31,11 +25,23 @@ NEED_SME=y
 NEED_AP_MLME=y
 NEED_NETLINK=y
 NEED_LINUX_IOCTL=y
-DRV_LIBS += -lnl
+NEED_RFKILL=y
+
+ifdef CONFIG_LIBNL32
+  DRV_LIBS += -lnl-3
+  DRV_LIBS += -lnl-genl-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_CFLAGS += -DCONFIG_LIBNL20
+  ifdef CONFIG_LIBNL20
+    DRV_LIBS += -lnl-genl
+    DRV_CFLAGS += -DCONFIG_LIBNL20
+  endif
 endif
 endif
 
@@ -62,57 +68,40 @@ endif
 
 ##### PURE AP DRIVERS
 
-ifdef CONFIG_DRIVER_ATHEROS
-DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS
-DRV_AP_OBJS += ../src/drivers/driver_atheros.o
-CONFIG_L2_PACKET=linux
+ifdef CONFIG_DRIVER_HOSTAP
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_HOSTAP
+DRV_AP_OBJS += ../src/drivers/driver_hostap.o
+CONFIG_WIRELESS_EXTENSION=y
+NEED_AP_MLME=y
 NEED_NETLINK=y
 NEED_LINUX_IOCTL=y
 endif
 
-##### PURE CLIENT DRIVERS
-
-ifdef CONFIG_DRIVER_WEXT
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_WEXT
+ifdef CONFIG_DRIVER_MADWIFI
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_MADWIFI
+DRV_AP_OBJS += ../src/drivers/driver_madwifi.o
 CONFIG_WIRELESS_EXTENSION=y
+CONFIG_L2_PACKET=linux
 NEED_NETLINK=y
 NEED_LINUX_IOCTL=y
 endif
 
-ifdef CONFIG_DRIVER_HERMES
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_HERMES
-DRV_WPA_OBJS += ../src/drivers/driver_hermes.o
-CONFIG_WIRELESS_EXTENSION=y
-endif
-
-ifdef CONFIG_DRIVER_ATMEL
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ATMEL
-DRV_WPA_OBJS += ../src/drivers/driver_atmel.o
-CONFIG_WIRELESS_EXTENSION=y
-endif
-
-ifdef CONFIG_DRIVER_NDISWRAPPER
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDISWRAPPER
-DRV_WPA_OBJS += ../src/drivers/driver_ndiswrapper.o
-CONFIG_WIRELESS_EXTENSION=y
-endif
-
-ifdef CONFIG_DRIVER_RALINK
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_RALINK
-DRV_WPA_OBJS += ../src/drivers/driver_ralink.o
+ifdef CONFIG_DRIVER_ATHEROS
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS
+DRV_AP_OBJS += ../src/drivers/driver_atheros.o
+CONFIG_L2_PACKET=linux
 NEED_NETLINK=y
 NEED_LINUX_IOCTL=y
 endif
 
-ifdef CONFIG_DRIVER_BROADCOM
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_BROADCOM
-DRV_WPA_OBJS += ../src/drivers/driver_broadcom.o
-endif
+##### PURE CLIENT DRIVERS
 
-ifdef CONFIG_DRIVER_IPW
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_IPW
-DRV_WPA_OBJS += ../src/drivers/driver_ipw.o
+ifdef CONFIG_DRIVER_WEXT
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_WEXT
 CONFIG_WIRELESS_EXTENSION=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+NEED_RFKILL=y
 endif
 
 ifdef CONFIG_DRIVER_NDIS
@@ -130,20 +119,6 @@ DRV_WPA_CFLAGS += -DCONFIG_USE_NDISUIO
 endif
 endif
 
-ifdef CONFIG_DRIVER_OSX
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_OSX
-DRV_WPA_OBJS += ../src/drivers/driver_osx.o
-DRV_WPA_LDFLAGS += -framework CoreFoundation
-DRV_WPA_LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211
-endif
-
-ifdef CONFIG_DRIVER_IPHONE
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_IPHONE
-DRV_WPA_OBJS += ../src/drivers/driver_iphone.o
-DRV_WPA_OBJS += ../src/drivers/MobileApple80211.o
-DRV_WPA_LDFLAGS += -framework CoreFoundation
-endif
-
 ifdef CONFIG_DRIVER_ROBOSWITCH
 DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH
 DRV_WPA_OBJS += ../src/drivers/driver_roboswitch.o
@@ -152,6 +127,7 @@ endif
 ifdef CONFIG_WIRELESS_EXTENSION
 DRV_WPA_CFLAGS += -DCONFIG_WIRELESS_EXTENSION
 DRV_WPA_OBJS += ../src/drivers/driver_wext.o
+NEED_RFKILL=y
 endif
 
 ifdef NEED_NETLINK
@@ -162,6 +138,10 @@ ifdef NEED_LINUX_IOCTL
 DRV_OBJS += ../src/drivers/linux_ioctl.o
 endif
 
+ifdef NEED_RFKILL
+DRV_OBJS += ../src/drivers/rfkill.o
+endif
+
 
 ##### COMMON VARS
 DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
new file mode 100644 (file)
index 0000000..1d7129c
--- /dev/null
@@ -0,0 +1,164 @@
+##### CLEAR VARS
+
+DRV_CFLAGS =
+DRV_WPA_CFLAGS =
+DRV_AP_CFLAGS =
+DRV_OBJS =
+DRV_WPA_OBJS =
+DRV_AP_OBJS =
+DRV_LIBS =
+DRV_WPA_LIBS =
+DRV_AP_LIBS =
+
+##### COMMON DRIVERS
+
+ifdef CONFIG_DRIVER_WIRED
+DRV_CFLAGS += -DCONFIG_DRIVER_WIRED
+DRV_OBJS += src/drivers/driver_wired.c
+endif
+
+ifdef CONFIG_DRIVER_NL80211
+DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
+DRV_OBJS += src/drivers/driver_nl80211.c
+DRV_OBJS += src/utils/radiotap.c
+NEED_SME=y
+NEED_AP_MLME=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+NEED_RFKILL=y
+
+ifdef CONFIG_LIBNL32
+  DRV_LIBS += -lnl-3
+  DRV_LIBS += -lnl-genl-3
+  DRV_CFLAGS += -DCONFIG_LIBNL20
+else
+  ifdef CONFIG_LIBNL_TINY
+    DRV_LIBS += -lnl-tiny
+  else
+    DRV_LIBS += -lnl
+  endif
+
+  ifdef CONFIG_LIBNL20
+    DRV_LIBS += -lnl-genl
+    DRV_CFLAGS += -DCONFIG_LIBNL20
+  endif
+endif
+endif
+
+ifdef CONFIG_DRIVER_BSD
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=freebsd
+endif
+DRV_CFLAGS += -DCONFIG_DRIVER_BSD
+DRV_OBJS += src/drivers/driver_bsd.c
+CONFIG_L2_FREEBSD=y
+CONFIG_DNET_PCAP=y
+endif
+
+ifdef CONFIG_DRIVER_TEST
+DRV_CFLAGS += -DCONFIG_DRIVER_TEST
+DRV_OBJS += src/drivers/driver_test.c
+NEED_AP_MLME=y
+endif
+
+ifdef CONFIG_DRIVER_NONE
+DRV_CFLAGS += -DCONFIG_DRIVER_NONE
+DRV_OBJS += src/drivers/driver_none.c
+endif
+
+##### PURE AP DRIVERS
+
+ifdef CONFIG_DRIVER_HOSTAP
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_HOSTAP
+DRV_AP_OBJS += src/drivers/driver_hostap.c
+CONFIG_WIRELESS_EXTENSION=y
+NEED_AP_MLME=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
+ifdef CONFIG_DRIVER_MADWIFI
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_MADWIFI
+DRV_AP_OBJS += src/drivers/driver_madwifi.c
+CONFIG_WIRELESS_EXTENSION=y
+CONFIG_L2_PACKET=linux
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
+ifdef CONFIG_DRIVER_ATHEROS
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS
+DRV_AP_OBJS += src/drivers/driver_atheros.c
+CONFIG_L2_PACKET=linux
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
+##### PURE CLIENT DRIVERS
+
+ifdef CONFIG_DRIVER_WEXT
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_WEXT
+CONFIG_WIRELESS_EXTENSION=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+NEED_RFKILL=y
+endif
+
+ifdef CONFIG_DRIVER_NDIS
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS
+DRV_WPA_OBJS += src/drivers/driver_ndis.c
+ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+DRV_WPA_OBJS += src/drivers/driver_ndis_.c
+endif
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=pcap
+endif
+CONFIG_WINPCAP=y
+ifdef CONFIG_USE_NDISUIO
+DRV_WPA_CFLAGS += -DCONFIG_USE_NDISUIO
+endif
+endif
+
+ifdef CONFIG_DRIVER_ROBOSWITCH
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH
+DRV_WPA_OBJS += src/drivers/driver_roboswitch.c
+endif
+
+ifdef CONFIG_WIRELESS_EXTENSION
+DRV_WPA_CFLAGS += -DCONFIG_WIRELESS_EXTENSION
+DRV_WPA_OBJS += src/drivers/driver_wext.c
+NEED_RFKILL=y
+endif
+
+ifdef NEED_NETLINK
+DRV_OBJS += src/drivers/netlink.c
+endif
+
+ifdef NEED_LINUX_IOCTL
+DRV_OBJS += src/drivers/linux_ioctl.c
+endif
+
+ifdef NEED_RFKILL
+DRV_OBJS += src/drivers/rfkill.c
+endif
+
+ifdef CONFIG_DRIVER_CUSTOM
+DRV_CFLAGS += -DCONFIG_DRIVER_CUSTOM
+endif
+
+##### COMMON VARS
+DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
+DRV_WPA_CFLAGS += $(DRV_CFLAGS)
+DRV_AP_CFLAGS += $(DRV_CFLAGS)
+
+DRV_BOTH_LIBS := $(DRV_LIBS) $(DRV_WPA_LIBS) $(DRV_AP_LIBS)
+DRV_WPA_LIBS += $(DRV_LIBS)
+DRV_AP_LIBS += $(DRV_LIBS)
+
+DRV_BOTH_OBJS := $(DRV_OBJS) $(DRV_WPA_OBJS) $(DRV_AP_OBJS)
+DRV_WPA_OBJS += $(DRV_OBJS)
+DRV_AP_OBJS += $(DRV_OBJS)
+
+DRV_BOTH_LDFLAGS := $(DRV_LDFLAGS) $(DRV_WPA_LDFLAGS) $(DRV_AP_LDFLAGS)
+DRV_WPA_LDFLAGS += $(DRV_LDFLAGS)
+DRV_AP_LDFLAGS += $(DRV_LDFLAGS)
index 0d6cf54..d7501cf 100644 (file)
@@ -24,6 +24,7 @@
 int linux_set_iface_flags(int sock, const char *ifname, int dev_up)
 {
        struct ifreq ifr;
+       int ret;
 
        if (sock < 0)
                return -1;
@@ -32,9 +33,10 @@ int linux_set_iface_flags(int sock, const char *ifname, int dev_up)
        os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
 
        if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
+               ret = errno ? -errno : -999;
                wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
                           ifname, strerror(errno));
-               return -1;
+               return ret;
        }
 
        if (dev_up) {
@@ -48,15 +50,38 @@ 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));
-               return -1;
+               return ret;
        }
 
        return 0;
 }
 
 
+int linux_iface_up(int sock, const char *ifname)
+{
+       struct ifreq ifr;
+       int ret;
+
+       if (sock < 0)
+               return -1;
+
+       os_memset(&ifr, 0, sizeof(ifr));
+       os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+
+       if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
+               ret = errno ? -errno : -999;
+               wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
+                          ifname, strerror(errno));
+               return ret;
+       }
+
+       return !!(ifr.ifr_flags & IFF_UP);
+}
+
+
 int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr)
 {
        struct ifreq ifr;
index a555738..e0bf673 100644 (file)
@@ -16,6 +16,7 @@
 #define LINUX_IOCTL_H
 
 int linux_set_iface_flags(int sock, const char *ifname, int dev_up);
+int linux_iface_up(int sock, const char *ifname);
 int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr);
 int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr);
 int linux_br_add(int sock, const char *brname);
diff --git a/src/drivers/linux_wext.h b/src/drivers/linux_wext.h
new file mode 100644 (file)
index 0000000..b6eea68
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#ifndef LINUX_WEXT_H
+#define LINUX_WEXT_H
+
+#ifndef ANDROID
+
+/*
+ * Avoid including other kernel header to avoid conflicts with C library
+ * headers.
+ */
+#define _LINUX_TYPES_H
+#define _LINUX_SOCKET_H
+#define _LINUX_IF_H
+
+#include <sys/types.h>
+#include <net/if.h>
+typedef __uint32_t __u32;
+typedef __int32_t __s32;
+typedef __uint16_t __u16;
+typedef __int16_t __s16;
+typedef __uint8_t __u8;
+#ifndef __user
+#define __user
+#endif /* __user */
+
+#endif /* ANDROID */
+
+#include <linux/wireless.h>
+
+#ifndef IW_ENCODE_ALG_PMK
+#define IW_ENCODE_ALG_PMK 4
+#endif
+
+#ifndef IW_ENC_CAPA_4WAY_HANDSHAKE
+#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010
+#endif
+
+#endif /* LINUX_WEXT_H */
index ad15b1d..6778907 100644 (file)
@@ -34,7 +34,7 @@ static void netlink_receive_link(struct netlink_data *netlink,
        if (cb == NULL || NLMSG_PAYLOAD(h, 0) < sizeof(struct ifinfomsg))
                return;
        cb(netlink->cfg->ctx, NLMSG_DATA(h),
-          NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)),
+          (u8 *) NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)),
           NLMSG_PAYLOAD(h, sizeof(struct ifinfomsg)));
 }
 
index bcbfbb5..ccf12a5 100644 (file)
@@ -16,6 +16,7 @@
 #define NETLINK_H
 
 struct netlink_data;
+struct ifinfomsg;
 
 struct netlink_config {
        void *ctx;
index 2ea3ede..f9261c2 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2008 Michael Wu <flamingice@sourmilk.net>
  * Copyright 2008 Luis Carlos Cobo <luisca@cozybit.com>
- * Copyright 2008 Michael Buesch <mb@bu3sch.de>
+ * Copyright 2008 Michael Buesch <m@bues.ch>
  * Copyright 2008, 2009 Luis R. Rodriguez <lrodriguez@atheros.com>
  * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
  * Copyright 2008 Colin McCabe <colin@cozybit.com>
  */
 
 /**
+ * DOC: Frame transmission/registration support
+ *
+ * Frame transmission and registration support exists to allow userspace
+ * management entities such as wpa_supplicant react to management frames
+ * that are not being handled by the kernel. This includes, for example,
+ * certain classes of action frames that cannot be handled in the kernel
+ * for various reasons.
+ *
+ * Frame registration is done on a per-interface basis and registrations
+ * cannot be removed other than by closing the socket. It is possible to
+ * specify a registration filter to register, for example, only for a
+ * certain type of action frame. In particular with action frames, those
+ * that userspace registers for will not be returned as unhandled by the
+ * driver, so that the registered application has to take responsibility
+ * for doing that.
+ *
+ * The type of frame that can be registered for is also dependent on the
+ * driver and interface type. The frame types are advertised in wiphy
+ * attributes so applications know what to expect.
+ *
+ * NOTE: When an interface changes type while registrations are active,
+ *       these registrations are ignored until the interface type is
+ *       changed again. This means that changing the interface type can
+ *       lead to a situation that couldn't otherwise be produced, but
+ *       any such registrations will be dormant in the sense that they
+ *       will not be serviced, i.e. they will not receive any frames.
+ *
+ * Frame transmission allows userspace to send for example the required
+ * responses to action frames. It is subject to some sanity checking,
+ * but many frames can be transmitted. When a frame was transmitted, its
+ * status is indicated to the sending socket.
+ *
+ * For more technical details, see the corresponding command descriptions
+ * below.
+ */
+
+/**
+ * DOC: Virtual interface / concurrency capabilities
+ *
+ * Some devices are able to operate with virtual MACs, they can have
+ * more than one virtual interface. The capability handling for this
+ * is a bit complex though, as there may be a number of restrictions
+ * on the types of concurrency that are supported.
+ *
+ * To start with, each device supports the interface types listed in
+ * the %NL80211_ATTR_SUPPORTED_IFTYPES attribute, but by listing the
+ * types there no concurrency is implied.
+ *
+ * Once concurrency is desired, more attributes must be observed:
+ * To start with, since some interface types are purely managed in
+ * software, like the AP-VLAN type in mac80211 for example, there's
+ * an additional list of these, they can be added at any time and
+ * are only restricted by some semantic restrictions (e.g. AP-VLAN
+ * cannot be added without a corresponding AP interface). This list
+ * is exported in the %NL80211_ATTR_SOFTWARE_IFTYPES attribute.
+ *
+ * Further, the list of supported combinations is exported. This is
+ * in the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute. Basically,
+ * it exports a list of "groups", and at any point in time the
+ * interfaces that are currently active must fall into any one of
+ * the advertised groups. Within each group, there are restrictions
+ * on the number of interfaces of different types that are supported
+ * and also the number of different channels, along with potentially
+ * some other restrictions. See &enum nl80211_if_combination_attrs.
+ *
+ * All together, these attributes define the concurrency of virtual
+ * interfaces that a given device supports.
+ */
+
+/**
  * enum nl80211_commands - supported nl80211 commands
  *
  * @NL80211_CMD_UNSPEC: unspecified command to catch errors
  *     %NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT,
  *     %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
  *     and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
+ *     However, for setting the channel, see %NL80211_CMD_SET_CHANNEL
+ *     instead, the support here is for backward compatibility only.
  * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
  *     or rename notification. Has attributes %NL80211_ATTR_WIPHY and
  *     %NL80211_ATTR_WIPHY_NAME.
  * @NL80211_CMD_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_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_CMD_SET_MPATH:  Set mesh path attributes for mesh path to
  *     destination %NL80211_ATTR_MAC on the interface identified by
  *     %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_MPATH: Create a new mesh path for the destination given by
+ *     %NL80211_ATTR_MAC via %NL80211_ATTR_MPATH_NEXT_HOP.
+ * @NL80211_CMD_DEL_MPATH: Delete a mesh path to the destination given by
+ *     %NL80211_ATTR_MAC.
  * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the
  *     the interface identified by %NL80211_ATTR_IFINDEX.
  * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
  *     %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and
  *     %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP.
  * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain
- *     to the the specified ISO/IEC 3166-1 alpha2 country code. The core will
+ *     to the specified ISO/IEC 3166-1 alpha2 country code. The core will
  *     store this as a valid request and then query userspace for it.
  *
- * @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the
+ * @NL80211_CMD_GET_MESH_CONFIG: Get mesh networking properties for the
  *     interface identified by %NL80211_ATTR_IFINDEX
  *
- * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the
+ * @NL80211_CMD_SET_MESH_CONFIG: Set mesh networking properties for the
  *      interface identified by %NL80211_ATTR_IFINDEX
  *
  * @NL80211_CMD_SET_MGMT_EXTRA_IE: Set extra IEs for management frames. The
  *
  * @NL80211_CMD_GET_SCAN: get scan results
  * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
+ *     %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
+ *     probe requests at CCK rate or not.
  * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
  *     NL80211_CMD_GET_SCAN and on the "scan" multicast group)
  * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
  *     partial scan results may be available
  *
+ * @NL80211_CMD_START_SCHED_SCAN: start a scheduled scan at certain
+ *     intervals, as specified by %NL80211_ATTR_SCHED_SCAN_INTERVAL.
+ *     Like with normal scans, if SSIDs (%NL80211_ATTR_SCAN_SSIDS)
+ *     are passed, they are used in the probe requests.  For
+ *     broadcast, a broadcast SSID must be passed (ie. an empty
+ *     string).  If no SSID is passed, no probe requests are sent and
+ *     a passive scan is performed.  %NL80211_ATTR_SCAN_FREQUENCIES,
+ *     if passed, define which channels should be scanned; if not
+ *     passed, all channels allowed for the current regulatory domain
+ *     are used.  Extra IEs can also be passed from the userspace by
+ *     using the %NL80211_ATTR_IE attribute.
+ * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan.  Returns -ENOENT
+ *     if scheduled scan is not running.
+ * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan
+ *     results available.
+ * @NL80211_CMD_SCHED_SCAN_STOPPED: indicates that the scheduled scan has
+ *     stopped.  The driver may issue this event at any time during a
+ *     scheduled scan.  One reason for stopping the scan is if the hardware
+ *     does not support starting an association or a normal scan while running
+ *     a scheduled scan.  This event is also sent when the
+ *     %NL80211_CMD_STOP_SCHED_SCAN command is received or when the interface
+ *     is brought down while a scheduled scan was running.
+ *
  * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation
  *      or noise level
  * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
  *     auth and assoc steps. For this, you need to specify the SSID in a
  *     %NL80211_ATTR_SSID attribute, and can optionally specify the association
  *     IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
- *     %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_CONTROL_PORT.
+ *     %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
+ *     %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
+ *     %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
  *     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.
  *     channel for the specified amount of time. This can be used to do
  *     off-channel operations like transmit a Public Action frame and wait for
  *     a response while being associated to an AP on another channel.
- *     %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify which
- *     radio is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the
+ *     %NL80211_ATTR_IFINDEX is used to specify which interface (and thus
+ *     radio) is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the
  *     frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be
  *     optionally used to specify additional channel parameters.
  *     %NL80211_ATTR_DURATION is used to specify the duration in milliseconds
  *     rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface
  *     and @NL80211_ATTR_TX_RATES the set of allowed rates.
  *
- * @NL80211_CMD_REGISTER_ACTION: Register for receiving certain action frames
- *     (via @NL80211_CMD_ACTION) for processing in userspace. This command
- *     requires an interface index and a match attribute containing the first
- *     few bytes of the frame that should match, e.g. a single byte for only
- *     a category match or four bytes for vendor frames including the OUI.
- *     The registration cannot be dropped, but is removed automatically
- *     when the netlink socket is closed. Multiple registrations can be made.
- * @NL80211_CMD_ACTION: Action frame TX request and RX notification. This
- *     command is used both as a request to transmit an Action frame and as an
- *     event indicating reception of an Action frame that was not processed in
+ * @NL80211_CMD_REGISTER_FRAME: Register for receiving certain mgmt frames
+ *     (via @NL80211_CMD_FRAME) for processing in userspace. This command
+ *     requires an interface index, a frame type attribute (optional for
+ *     backward compatibility reasons, if not given assumes action frames)
+ *     and a match attribute containing the first few bytes of the frame
+ *     that should match, e.g. a single byte for only a category match or
+ *     four bytes for vendor frames including the OUI. The registration
+ *     cannot be dropped, but is removed automatically when the netlink
+ *     socket is closed. Multiple registrations can be made.
+ * @NL80211_CMD_REGISTER_ACTION: Alias for @NL80211_CMD_REGISTER_FRAME for
+ *     backward compatibility
+ * @NL80211_CMD_FRAME: Management frame TX request and RX notification. This
+ *     command is used both as a request to transmit a management frame and
+ *     as an event indicating reception of a frame that was not processed in
  *     kernel code, but is for us (i.e., which may need to be processed in a
  *     user space application). %NL80211_ATTR_FRAME is used to specify the
  *     frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and
  *     optionally %NL80211_ATTR_WIPHY_CHANNEL_TYPE) is used to indicate on
- *     which channel the frame is to be transmitted or was received. This
- *     channel has to be the current channel (remain-on-channel or the
- *     operational channel). When called, this operation returns a cookie
- *     (%NL80211_ATTR_COOKIE) that will be included with the TX status event
- *     pertaining to the TX request.
- * @NL80211_CMD_ACTION_TX_STATUS: Report TX status of an Action frame
- *     transmitted with %NL80211_CMD_ACTION. %NL80211_ATTR_COOKIE identifies
+ *     which channel the frame is to be transmitted or was received. If this
+ *     channel is not the current channel (remain-on-channel or the
+ *     operational channel) the device will switch to the given channel and
+ *     transmit the frame, optionally waiting for a response for the time
+ *     specified using %NL80211_ATTR_DURATION. When called, this operation
+ *     returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the
+ *     TX status event pertaining to the TX request.
+ *     %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
+ *     management frames at CCK rate or not in 2GHz band.
+ * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
+ *     command may be used with the corresponding cookie to cancel the wait
+ *     time if it is known that it is no longer necessary.
+ * @NL80211_CMD_ACTION: Alias for @NL80211_CMD_FRAME for backward compatibility.
+ * @NL80211_CMD_FRAME_TX_STATUS: Report TX status of a management frame
+ *     transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies
  *     the TX command and %NL80211_ATTR_FRAME includes the contents of the
  *     frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged
  *     the frame.
+ * @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for
+ *     backward compatibility.
  * @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command
  *     is used to configure connection quality monitoring notification trigger
  *     levels.
  * @NL80211_CMD_NOTIFY_CQM: Connection quality monitor notification. This
  *     command is used as an event to indicate the that a trigger level was
  *     reached.
+ * @NL80211_CMD_SET_CHANNEL: Set the channel (using %NL80211_ATTR_WIPHY_FREQ
+ *     and %NL80211_ATTR_WIPHY_CHANNEL_TYPE) the given interface (identifed
+ *     by %NL80211_ATTR_IFINDEX) shall operate on.
+ *     In case multiple channels are supported by the device, the mechanism
+ *     with which it switches channels is implementation-defined.
+ *     When a monitor interface is given, it can only switch channel while
+ *     no other interfaces are operating to avoid disturbing the operation
+ *     of any other interfaces, and other interfaces will again take
+ *     precedence when they are used.
+ *
+ * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface.
+ *
+ * @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial
+ *     mesh config parameters may be given.
+ * @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the
+ *     network is determined by the network interface.
+ *
+ * @NL80211_CMD_UNPROT_DEAUTHENTICATE: Unprotected deauthentication frame
+ *     notification. This event is used to indicate that an unprotected
+ *     deauthentication frame was dropped when MFP is in use.
+ * @NL80211_CMD_UNPROT_DISASSOCIATE: Unprotected disassociation frame
+ *     notification. This event is used to indicate that an unprotected
+ *     disassociation frame was dropped when MFP is in use.
+ *
+ * @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a
+ *      beacon or probe response from a compatible mesh peer.  This is only
+ *      sent while no station information (sta_info) exists for the new peer
+ *      candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH is set.  On
+ *      reception of this notification, userspace may decide to create a new
+ *      station (@NL80211_CMD_NEW_STATION).  To stop this notification from
+ *      reoccurring, the userspace authentication daemon may want to create the
+ *      new station with the AUTHENTICATED flag unset and maybe change it later
+ *      depending on the authentication result.
+ *
+ * @NL80211_CMD_GET_WOWLAN: get Wake-on-Wireless-LAN (WoWLAN) settings.
+ * @NL80211_CMD_SET_WOWLAN: set Wake-on-Wireless-LAN (WoWLAN) settings.
+ *     Since wireless is more complex than wired ethernet, it supports
+ *     various triggers. These triggers can be configured through this
+ *     command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For
+ *     more background information, see
+ *     http://wireless.kernel.org/en/users/Documentation/WoWLAN.
+ *
+ * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver
+ *     the necessary information for supporting GTK rekey offload. This
+ *     feature is typically used during WoWLAN. The configuration data
+ *     is contained in %NL80211_ATTR_REKEY_DATA (which is nested and
+ *     contains the data in sub-attributes). After rekeying happened,
+ *     this command may also be sent by the driver as an MLME event to
+ *     inform userspace of the new replay counter.
+ *
+ * @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace
+ *     of PMKSA caching dandidates.
+ *
+ * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
+ * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
+ *
+ * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP
+ *     (or GO) interface (i.e. hostapd) to ask for unexpected frames to
+ *     implement sending deauth to stations that send unexpected class 3
+ *     frames. Also used as the event sent by the kernel when such a frame
+ *     is received.
+ *     For the event, the %NL80211_ATTR_MAC attribute carries the TA and
+ *     other attributes like the interface index are present.
+ *     If used as the command it must have an interface index and you can
+ *     only unsubscribe from the event by closing the socket. Subscription
+ *     is also for %NL80211_CMD_UNEXPECTED_4ADDR_FRAME events.
+ *
+ * @NL80211_CMD_UNEXPECTED_4ADDR_FRAME: Sent as an event indicating that the
+ *     associated station identified by %NL80211_ATTR_MAC sent a 4addr frame
+ *     and wasn't already in a 4-addr VLAN. The event will be sent similarly
+ *     to the %NL80211_CMD_UNEXPECTED_FRAME event, to the same listener.
+ *
+ * @NL80211_CMD_PROBE_CLIENT: Probe an associated station on an AP interface
+ *     by sending a null data frame to it and reporting when the frame is
+ *     acknowleged. This is used to allow timing out inactive clients. Uses
+ *     %NL80211_ATTR_IFINDEX and %NL80211_ATTR_MAC. The command returns a
+ *     direct reply with an %NL80211_ATTR_COOKIE that is later used to match
+ *     up the event with the request. The event includes the same data and
+ *     has %NL80211_ATTR_ACK set if the frame was ACKed.
+ *
+ * @NL80211_CMD_REGISTER_BEACONS: Register this socket to receive beacons from
+ *     other BSSes when any interfaces are in AP mode. This helps implement
+ *     OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME
+ *     messages. Note that per PHY only one application may register.
  *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
 enum nl80211_commands {
-/* don't change the order or add anything inbetween, this is ABI! */
+/* don't change the order or add anything between, this is ABI! */
        NL80211_CMD_UNSPEC,
 
        NL80211_CMD_GET_WIPHY,          /* can dump */
@@ -372,8 +580,8 @@ enum nl80211_commands {
        NL80211_CMD_SET_REG,
        NL80211_CMD_REQ_SET_REG,
 
-       NL80211_CMD_GET_MESH_PARAMS,
-       NL80211_CMD_SET_MESH_PARAMS,
+       NL80211_CMD_GET_MESH_CONFIG,
+       NL80211_CMD_SET_MESH_CONFIG,
 
        NL80211_CMD_SET_MGMT_EXTRA_IE /* reserved; not used */,
 
@@ -418,9 +626,12 @@ enum nl80211_commands {
 
        NL80211_CMD_SET_TX_BITRATE_MASK,
 
-       NL80211_CMD_REGISTER_ACTION,
-       NL80211_CMD_ACTION,
-       NL80211_CMD_ACTION_TX_STATUS,
+       NL80211_CMD_REGISTER_FRAME,
+       NL80211_CMD_REGISTER_ACTION = NL80211_CMD_REGISTER_FRAME,
+       NL80211_CMD_FRAME,
+       NL80211_CMD_ACTION = NL80211_CMD_FRAME,
+       NL80211_CMD_FRAME_TX_STATUS,
+       NL80211_CMD_ACTION_TX_STATUS = NL80211_CMD_FRAME_TX_STATUS,
 
        NL80211_CMD_SET_POWER_SAVE,
        NL80211_CMD_GET_POWER_SAVE,
@@ -428,6 +639,42 @@ enum nl80211_commands {
        NL80211_CMD_SET_CQM,
        NL80211_CMD_NOTIFY_CQM,
 
+       NL80211_CMD_SET_CHANNEL,
+       NL80211_CMD_SET_WDS_PEER,
+
+       NL80211_CMD_FRAME_WAIT_CANCEL,
+
+       NL80211_CMD_JOIN_MESH,
+       NL80211_CMD_LEAVE_MESH,
+
+       NL80211_CMD_UNPROT_DEAUTHENTICATE,
+       NL80211_CMD_UNPROT_DISASSOCIATE,
+
+       NL80211_CMD_NEW_PEER_CANDIDATE,
+
+       NL80211_CMD_GET_WOWLAN,
+       NL80211_CMD_SET_WOWLAN,
+
+       NL80211_CMD_START_SCHED_SCAN,
+       NL80211_CMD_STOP_SCHED_SCAN,
+       NL80211_CMD_SCHED_SCAN_RESULTS,
+       NL80211_CMD_SCHED_SCAN_STOPPED,
+
+       NL80211_CMD_SET_REKEY_OFFLOAD,
+
+       NL80211_CMD_PMKSA_CANDIDATE,
+
+       NL80211_CMD_TDLS_OPER,
+       NL80211_CMD_TDLS_MGMT,
+
+       NL80211_CMD_UNEXPECTED_FRAME,
+
+       NL80211_CMD_PROBE_CLIENT,
+
+       NL80211_CMD_REGISTER_BEACONS,
+
+       NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -448,6 +695,13 @@ enum nl80211_commands {
 #define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE
 #define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT
 
+#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
+
+/* source-level API compatibility */
+#define NL80211_CMD_GET_MESH_PARAMS NL80211_CMD_GET_MESH_CONFIG
+#define NL80211_CMD_SET_MESH_PARAMS NL80211_CMD_SET_MESH_CONFIG
+#define NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE NL80211_MESH_SETUP_IE
+
 /**
  * enum nl80211_attrs - nl80211 netlink attributes
  *
@@ -518,7 +772,7 @@ enum nl80211_commands {
  *     consisting of a nested array.
  *
  * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes).
- * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link.
+ * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link.
  * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
  * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
  *     info given for %NL80211_CMD_GET_MPATH, nested attribute described at
@@ -563,8 +817,14 @@ enum nl80211_commands {
  *
  * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
  *     a single scan request, a wiphy attribute.
+ * @NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS: number of SSIDs you can
+ *     scan with a single scheduled scan request, a wiphy attribute.
  * @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements
  *     that can be added to a scan request
+ * @NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN: maximum length of information
+ *     elements that can be added to a scheduled scan request
+ * @NL80211_ATTR_MAX_MATCH_SETS: maximum number of sets that can be
+ *     used with @NL80211_ATTR_SCHED_SCAN_MATCH, a wiphy attribute.
  *
  * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
  * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
@@ -626,6 +886,15 @@ enum nl80211_commands {
  *     request, the driver will assume that the port is unauthorized until
  *     authorized by user space. Otherwise, port is marked authorized by
  *     default in station mode.
+ * @NL80211_ATTR_CONTROL_PORT_ETHERTYPE: A 16-bit value indicating the
+ *     ethertype that will be used for key negotiation. It can be
+ *     specified with the associate and connect commands. If it is not
+ *     specified, the value defaults to 0x888E (PAE, 802.1X). This
+ *     attribute is also used as a flag in the wiphy information to
+ *     indicate that protocols other than PAE are supported.
+ * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with
+ *     %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom
+ *     ethertype frames used for key negotiation must not be encrypted.
  *
  * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
  *     We recommend using nested, driver-specific attributes within this.
@@ -636,18 +905,20 @@ enum nl80211_commands {
  * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT
  *     event (u16)
  * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating
- *     that protected APs should be used.
+ *     that protected APs should be used. This is also used with NEW_BEACON to
+ *     indicate that the BSS is to use protection.
  *
- * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to
- *     indicate which unicast key ciphers will be used with the connection
+ * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT, ASSOCIATE, and NEW_BEACON
+ *     to indicate which unicast key ciphers will be used with the connection
  *     (an array of u32).
- * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate
- *     which group key cipher will be used with the connection (a u32).
- * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate
- *     which WPA version(s) the AP we want to associate with is using
+ * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ *     indicate which group key cipher will be used with the connection (a
+ *     u32).
+ * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ *     indicate which WPA version(s) the AP we want to associate with is using
  *     (a u32 with flags from &enum nl80211_wpa_versions).
- * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate
- *     which key management algorithm(s) to use (an array of u32).
+ * @NL80211_ATTR_AKM_SUITES: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ *     indicate which key management algorithm(s) to use (an array of u32).
  *
  * @NL80211_ATTR_REQ_IE: (Re)association request information elements as
  *     sent out by the card, for ROAM and successful CONNECT events.
@@ -684,6 +955,9 @@ enum nl80211_commands {
  *     cache, a wiphy attribute.
  *
  * @NL80211_ATTR_DURATION: Duration of an operation in milliseconds, u32.
+ * @NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION: Device attribute that
+ *     specifies the maximum duration that can be requested with the
+ *     remain-on-channel operation, in milliseconds, u32.
  *
  * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects.
  *
@@ -695,7 +969,16 @@ enum nl80211_commands {
  *     is used with %NL80211_CMD_SET_TX_BITRATE_MASK.
  *
  * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain
- *     at least one byte, currently used with @NL80211_CMD_REGISTER_ACTION.
+ *     at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME.
+ * @NL80211_ATTR_FRAME_TYPE: A u16 indicating the frame type/subtype for the
+ *     @NL80211_CMD_REGISTER_FRAME command.
+ * @NL80211_ATTR_TX_FRAME_TYPES: wiphy capability attribute, which is a
+ *     nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing
+ *     information about which frame types can be transmitted with
+ *     %NL80211_CMD_FRAME.
+ * @NL80211_ATTR_RX_FRAME_TYPES: wiphy capability attribute, which is a
+ *     nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing
+ *     information about which frame types can be registered for RX.
  *
  * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was
  *     acknowledged by the recipient.
@@ -709,11 +992,189 @@ enum nl80211_commands {
  *     NL80211_CMD_AUTHENTICATE, NL80211_CMD_DEAUTHENTICATE,
  *     NL80211_CMD_DISASSOCIATE.
  *
+ * @NL80211_ATTR_AP_ISOLATE: (AP mode) Do not forward traffic between stations
+ *     connected to this BSS.
+ *
+ * @NL80211_ATTR_WIPHY_TX_POWER_SETTING: Transmit power setting type. See
+ *      &enum nl80211_tx_power_setting for possible values.
+ * @NL80211_ATTR_WIPHY_TX_POWER_LEVEL: Transmit power level in signed mBm units.
+ *      This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING
+ *      for non-automatic settings.
+ *
+ * @NL80211_ATTR_SUPPORT_IBSS_RSN: The device supports IBSS RSN, which mostly
+ *     means support for per-station GTKs.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_TX: Bitmap of allowed antennas for transmitting.
+ *     This can be used to mask out antennas which are not attached or should
+ *     not be used for transmitting. If an antenna is not selected in this
+ *     bitmap the hardware is not allowed to transmit on this antenna.
+ *
+ *     Each bit represents one antenna, starting with antenna 1 at the first
+ *     bit. Depending on which antennas are selected in the bitmap, 802.11n
+ *     drivers can derive which chainmasks to use (if all antennas belonging to
+ *     a particular chain are disabled this chain should be disabled) and if
+ *     a chain has diversity antennas wether diversity should be used or not.
+ *     HT capabilities (STBC, TX Beamforming, Antenna selection) can be
+ *     derived from the available chains after applying the antenna mask.
+ *     Non-802.11n drivers can derive wether to use diversity or not.
+ *     Drivers may reject configurations or RX/TX mask combinations they cannot
+ *     support by returning -EINVAL.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_RX: Bitmap of allowed antennas for receiving.
+ *     This can be used to mask out antennas which are not attached or should
+ *     not be used for receiving. If an antenna is not selected in this bitmap
+ *     the hardware should not be configured to receive on this antenna.
+ *     For a more detailed description see @NL80211_ATTR_WIPHY_ANTENNA_TX.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX: Bitmap of antennas which are available
+ *     for configuration as TX antennas via the above parameters.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX: Bitmap of antennas which are available
+ *     for configuration as RX antennas via the above parameters.
+ *
+ * @NL80211_ATTR_MCAST_RATE: Multicast tx rate (in 100 kbps) for IBSS
+ *
+ * @NL80211_ATTR_OFFCHANNEL_TX_OK: For management frame TX, the frame may be
+ *     transmitted on another channel when the channel given doesn't match
+ *     the current channel. If the current channel doesn't match and this
+ *     flag isn't set, the frame will be rejected. This is also used as an
+ *     nl80211 capability flag.
+ *
+ * @NL80211_ATTR_BSS_HTOPMODE: HT operation mode (u16)
+ *
+ * @NL80211_ATTR_KEY_DEFAULT_TYPES: A nested attribute containing flags
+ *     attributes, specifying what a key should be set as default as.
+ *     See &enum nl80211_key_default_types.
+ *
+ * @NL80211_ATTR_MESH_SETUP: Optional mesh setup parameters.  These cannot be
+ *     changed once the mesh is active.
+ * @NL80211_ATTR_MESH_CONFIG: Mesh configuration parameters, a nested attribute
+ *     containing attributes from &enum nl80211_meshconf_params.
+ * @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver
+ *     allows auth frames in a mesh to be passed to userspace for processing via
+ *     the @NL80211_MESH_SETUP_USERSPACE_AUTH flag.
+ * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as
+ *     defined in &enum nl80211_plink_state. Used when userspace is
+ *     driving the peer link management state machine.
+ *     @NL80211_MESH_SETUP_USERSPACE_AMPE must be enabled.
+ *
+ * @NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED: indicates, as part of the wiphy
+ *     capabilities, the supported WoWLAN triggers
+ * @NL80211_ATTR_WOWLAN_TRIGGERS: used by %NL80211_CMD_SET_WOWLAN to
+ *     indicate which WoW triggers should be enabled. This is also
+ *     used by %NL80211_CMD_GET_WOWLAN to get the currently enabled WoWLAN
+ *     triggers.
+
+ * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan
+ *     cycles, in msecs.
+
+ * @NL80211_ATTR_SCHED_SCAN_MATCH: Nested attribute with one or more
+ *     sets of attributes to match during scheduled scans.  Only BSSs
+ *     that match any of the sets will be reported.  These are
+ *     pass-thru filter rules.
+ *     For a match to succeed, the BSS must match all attributes of a
+ *     set.  Since not every hardware supports matching all types of
+ *     attributes, there is no guarantee that the reported BSSs are
+ *     fully complying with the match sets and userspace needs to be
+ *     able to ignore them by itself.
+ *     Thus, the implementation is somewhat hardware-dependent, but
+ *     this is only an optimization and the userspace application
+ *     needs to handle all the non-filtered results anyway.
+ *     If the match attributes don't make sense when combined with
+ *     the values passed in @NL80211_ATTR_SCAN_SSIDS (eg. if an SSID
+ *     is included in the probe request, but the match attributes
+ *     will never let it go through), -EINVAL may be returned.
+ *     If ommited, no filtering is done.
+ *
+ * @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported
+ *     interface combinations. In each nested item, it contains attributes
+ *     defined in &enum nl80211_if_combination_attrs.
+ * @NL80211_ATTR_SOFTWARE_IFTYPES: Nested attribute (just like
+ *     %NL80211_ATTR_SUPPORTED_IFTYPES) containing the interface types that
+ *     are managed in software: interfaces of these types aren't subject to
+ *     any restrictions in their number or combinations.
+ *
+ * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information
+ *     necessary for GTK rekeying in the device, see &enum nl80211_rekey_data.
+ *
+ * @NL80211_ATTR_SCAN_SUPP_RATES: rates per to be advertised as supported in scan,
+ *     nested array attribute containing an entry for each band, with the entry
+ *     being a list of supported rates as defined by IEEE 802.11 7.3.2.2 but
+ *     without the length restriction (at most %NL80211_MAX_SUPP_RATES).
+ *
+ * @NL80211_ATTR_HIDDEN_SSID: indicates whether SSID is to be hidden from Beacon
+ *     and Probe Response (when response to wildcard Probe Request); see
+ *     &enum nl80211_hidden_ssid, represented as a u32
+ *
+ * @NL80211_ATTR_IE_PROBE_RESP: Information element(s) for Probe Response frame.
+ *     This is used with %NL80211_CMD_NEW_BEACON and %NL80211_CMD_SET_BEACON to
+ *     provide extra IEs (e.g., WPS/P2P IE) into Probe Response frames when the
+ *     driver (or firmware) replies to Probe Request frames.
+ * @NL80211_ATTR_IE_ASSOC_RESP: Information element(s) for (Re)Association
+ *     Response frames. This is used with %NL80211_CMD_NEW_BEACON and
+ *     %NL80211_CMD_SET_BEACON to provide extra IEs (e.g., WPS/P2P IE) into
+ *     (Re)Association Response frames when the driver (or firmware) replies to
+ *     (Re)Association Request frames.
+ *
+ * @NL80211_ATTR_STA_WME: Nested attribute containing the wme configuration
+ *     of the station, see &enum nl80211_sta_wme_attr.
+ * @NL80211_ATTR_SUPPORT_AP_UAPSD: the device supports uapsd when working
+ *     as AP.
+ *
+ * @NL80211_ATTR_ROAM_SUPPORT: Indicates whether the firmware is capable of
+ *     roaming to another AP in the same ESS if the signal lever is low.
+ *
+ * @NL80211_ATTR_PMKSA_CANDIDATE: Nested attribute containing the PMKSA caching
+ *     candidate information, see &enum nl80211_pmksa_candidate_attr.
+ *
+ * @NL80211_ATTR_TX_NO_CCK_RATE: Indicates whether to use CCK rate or not
+ *     for management frames transmission. In order to avoid p2p probe/action
+ *     frames are being transmitted at CCK rate in 2GHz band, the user space
+ *     applications use this attribute.
+ *     This attribute is used with %NL80211_CMD_TRIGGER_SCAN and
+ *     %NL80211_CMD_FRAME commands.
+ *
+ * @NL80211_ATTR_TDLS_ACTION: Low level TDLS action code (e.g. link setup
+ *     request, link setup confirm, link teardown, etc.). Values are
+ *     described in the TDLS (802.11z) specification.
+ * @NL80211_ATTR_TDLS_DIALOG_TOKEN: Non-zero token for uniquely identifying a
+ *     TDLS conversation between two devices.
+ * @NL80211_ATTR_TDLS_OPERATION: High level TDLS operation; see
+ *     &enum nl80211_tdls_operation, represented as a u8.
+ * @NL80211_ATTR_TDLS_SUPPORT: A flag indicating the device can operate
+ *     as a TDLS peer sta.
+ * @NL80211_ATTR_TDLS_EXTERNAL_SETUP: The TDLS discovery/setup and teardown
+ *     procedures should be performed by sending TDLS packets via
+ *     %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be
+ *     used for asking the driver to perform a TDLS operation.
+ *
+ * @NL80211_ATTR_DEVICE_AP_SME: This u32 attribute may be listed for devices
+ *     that have AP support to indicate that they have the AP SME integrated
+ *     with support for the features listed in this attribute, see
+ *     &enum nl80211_ap_sme_features.
+ *
+ * @NL80211_ATTR_DONT_WAIT_FOR_ACK: Used with %NL80211_CMD_FRAME, this tells
+ *     the driver to not wait for an acknowledgement. Note that due to this,
+ *     it will also not give a status callback nor return a cookie. This is
+ *     mostly useful for probe responses to save airtime.
+ *
+ * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from
+ *     &enum nl80211_feature_flags and is advertised in wiphy information.
+ * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe
+ *
+ *     requests while operating in AP-mode.
+ *     This attribute holds a bitmap of the supported protocols for
+ *     offloading (see &enum nl80211_probe_resp_offload_support_attr).
+ *
+ * @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire
+ *     probe-response frame. The DA field in the 802.11 header is zero-ed out,
+ *     to be filled by the FW.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_attrs {
-/* don't change the order or add anything inbetween, this is ABI! */
+/* don't change the order or add anything between, this is ABI! */
        NL80211_ATTR_UNSPEC,
 
        NL80211_ATTR_WIPHY,
@@ -763,7 +1224,7 @@ enum nl80211_attrs {
        NL80211_ATTR_REG_ALPHA2,
        NL80211_ATTR_REG_RULES,
 
-       NL80211_ATTR_MESH_PARAMS,
+       NL80211_ATTR_MESH_CONFIG,
 
        NL80211_ATTR_BSS_BASIC_RATES,
 
@@ -864,6 +1325,89 @@ enum nl80211_attrs {
 
        NL80211_ATTR_LOCAL_STATE_CHANGE,
 
+       NL80211_ATTR_AP_ISOLATE,
+
+       NL80211_ATTR_WIPHY_TX_POWER_SETTING,
+       NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
+
+       NL80211_ATTR_TX_FRAME_TYPES,
+       NL80211_ATTR_RX_FRAME_TYPES,
+       NL80211_ATTR_FRAME_TYPE,
+
+       NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
+       NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
+
+       NL80211_ATTR_SUPPORT_IBSS_RSN,
+
+       NL80211_ATTR_WIPHY_ANTENNA_TX,
+       NL80211_ATTR_WIPHY_ANTENNA_RX,
+
+       NL80211_ATTR_MCAST_RATE,
+
+       NL80211_ATTR_OFFCHANNEL_TX_OK,
+
+       NL80211_ATTR_BSS_HT_OPMODE,
+
+       NL80211_ATTR_KEY_DEFAULT_TYPES,
+
+       NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
+
+       NL80211_ATTR_MESH_SETUP,
+
+       NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
+       NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
+
+       NL80211_ATTR_SUPPORT_MESH_AUTH,
+       NL80211_ATTR_STA_PLINK_STATE,
+
+       NL80211_ATTR_WOWLAN_TRIGGERS,
+       NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED,
+
+       NL80211_ATTR_SCHED_SCAN_INTERVAL,
+
+       NL80211_ATTR_INTERFACE_COMBINATIONS,
+       NL80211_ATTR_SOFTWARE_IFTYPES,
+
+       NL80211_ATTR_REKEY_DATA,
+
+       NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
+       NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
+
+       NL80211_ATTR_SCAN_SUPP_RATES,
+
+       NL80211_ATTR_HIDDEN_SSID,
+
+       NL80211_ATTR_IE_PROBE_RESP,
+       NL80211_ATTR_IE_ASSOC_RESP,
+
+       NL80211_ATTR_STA_WME,
+       NL80211_ATTR_SUPPORT_AP_UAPSD,
+
+       NL80211_ATTR_ROAM_SUPPORT,
+
+       NL80211_ATTR_SCHED_SCAN_MATCH,
+       NL80211_ATTR_MAX_MATCH_SETS,
+
+       NL80211_ATTR_PMKSA_CANDIDATE,
+
+       NL80211_ATTR_TX_NO_CCK_RATE,
+
+       NL80211_ATTR_TDLS_ACTION,
+       NL80211_ATTR_TDLS_DIALOG_TOKEN,
+       NL80211_ATTR_TDLS_OPERATION,
+       NL80211_ATTR_TDLS_SUPPORT,
+       NL80211_ATTR_TDLS_EXTERNAL_SETUP,
+
+       NL80211_ATTR_DEVICE_AP_SME,
+
+       NL80211_ATTR_DONT_WAIT_FOR_ACK,
+
+       NL80211_ATTR_FEATURE_FLAGS,
+
+       NL80211_ATTR_PROBE_RESP_OFFLOAD,
+
+       NL80211_ATTR_PROBE_RESP,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -872,6 +1416,7 @@ enum nl80211_attrs {
 
 /* source-level API compatibility */
 #define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
+#define        NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG
 
 /*
  * Allow user space programs to use #ifdef on new attributes by defining them
@@ -897,6 +1442,7 @@ enum nl80211_attrs {
 #define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
 #define NL80211_ATTR_KEY NL80211_ATTR_KEY
 #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
+#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
 
 #define NL80211_MAX_SUPP_RATES                 32
 #define NL80211_MAX_SUPP_REG_RULES             32
@@ -915,12 +1461,16 @@ enum nl80211_attrs {
  * @NL80211_IFTYPE_ADHOC: independent BSS member
  * @NL80211_IFTYPE_STATION: managed BSS member
  * @NL80211_IFTYPE_AP: access point
- * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points
+ * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points; VLAN interfaces
+ *     are a bit special in that they must always be tied to a pre-existing
+ *     AP type interface.
  * @NL80211_IFTYPE_WDS: wireless distribution interface
  * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
  * @NL80211_IFTYPE_MESH_POINT: mesh point
+ * @NL80211_IFTYPE_P2P_CLIENT: P2P client
+ * @NL80211_IFTYPE_P2P_GO: P2P group owner
  * @NL80211_IFTYPE_MAX: highest interface type number currently defined
- * @__NL80211_IFTYPE_AFTER_LAST: internal use
+ * @NUM_NL80211_IFTYPES: number of defined interface types
  *
  * These values are used with the %NL80211_ATTR_IFTYPE
  * to set the type of an interface.
@@ -935,10 +1485,12 @@ enum nl80211_iftype {
        NL80211_IFTYPE_WDS,
        NL80211_IFTYPE_MONITOR,
        NL80211_IFTYPE_MESH_POINT,
+       NL80211_IFTYPE_P2P_CLIENT,
+       NL80211_IFTYPE_P2P_GO,
 
        /* keep last */
-       __NL80211_IFTYPE_AFTER_LAST,
-       NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1
+       NUM_NL80211_IFTYPES,
+       NL80211_IFTYPE_MAX = NUM_NL80211_IFTYPES - 1
 };
 
 /**
@@ -947,11 +1499,16 @@ enum nl80211_iftype {
  * Station flags. When a station is added to an AP interface, it is
  * assumed to be already associated (and hence authenticated.)
  *
+ * @__NL80211_STA_FLAG_INVALID: attribute number 0 is reserved
  * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
  * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
  *     with short barker preamble
  * @NL80211_STA_FLAG_WME: station is WME/QoS capable
  * @NL80211_STA_FLAG_MFP: station uses management frame protection
+ * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated
+ * @NL80211_STA_FLAG_TDLS_PEER: station is a TDLS peer
+ * @NL80211_STA_FLAG_MAX: highest station flag number currently defined
+ * @__NL80211_STA_FLAG_AFTER_LAST: internal use
  */
 enum nl80211_sta_flags {
        __NL80211_STA_FLAG_INVALID,
@@ -959,6 +1516,8 @@ enum nl80211_sta_flags {
        NL80211_STA_FLAG_SHORT_PREAMBLE,
        NL80211_STA_FLAG_WME,
        NL80211_STA_FLAG_MFP,
+       NL80211_STA_FLAG_AUTHENTICATED,
+       NL80211_STA_FLAG_TDLS_PEER,
 
        /* keep last */
        __NL80211_STA_FLAG_AFTER_LAST,
@@ -1004,6 +1563,36 @@ enum nl80211_rate_info {
 };
 
 /**
+ * enum nl80211_sta_bss_param - BSS information collected by STA
+ *
+ * These attribute types are used with %NL80211_STA_INFO_BSS_PARAM
+ * when getting information about the bitrate of a station.
+ *
+ * @__NL80211_STA_BSS_PARAM_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_BSS_PARAM_CTS_PROT: whether CTS protection is enabled (flag)
+ * @NL80211_STA_BSS_PARAM_SHORT_PREAMBLE:  whether short preamble is enabled
+ *     (flag)
+ * @NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME:  whether short slot time is enabled
+ *     (flag)
+ * @NL80211_STA_BSS_PARAM_DTIM_PERIOD: DTIM period for beaconing (u8)
+ * @NL80211_STA_BSS_PARAM_BEACON_INTERVAL: Beacon interval (u16)
+ * @NL80211_STA_BSS_PARAM_MAX: highest sta_bss_param number currently defined
+ * @__NL80211_STA_BSS_PARAM_AFTER_LAST: internal use
+ */
+enum nl80211_sta_bss_param {
+       __NL80211_STA_BSS_PARAM_INVALID,
+       NL80211_STA_BSS_PARAM_CTS_PROT,
+       NL80211_STA_BSS_PARAM_SHORT_PREAMBLE,
+       NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME,
+       NL80211_STA_BSS_PARAM_DTIM_PERIOD,
+       NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
+
+       /* keep last */
+       __NL80211_STA_BSS_PARAM_AFTER_LAST,
+       NL80211_STA_BSS_PARAM_MAX = __NL80211_STA_BSS_PARAM_AFTER_LAST - 1
+};
+
+/**
  * enum nl80211_sta_info - station information
  *
  * These attribute types are used with %NL80211_ATTR_STA_INFO
@@ -1013,14 +1602,27 @@ enum nl80211_rate_info {
  * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
  * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
  * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
- * @__NL80211_STA_INFO_AFTER_LAST: internal
- * @NL80211_STA_INFO_MAX: highest possible station info attribute
  * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
  * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
- *     containing info as possible, see &enum nl80211_sta_info_txrate.
+ *     containing info as possible, see &enum nl80211_rate_info
  * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)
  * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this
  *     station)
+ * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station)
+ * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station)
+ * @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm)
+ * @NL80211_STA_INFO_LLID: the station's mesh LLID
+ * @NL80211_STA_INFO_PLID: the station's mesh PLID
+ * @NL80211_STA_INFO_PLINK_STATE: peer link state for the station
+ *     (see %enum nl80211_plink_state)
+ * @NL80211_STA_INFO_RX_BITRATE: last unicast data frame rx rate, nested
+ *     attribute, like NL80211_STA_INFO_TX_BITRATE.
+ * @NL80211_STA_INFO_BSS_PARAM: current station's view of BSS, nested attribute
+ *     containing info as possible, see &enum nl80211_sta_bss_param
+ * @NL80211_STA_INFO_CONNECTED_TIME: time since the station is last connected
+ * @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update.
+ * @__NL80211_STA_INFO_AFTER_LAST: internal
+ * @NL80211_STA_INFO_MAX: highest possible station info attribute
  */
 enum nl80211_sta_info {
        __NL80211_STA_INFO_INVALID,
@@ -1034,6 +1636,13 @@ enum nl80211_sta_info {
        NL80211_STA_INFO_TX_BITRATE,
        NL80211_STA_INFO_RX_PACKETS,
        NL80211_STA_INFO_TX_PACKETS,
+       NL80211_STA_INFO_TX_RETRIES,
+       NL80211_STA_INFO_TX_FAILED,
+       NL80211_STA_INFO_SIGNAL_AVG,
+       NL80211_STA_INFO_RX_BITRATE,
+       NL80211_STA_INFO_BSS_PARAM,
+       NL80211_STA_INFO_CONNECTED_TIME,
+       NL80211_STA_INFO_STA_FLAGS,
 
        /* keep last */
        __NL80211_STA_INFO_AFTER_LAST,
@@ -1064,14 +1673,17 @@ enum nl80211_mpath_flags {
  * information about a mesh path.
  *
  * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved
- * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination
- * @NL80211_ATTR_MPATH_SN: destination sequence number
- * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path
- * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now
- * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in
+ * @NL80211_MPATH_INFO_FRAME_QLEN: number of queued frames for this destination
+ * @NL80211_MPATH_INFO_SN: destination sequence number
+ * @NL80211_MPATH_INFO_METRIC: metric (cost) of this mesh path
+ * @NL80211_MPATH_INFO_EXPTIME: expiration time for the path, in msec from now
+ * @NL80211_MPATH_INFO_FLAGS: mesh path flags, enumerated in
  *     &enum nl80211_mpath_flags;
- * @NL80211_ATTR_MPATH_DISCOVERY_TIMEOUT: total path discovery timeout, in msec
- * @NL80211_ATTR_MPATH_DISCOVERY_RETRIES: mesh path discovery retries
+ * @NL80211_MPATH_INFO_DISCOVERY_TIMEOUT: total path discovery timeout, in msec
+ * @NL80211_MPATH_INFO_DISCOVERY_RETRIES: mesh path discovery retries
+ * @NL80211_MPATH_INFO_MAX: highest mesh path information attribute number
+ *     currently defind
+ * @__NL80211_MPATH_INFO_AFTER_LAST: internal use
  */
 enum nl80211_mpath_info {
        __NL80211_MPATH_INFO_INVALID,
@@ -1100,6 +1712,8 @@ 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_MAX: highest band attribute currently defined
+ * @__NL80211_BAND_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_band_attr {
        __NL80211_BAND_ATTR_INVALID,
@@ -1120,6 +1734,7 @@ enum nl80211_band_attr {
 
 /**
  * enum nl80211_frequency_attr - frequency attributes
+ * @__NL80211_FREQUENCY_ATTR_INVALID: attribute number 0 is reserved
  * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
  * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
  *     regulatory domain.
@@ -1131,6 +1746,9 @@ 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_MAX: highest frequency attribute number
+ *     currently defined
+ * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_frequency_attr {
        __NL80211_FREQUENCY_ATTR_INVALID,
@@ -1150,9 +1768,13 @@ enum nl80211_frequency_attr {
 
 /**
  * enum nl80211_bitrate_attr - bitrate attributes
+ * @__NL80211_BITRATE_ATTR_INVALID: attribute number 0 is reserved
  * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps
  * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported
  *     in 2.4 GHz band.
+ * @NL80211_BITRATE_ATTR_MAX: highest bitrate attribute number
+ *     currently defined
+ * @__NL80211_BITRATE_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_bitrate_attr {
        __NL80211_BITRATE_ATTR_INVALID,
@@ -1174,7 +1796,11 @@ enum nl80211_bitrate_attr {
  *     wireless core it thinks its knows the regulatory domain we should be in.
  * @NL80211_REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an
  *     802.11 country information element with regulatory information it
- *     thinks we should consider.
+ *     thinks we should consider. cfg80211 only processes the country
+ *     code from the IE, and relies on the regulatory domain information
+ *     structure passed by userspace (CRDA) from our wireless-regdb.
+ *     If a channel is enabled but the country code indicates it should
+ *     be disabled we disable the channel and re-enable it upon disassociation.
  */
 enum nl80211_reg_initiator {
        NL80211_REGDOM_SET_BY_CORE,
@@ -1208,6 +1834,7 @@ enum nl80211_reg_type {
 
 /**
  * enum nl80211_reg_rule_attr - regulatory rule attributes
+ * @__NL80211_REG_RULE_ATTR_INVALID: attribute number 0 is reserved
  * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional
  *     considerations for a given frequency range. These are the
  *     &enum nl80211_reg_rule_flags.
@@ -1224,6 +1851,9 @@ enum nl80211_reg_type {
  *     If you don't have one then don't send this.
  * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for
  *     a given frequency range. The value is in mBm (100 * dBm).
+ * @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number
+ *     currently defined
+ * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_reg_rule_attr {
        __NL80211_REG_RULE_ATTR_INVALID,
@@ -1242,6 +1872,26 @@ enum nl80211_reg_rule_attr {
 };
 
 /**
+ * enum nl80211_sched_scan_match_attr - scheduled scan match attributes
+ * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching,
+ * only report BSS with matching SSID.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
+ *     attribute number currently defined
+ * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_sched_scan_match_attr {
+       __NL80211_SCHED_SCAN_MATCH_ATTR_INVALID,
+
+       NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+
+       /* keep last */
+       __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
+       NL80211_SCHED_SCAN_MATCH_ATTR_MAX =
+               __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST - 1
+};
+
+/**
  * enum nl80211_reg_rule_flags - regulatory rule flags
  *
  * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed
@@ -1275,11 +1925,31 @@ enum nl80211_reg_rule_flags {
  * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved
  * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel
  * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm)
+ * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME: amount of time (in ms) that the radio
+ *     spent on this channel
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY: amount of the time the primary
+ *     channel was sensed busy (either due to activity or energy detect)
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: amount of time the extension
+ *     channel was sensed busy
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_RX: amount of time the radio spent
+ *     receiving data
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_TX: amount of time the radio spent
+ *     transmitting data
+ * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
+ *     currently defined
+ * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
  */
 enum nl80211_survey_info {
        __NL80211_SURVEY_INFO_INVALID,
        NL80211_SURVEY_INFO_FREQUENCY,
        NL80211_SURVEY_INFO_NOISE,
+       NL80211_SURVEY_INFO_IN_USE,
+       NL80211_SURVEY_INFO_CHANNEL_TIME,
+       NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY,
+       NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY,
+       NL80211_SURVEY_INFO_CHANNEL_TIME_RX,
+       NL80211_SURVEY_INFO_CHANNEL_TIME_TX,
 
        /* keep last */
        __NL80211_SURVEY_INFO_AFTER_LAST,
@@ -1319,14 +1989,15 @@ enum nl80211_mntr_flags {
 /**
  * enum nl80211_meshconf_params - mesh configuration parameters
  *
- * Mesh configuration parameters
+ * Mesh configuration parameters. These can be changed while the mesh is
+ * active.
  *
  * @__NL80211_MESHCONF_INVALID: internal use
  *
  * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in
  * millisecond units, used by the Peer Link Open message
  *
- * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the inital confirm timeout, in
+ * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the initial confirm timeout, in
  * millisecond units, used by the peer link management to close a peer link
  *
  * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in
@@ -1366,7 +2037,17 @@ enum nl80211_mntr_flags {
  * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs)
  * that it takes for an HWMP information element to propagate across the mesh
  *
- * @NL80211_MESHCONF_ROOTMODE: whether root mode is enabled or not
+ * @NL80211_MESHCONF_HWMP_ROOTMODE: whether root mode is enabled or not
+ *
+ * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
+ * source mesh point for path selection elements.
+ *
+ * @NL80211_MESHCONF_HWMP_RANN_INTERVAL:  The interval of time (in TUs) between
+ * root announcements are transmitted.
+ *
+ * @NL80211_MESHCONF_GATE_ANNOUNCEMENTS: Advertise that this mesh station has
+ * access to a broader network beyond the MBSS.  This is done via Root
+ * Announcement frames.
  *
  * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
  *
@@ -1388,6 +2069,9 @@ enum nl80211_meshconf_params {
        NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
        NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
        NL80211_MESHCONF_HWMP_ROOTMODE,
+       NL80211_MESHCONF_ELEMENT_TTL,
+       NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+       NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
 
        /* keep last */
        __NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -1395,6 +2079,54 @@ enum nl80211_meshconf_params {
 };
 
 /**
+ * enum nl80211_mesh_setup_params - mesh setup parameters
+ *
+ * Mesh setup parameters.  These are used to start/join a mesh and cannot be
+ * changed while the mesh is active.
+ *
+ * @__NL80211_MESH_SETUP_INVALID: Internal use
+ *
+ * @NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL: Enable this option to use a
+ * vendor specific path selection algorithm or disable it to use the default
+ * HWMP.
+ *
+ * @NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC: Enable this option to use a
+ * vendor specific path metric or disable it to use the default Airtime
+ * metric.
+ *
+ * @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a
+ * robust security network ie, or a vendor specific information element that
+ * vendors will use to identify the path selection methods and metrics in use.
+ *
+ * @NL80211_MESH_SETUP_USERSPACE_AUTH: Enable this option if an authentication
+ * daemon will be authenticating mesh candidates.
+ *
+ * @NL80211_MESH_SETUP_USERSPACE_AMPE: Enable this option if an authentication
+ * daemon will be securing peer link frames.  AMPE is a secured version of Mesh
+ * Peering Management (MPM) and is implemented with the assistance of a
+ * userspace daemon.  When this flag is set, the kernel will send peer
+ * management frames to a userspace daemon that will implement AMPE
+ * functionality (security capabilities selection, key confirmation, and key
+ * management).  When the flag is unset (default), the kernel can autonomously
+ * complete (unsecured) mesh peering without the need of a userspace daemon.
+ *
+ * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
+ * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
+ */
+enum nl80211_mesh_setup_params {
+       __NL80211_MESH_SETUP_INVALID,
+       NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL,
+       NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC,
+       NL80211_MESH_SETUP_IE,
+       NL80211_MESH_SETUP_USERSPACE_AUTH,
+       NL80211_MESH_SETUP_USERSPACE_AMPE,
+
+       /* keep last */
+       __NL80211_MESH_SETUP_ATTR_AFTER_LAST,
+       NL80211_MESH_SETUP_ATTR_MAX = __NL80211_MESH_SETUP_ATTR_AFTER_LAST - 1
+};
+
+/**
  * enum nl80211_txq_attr - TX queue parameter attributes
  * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved
  * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*)
@@ -1439,6 +2171,7 @@ enum nl80211_channel_type {
  * enum nl80211_bss - netlink attributes for a BSS
  *
  * @__NL80211_BSS_INVALID: invalid
+ * @NL80211_BSS_BSSID: BSSID of the BSS (6 octets)
  * @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
  * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
  * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
@@ -1482,6 +2215,12 @@ enum nl80211_bss {
 
 /**
  * enum nl80211_bss_status - BSS "status"
+ * @NL80211_BSS_STATUS_AUTHENTICATED: Authenticated with this BSS.
+ * @NL80211_BSS_STATUS_ASSOCIATED: Associated with this BSS.
+ * @NL80211_BSS_STATUS_IBSS_JOINED: Joined to this IBSS.
+ *
+ * The BSS status is a BSS attribute in scan dumps, which
+ * indicates the status the interface has wrt. this BSS.
  */
 enum nl80211_bss_status {
        NL80211_BSS_STATUS_AUTHENTICATED,
@@ -1519,11 +2258,14 @@ enum nl80211_auth_type {
  * @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key
  * @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key
  * @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS)
+ * @NUM_NL80211_KEYTYPES: number of defined key types
  */
 enum nl80211_key_type {
        NL80211_KEYTYPE_GROUP,
        NL80211_KEYTYPE_PAIRWISE,
        NL80211_KEYTYPE_PEERKEY,
+
+       NUM_NL80211_KEYTYPES
 };
 
 /**
@@ -1542,6 +2284,23 @@ enum nl80211_wpa_versions {
 };
 
 /**
+ * enum nl80211_key_default_types - key default types
+ * @__NL80211_KEY_DEFAULT_TYPE_INVALID: invalid
+ * @NL80211_KEY_DEFAULT_TYPE_UNICAST: key should be used as default
+ *     unicast key
+ * @NL80211_KEY_DEFAULT_TYPE_MULTICAST: key should be used as default
+ *     multicast key
+ * @NUM_NL80211_KEY_DEFAULT_TYPES: number of default types
+ */
+enum nl80211_key_default_types {
+       __NL80211_KEY_DEFAULT_TYPE_INVALID,
+       NL80211_KEY_DEFAULT_TYPE_UNICAST,
+       NL80211_KEY_DEFAULT_TYPE_MULTICAST,
+
+       NUM_NL80211_KEY_DEFAULT_TYPES
+};
+
+/**
  * enum nl80211_key_attributes - key attributes
  * @__NL80211_KEY_INVALID: invalid
  * @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of
@@ -1554,6 +2313,12 @@ enum nl80211_wpa_versions {
  *     CCMP keys, each six bytes in little endian
  * @NL80211_KEY_DEFAULT: flag indicating default key
  * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key
+ * @NL80211_KEY_TYPE: the key type from enum nl80211_key_type, if not
+ *     specified the default depends on whether a MAC address was
+ *     given with the command using the key or not (u32)
+ * @NL80211_KEY_DEFAULT_TYPES: A nested attribute containing flags
+ *     attributes, specifying what a key should be set as default as.
+ *     See &enum nl80211_key_default_types.
  * @__NL80211_KEY_AFTER_LAST: internal
  * @NL80211_KEY_MAX: highest key attribute
  */
@@ -1565,6 +2330,8 @@ enum nl80211_key_attributes {
        NL80211_KEY_SEQ,
        NL80211_KEY_DEFAULT,
        NL80211_KEY_DEFAULT_MGMT,
+       NL80211_KEY_TYPE,
+       NL80211_KEY_DEFAULT_TYPES,
 
        /* keep last */
        __NL80211_KEY_AFTER_LAST,
@@ -1592,8 +2359,8 @@ 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_2GHZ: 2.4 GHz ISM band
+ * @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
  */
 enum nl80211_band {
        NL80211_BAND_2GHZ,
@@ -1615,6 +2382,8 @@ enum nl80211_ps_state {
  *     the minimum amount the RSSI level must change after an event before a
  *     new event may be issued (to reduce effects of RSSI oscillation).
  * @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event
+ * @NL80211_ATTR_CQM_PKT_LOSS_EVENT: a u32 value indicating that this many
+ *     consecutive packets were not acknowledged by the peer
  * @__NL80211_ATTR_CQM_AFTER_LAST: internal
  * @NL80211_ATTR_CQM_MAX: highest key attribute
  */
@@ -1623,6 +2392,7 @@ enum nl80211_attr_cqm {
        NL80211_ATTR_CQM_RSSI_THOLD,
        NL80211_ATTR_CQM_RSSI_HYST,
        NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
+       NL80211_ATTR_CQM_PKT_LOSS_EVENT,
 
        /* keep last */
        __NL80211_ATTR_CQM_AFTER_LAST,
@@ -1631,9 +2401,9 @@ enum nl80211_attr_cqm {
 
 /**
  * enum nl80211_cqm_rssi_threshold_event - RSSI threshold event
- * @NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW - The RSSI level is lower than the
+ * @NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW: The RSSI level is lower than the
  *      configured threshold
- * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH - The RSSI is higher than the
+ * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
  *      configured threshold
  */
 enum nl80211_cqm_rssi_threshold_event {
@@ -1641,4 +2411,354 @@ enum nl80211_cqm_rssi_threshold_event {
        NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
 };
 
+
+/**
+ * enum nl80211_tx_power_setting - TX power adjustment
+ * @NL80211_TX_POWER_AUTOMATIC: automatically determine transmit power
+ * @NL80211_TX_POWER_LIMITED: limit TX power by the mBm parameter
+ * @NL80211_TX_POWER_FIXED: fix TX power to the mBm parameter
+ */
+enum nl80211_tx_power_setting {
+       NL80211_TX_POWER_AUTOMATIC,
+       NL80211_TX_POWER_LIMITED,
+       NL80211_TX_POWER_FIXED,
+};
+
+/**
+ * enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute
+ * @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute
+ * @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has
+ *     a zero bit are ignored
+ * @NL80211_WOWLAN_PKTPAT_MASK: pattern mask, must be long enough to have
+ *     a bit for each byte in the pattern. The lowest-order bit corresponds
+ *     to the first byte of the pattern, but the bytes of the pattern are
+ *     in a little-endian-like format, i.e. the 9th byte of the pattern
+ *     corresponds to the lowest-order bit in the second byte of the mask.
+ *     For example: The match 00:xx:00:00:xx:00:00:00:00:xx:xx:xx (where
+ *     xx indicates "don't care") would be represented by a pattern of
+ *     twelve zero bytes, and a mask of "0xed,0x07".
+ *     Note that the pattern matching is done as though frames were not
+ *     802.11 frames but 802.3 frames, i.e. the frame is fully unpacked
+ *     first (including SNAP header unpacking) and then matched.
+ * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes
+ * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number
+ */
+enum nl80211_wowlan_packet_pattern_attr {
+       __NL80211_WOWLAN_PKTPAT_INVALID,
+       NL80211_WOWLAN_PKTPAT_MASK,
+       NL80211_WOWLAN_PKTPAT_PATTERN,
+
+       NUM_NL80211_WOWLAN_PKTPAT,
+       MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1,
+};
+
+/**
+ * struct nl80211_wowlan_pattern_support - pattern support information
+ * @max_patterns: maximum number of patterns supported
+ * @min_pattern_len: minimum length of each pattern
+ * @max_pattern_len: maximum length of each pattern
+ *
+ * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when
+ * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the
+ * capability information given by the kernel to userspace.
+ */
+struct nl80211_wowlan_pattern_support {
+       __u32 max_patterns;
+       __u32 min_pattern_len;
+       __u32 max_pattern_len;
+} __attribute__((packed));
+
+/**
+ * enum nl80211_wowlan_triggers - WoWLAN trigger definitions
+ * @__NL80211_WOWLAN_TRIG_INVALID: invalid number for nested attributes
+ * @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put
+ *     the chip into a special state -- works best with chips that have
+ *     support for low-power operation already (flag)
+ * @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect
+ *     is detected is implementation-specific (flag)
+ * @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed
+ *     by 16 repetitions of MAC addr, anywhere in payload) (flag)
+ * @NL80211_WOWLAN_TRIG_PKT_PATTERN: wake up on the specified packet patterns
+ *     which are passed in an array of nested attributes, each nested attribute
+ *     defining a with attributes from &struct nl80211_wowlan_trig_pkt_pattern.
+ *     Each pattern defines a wakeup packet. The matching is done on the MSDU,
+ *     i.e. as though the packet was an 802.3 packet, so the pattern matching
+ *     is done after the packet is converted to the MSDU.
+ *
+ *     In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute
+ *     carrying a &struct nl80211_wowlan_pattern_support.
+ * @NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED: Not a real trigger, and cannot be
+ *     used when setting, used only to indicate that GTK rekeying is supported
+ *     by the device (flag)
+ * @NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE: wake up on GTK rekey failure (if
+ *     done by the device) (flag)
+ * @NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST: wake up on EAP Identity Request
+ *     packet (flag)
+ * @NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE: wake up on 4-way handshake (flag)
+ * @NL80211_WOWLAN_TRIG_RFKILL_RELEASE: wake up when rfkill is released
+ *     (on devices that have rfkill in the device) (flag)
+ * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers
+ * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number
+ */
+enum nl80211_wowlan_triggers {
+       __NL80211_WOWLAN_TRIG_INVALID,
+       NL80211_WOWLAN_TRIG_ANY,
+       NL80211_WOWLAN_TRIG_DISCONNECT,
+       NL80211_WOWLAN_TRIG_MAGIC_PKT,
+       NL80211_WOWLAN_TRIG_PKT_PATTERN,
+       NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED,
+       NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE,
+       NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST,
+       NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE,
+       NL80211_WOWLAN_TRIG_RFKILL_RELEASE,
+
+       /* keep last */
+       NUM_NL80211_WOWLAN_TRIG,
+       MAX_NL80211_WOWLAN_TRIG = NUM_NL80211_WOWLAN_TRIG - 1
+};
+
+/**
+ * enum nl80211_iface_limit_attrs - limit attributes
+ * @NL80211_IFACE_LIMIT_UNSPEC: (reserved)
+ * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that
+ *     can be chosen from this set of interface types (u32)
+ * @NL80211_IFACE_LIMIT_TYPES: nested attribute containing a
+ *     flag attribute for each interface type in this set
+ * @NUM_NL80211_IFACE_LIMIT: number of attributes
+ * @MAX_NL80211_IFACE_LIMIT: highest attribute number
+ */
+enum nl80211_iface_limit_attrs {
+       NL80211_IFACE_LIMIT_UNSPEC,
+       NL80211_IFACE_LIMIT_MAX,
+       NL80211_IFACE_LIMIT_TYPES,
+
+       /* keep last */
+       NUM_NL80211_IFACE_LIMIT,
+       MAX_NL80211_IFACE_LIMIT = NUM_NL80211_IFACE_LIMIT - 1
+};
+
+/**
+ * enum nl80211_if_combination_attrs -- interface combination attributes
+ *
+ * @NL80211_IFACE_COMB_UNSPEC: (reserved)
+ * @NL80211_IFACE_COMB_LIMITS: Nested attributes containing the limits
+ *     for given interface types, see &enum nl80211_iface_limit_attrs.
+ * @NL80211_IFACE_COMB_MAXNUM: u32 attribute giving the total number of
+ *     interfaces that can be created in this group. This number doesn't
+ *     apply to interfaces purely managed in software, which are listed
+ *     in a separate attribute %NL80211_ATTR_INTERFACES_SOFTWARE.
+ * @NL80211_IFACE_COMB_STA_AP_BI_MATCH: flag attribute specifying that
+ *     beacon intervals within this group must be all the same even for
+ *     infrastructure and AP/GO combinations, i.e. the GO(s) must adopt
+ *     the infrastructure network's beacon interval.
+ * @NL80211_IFACE_COMB_NUM_CHANNELS: u32 attribute specifying how many
+ *     different channels may be used within this group.
+ * @NUM_NL80211_IFACE_COMB: number of attributes
+ * @MAX_NL80211_IFACE_COMB: highest attribute number
+ *
+ * Examples:
+ *     limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2
+ *     => allows an AP and a STA that must match BIs
+ *
+ *     numbers = [ #{AP, P2P-GO} <= 8 ], channels = 1, max = 8
+ *     => allows 8 of AP/GO
+ *
+ *     numbers = [ #{STA} <= 2 ], channels = 2, max = 2
+ *     => allows two STAs on different channels
+ *
+ *     numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4
+ *     => allows a STA plus three P2P interfaces
+ *
+ * The list of these four possiblities could completely be contained
+ * within the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute to indicate
+ * that any of these groups must match.
+ *
+ * "Combinations" of just a single interface will not be listed here,
+ * a single interface of any valid interface type is assumed to always
+ * be possible by itself. This means that implicitly, for each valid
+ * interface type, the following group always exists:
+ *     numbers = [ #{<type>} <= 1 ], channels = 1, max = 1
+ */
+enum nl80211_if_combination_attrs {
+       NL80211_IFACE_COMB_UNSPEC,
+       NL80211_IFACE_COMB_LIMITS,
+       NL80211_IFACE_COMB_MAXNUM,
+       NL80211_IFACE_COMB_STA_AP_BI_MATCH,
+       NL80211_IFACE_COMB_NUM_CHANNELS,
+
+       /* keep last */
+       NUM_NL80211_IFACE_COMB,
+       MAX_NL80211_IFACE_COMB = NUM_NL80211_IFACE_COMB - 1
+};
+
+
+/**
+ * enum nl80211_plink_state - state of a mesh peer link finite state machine
+ *
+ * @NL80211_PLINK_LISTEN: initial state, considered the implicit
+ *     state of non existant mesh peer links
+ * @NL80211_PLINK_OPN_SNT: mesh plink open frame has been sent to
+ *     this mesh peer
+ * @NL80211_PLINK_OPN_RCVD: mesh plink open frame has been received
+ *     from this mesh peer
+ * @NL80211_PLINK_CNF_RCVD: mesh plink confirm frame has been
+ *     received from this mesh peer
+ * @NL80211_PLINK_ESTAB: mesh peer link is established
+ * @NL80211_PLINK_HOLDING: mesh peer link is being closed or cancelled
+ * @NL80211_PLINK_BLOCKED: all frames transmitted from this mesh
+ *     plink are discarded
+ * @NUM_NL80211_PLINK_STATES: number of peer link states
+ * @MAX_NL80211_PLINK_STATES: highest numerical value of plink states
+ */
+enum nl80211_plink_state {
+       NL80211_PLINK_LISTEN,
+       NL80211_PLINK_OPN_SNT,
+       NL80211_PLINK_OPN_RCVD,
+       NL80211_PLINK_CNF_RCVD,
+       NL80211_PLINK_ESTAB,
+       NL80211_PLINK_HOLDING,
+       NL80211_PLINK_BLOCKED,
+
+       /* keep last */
+       NUM_NL80211_PLINK_STATES,
+       MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1
+};
+
+#define NL80211_KCK_LEN                        16
+#define NL80211_KEK_LEN                        16
+#define NL80211_REPLAY_CTR_LEN         8
+
+/**
+ * enum nl80211_rekey_data - attributes for GTK rekey offload
+ * @__NL80211_REKEY_DATA_INVALID: invalid number for nested attributes
+ * @NL80211_REKEY_DATA_KEK: key encryption key (binary)
+ * @NL80211_REKEY_DATA_KCK: key confirmation key (binary)
+ * @NL80211_REKEY_DATA_REPLAY_CTR: replay counter (binary)
+ * @NUM_NL80211_REKEY_DATA: number of rekey attributes (internal)
+ * @MAX_NL80211_REKEY_DATA: highest rekey attribute (internal)
+ */
+enum nl80211_rekey_data {
+       __NL80211_REKEY_DATA_INVALID,
+       NL80211_REKEY_DATA_KEK,
+       NL80211_REKEY_DATA_KCK,
+       NL80211_REKEY_DATA_REPLAY_CTR,
+
+       /* keep last */
+       NUM_NL80211_REKEY_DATA,
+       MAX_NL80211_REKEY_DATA = NUM_NL80211_REKEY_DATA - 1
+};
+
+/**
+ * enum nl80211_hidden_ssid - values for %NL80211_ATTR_HIDDEN_SSID
+ * @NL80211_HIDDEN_SSID_NOT_IN_USE: do not hide SSID (i.e., broadcast it in
+ *     Beacon frames)
+ * @NL80211_HIDDEN_SSID_ZERO_LEN: hide SSID by using zero-length SSID element
+ *     in Beacon frames
+ * @NL80211_HIDDEN_SSID_ZERO_CONTENTS: hide SSID by using correct length of SSID
+ *     element in Beacon frames but zero out each byte in the SSID
+ */
+enum nl80211_hidden_ssid {
+       NL80211_HIDDEN_SSID_NOT_IN_USE,
+       NL80211_HIDDEN_SSID_ZERO_LEN,
+       NL80211_HIDDEN_SSID_ZERO_CONTENTS
+};
+
+/**
+ * enum nl80211_sta_wme_attr - station WME attributes
+ * @__NL80211_STA_WME_INVALID: invalid number for nested attribute
+ * @NL80211_STA_WME_UAPSD_QUEUES: bitmap of uapsd queues. the format
+ *     is the same as the AC bitmap in the QoS info field.
+ * @NL80211_STA_WME_MAX_SP: max service period. the format is the same
+ *     as the MAX_SP field in the QoS info field (but already shifted down).
+ * @__NL80211_STA_WME_AFTER_LAST: internal
+ * @NL80211_STA_WME_MAX: highest station WME attribute
+ */
+enum nl80211_sta_wme_attr {
+       __NL80211_STA_WME_INVALID,
+       NL80211_STA_WME_UAPSD_QUEUES,
+       NL80211_STA_WME_MAX_SP,
+
+       /* keep last */
+       __NL80211_STA_WME_AFTER_LAST,
+       NL80211_STA_WME_MAX = __NL80211_STA_WME_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_pmksa_candidate_attr - attributes for PMKSA caching candidates
+ * @__NL80211_PMKSA_CANDIDATE_INVALID: invalid number for nested attributes
+ * @NL80211_PMKSA_CANDIDATE_INDEX: candidate index (u32; the smaller, the higher
+ *     priority)
+ * @NL80211_PMKSA_CANDIDATE_BSSID: candidate BSSID (6 octets)
+ * @NL80211_PMKSA_CANDIDATE_PREAUTH: RSN pre-authentication supported (flag)
+ * @NUM_NL80211_PMKSA_CANDIDATE: number of PMKSA caching candidate attributes
+ *     (internal)
+ * @MAX_NL80211_PMKSA_CANDIDATE: highest PMKSA caching candidate attribute
+ *     (internal)
+ */
+enum nl80211_pmksa_candidate_attr {
+       __NL80211_PMKSA_CANDIDATE_INVALID,
+       NL80211_PMKSA_CANDIDATE_INDEX,
+       NL80211_PMKSA_CANDIDATE_BSSID,
+       NL80211_PMKSA_CANDIDATE_PREAUTH,
+
+       /* keep last */
+       NUM_NL80211_PMKSA_CANDIDATE,
+       MAX_NL80211_PMKSA_CANDIDATE = NUM_NL80211_PMKSA_CANDIDATE - 1
+};
+
+/**
+ * enum nl80211_tdls_operation - values for %NL80211_ATTR_TDLS_OPERATION
+ * @NL80211_TDLS_DISCOVERY_REQ: Send a TDLS discovery request
+ * @NL80211_TDLS_SETUP: Setup TDLS link
+ * @NL80211_TDLS_TEARDOWN: Teardown a TDLS link which is already established
+ * @NL80211_TDLS_ENABLE_LINK: Enable TDLS link
+ * @NL80211_TDLS_DISABLE_LINK: Disable TDLS link
+ */
+enum nl80211_tdls_operation {
+       NL80211_TDLS_DISCOVERY_REQ,
+       NL80211_TDLS_SETUP,
+       NL80211_TDLS_TEARDOWN,
+       NL80211_TDLS_ENABLE_LINK,
+       NL80211_TDLS_DISABLE_LINK,
+};
+
+/*
+ * enum nl80211_ap_sme_features - device-integrated AP features
+ * Reserved for future use, no bits are defined in
+ * NL80211_ATTR_DEVICE_AP_SME yet.
+enum nl80211_ap_sme_features {
+};
+ */
+
+/**
+ * enum nl80211_feature_flags - device/driver features
+ * @NL80211_FEATURE_SK_TX_STATUS: This driver supports reflecting back
+ *     TX status to the socket error queue when requested with the
+ *     socket option.
+ */
+enum nl80211_feature_flags {
+       NL80211_FEATURE_SK_TX_STATUS    = 1 << 0,
+};
+
+/**
+ * enum nl80211_probe_resp_offload_support_attr - optional supported
+ *     protocols for probe-response offloading by the driver/FW.
+ *     To be used with the %NL80211_ATTR_PROBE_RESP_OFFLOAD attribute.
+ *     Each enum value represents a bit in the bitmap of supported
+ *     protocols. Typically a subset of probe-requests belonging to a
+ *     supported protocol will be excluded from offload and uploaded
+ *     to the host.
+ *
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS: Support for WPS ver. 1
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2: Support for WPS ver. 2
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P: Support for P2P
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U: Support for 802.11u
+ */
+enum nl80211_probe_resp_offload_support_attr {
+       NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS =        1<<0,
+       NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 =       1<<1,
+       NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P =        1<<2,
+       NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U =     1<<3,
+};
+
 #endif /* __LINUX_NL80211_H */
diff --git a/src/drivers/rfkill.c b/src/drivers/rfkill.c
new file mode 100644 (file)
index 0000000..8818311
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+#include <fcntl.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "rfkill.h"
+
+#define RFKILL_EVENT_SIZE_V1 8
+
+struct rfkill_event {
+       u32 idx;
+       u8 type;
+       u8 op;
+       u8 soft;
+       u8 hard;
+} STRUCT_PACKED;
+
+enum rfkill_operation {
+       RFKILL_OP_ADD = 0,
+       RFKILL_OP_DEL,
+       RFKILL_OP_CHANGE,
+       RFKILL_OP_CHANGE_ALL,
+};
+
+enum rfkill_type {
+       RFKILL_TYPE_ALL = 0,
+       RFKILL_TYPE_WLAN,
+       RFKILL_TYPE_BLUETOOTH,
+       RFKILL_TYPE_UWB,
+       RFKILL_TYPE_WIMAX,
+       RFKILL_TYPE_WWAN,
+       RFKILL_TYPE_GPS,
+       RFKILL_TYPE_FM,
+       NUM_RFKILL_TYPES,
+};
+
+
+struct rfkill_data {
+       struct rfkill_config *cfg;
+       int fd;
+       int blocked;
+};
+
+
+static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+       struct rfkill_data *rfkill = eloop_ctx;
+       struct rfkill_event event;
+       ssize_t len;
+       int new_blocked;
+
+       len = read(rfkill->fd, &event, sizeof(event));
+       if (len < 0) {
+               wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
+                          strerror(errno));
+               return;
+       }
+       if (len != RFKILL_EVENT_SIZE_V1) {
+               wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size "
+                          "%d (expected %d)",
+                          (int) len, RFKILL_EVENT_SIZE_V1);
+               return;
+       }
+       wpa_printf(MSG_DEBUG, "rfkill: event: idx=%u type=%d "
+                  "op=%u soft=%u hard=%u",
+                  event.idx, event.type, event.op, event.soft,
+                  event.hard);
+       if (event.op != RFKILL_OP_CHANGE || event.type != RFKILL_TYPE_WLAN)
+               return;
+
+       if (event.hard) {
+               wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
+               new_blocked = 1;
+       } else if (event.soft) {
+               wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
+               new_blocked = 1;
+       } else {
+               wpa_printf(MSG_INFO, "rfkill: WLAN unblocked");
+               new_blocked = 0;
+       }
+
+       if (new_blocked != rfkill->blocked) {
+               rfkill->blocked = new_blocked;
+               if (new_blocked)
+                       rfkill->cfg->blocked_cb(rfkill->cfg->ctx);
+               else
+                       rfkill->cfg->unblocked_cb(rfkill->cfg->ctx);
+       }
+}
+
+
+struct rfkill_data * rfkill_init(struct rfkill_config *cfg)
+{
+       struct rfkill_data *rfkill;
+       struct rfkill_event event;
+       ssize_t len;
+
+       rfkill = os_zalloc(sizeof(*rfkill));
+       if (rfkill == NULL)
+               return NULL;
+
+       rfkill->cfg = cfg;
+       rfkill->fd = open("/dev/rfkill", O_RDONLY);
+       if (rfkill->fd < 0) {
+               wpa_printf(MSG_INFO, "rfkill: Cannot open RFKILL control "
+                          "device");
+               goto fail;
+       }
+
+       if (fcntl(rfkill->fd, F_SETFL, O_NONBLOCK) < 0) {
+               wpa_printf(MSG_ERROR, "rfkill: Cannot set non-blocking mode: "
+                          "%s", strerror(errno));
+               goto fail2;
+       }
+
+       for (;;) {
+               len = read(rfkill->fd, &event, sizeof(event));
+               if (len < 0) {
+                       if (errno == EAGAIN)
+                               break; /* No more entries */
+                       wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
+                                  strerror(errno));
+                       break;
+               }
+               if (len != RFKILL_EVENT_SIZE_V1) {
+                       wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size "
+                                  "%d (expected %d)",
+                                  (int) len, RFKILL_EVENT_SIZE_V1);
+                       continue;
+               }
+               wpa_printf(MSG_DEBUG, "rfkill: initial event: idx=%u type=%d "
+                          "op=%u soft=%u hard=%u",
+                          event.idx, event.type, event.op, event.soft,
+                          event.hard);
+               if (event.op != RFKILL_OP_ADD ||
+                   event.type != RFKILL_TYPE_WLAN)
+                       continue;
+               if (event.hard) {
+                       wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
+                       rfkill->blocked = 1;
+               } else if (event.soft) {
+                       wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
+                       rfkill->blocked = 1;
+               }
+       }
+
+       eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL);
+
+       return rfkill;
+
+fail2:
+       close(rfkill->fd);
+fail:
+       os_free(rfkill);
+       return NULL;
+}
+
+
+void rfkill_deinit(struct rfkill_data *rfkill)
+{
+       if (rfkill == NULL)
+               return;
+
+       if (rfkill->fd >= 0) {
+               eloop_unregister_read_sock(rfkill->fd);
+               close(rfkill->fd);
+       }
+
+       os_free(rfkill->cfg);
+       os_free(rfkill);
+}
+
+
+int rfkill_is_blocked(struct rfkill_data *rfkill)
+{
+       if (rfkill == NULL)
+               return 0;
+
+       return rfkill->blocked;
+}
diff --git a/src/drivers/rfkill.h b/src/drivers/rfkill.h
new file mode 100644 (file)
index 0000000..7a984a6
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#ifndef RFKILL_H
+#define RFKILL_H
+
+struct rfkill_data;
+
+struct rfkill_config {
+       void *ctx;
+       char ifname[IFNAMSIZ];
+       void (*blocked_cb)(void *ctx);
+       void (*unblocked_cb)(void *ctx);
+};
+
+struct rfkill_data * rfkill_init(struct rfkill_config *cfg);
+void rfkill_deinit(struct rfkill_data *rfkill);
+int rfkill_is_blocked(struct rfkill_data *rfkill);
+
+#endif /* RFKILL_H */
diff --git a/src/drivers/wireless_copy.h b/src/drivers/wireless_copy.h
deleted file mode 100644 (file)
index ad76466..0000000
+++ /dev/null
@@ -1,1099 +0,0 @@
-/* This is based on Linux Wireless Extensions header file from WIRELESS_EXT 18.
- * I have just removed kernel related headers and added some typedefs etc. to
- * make this easier to include into user space programs.
- * Jouni Malinen, 2005-03-12.
- */
-
-
-/*
- * This file define a set of standard wireless extensions
- *
- * Version :   19      18.3.05
- *
- * Authors :   Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2005 Jean Tourrilhes, All Rights Reserved.
- */
-
-#ifndef _LINUX_WIRELESS_H
-#define _LINUX_WIRELESS_H
-
-/************************** DOCUMENTATION **************************/
-/*
- * Initial APIs (1996 -> onward) :
- * -----------------------------
- * Basically, the wireless extensions are for now a set of standard ioctl
- * call + /proc/net/wireless
- *
- * The entry /proc/net/wireless give statistics and information on the
- * driver.
- * This is better than having each driver having its entry because
- * its centralised and we may remove the driver module safely.
- *
- * Ioctl are used to configure the driver and issue commands.  This is
- * better than command line options of insmod because we may want to
- * change dynamically (while the driver is running) some parameters.
- *
- * The ioctl mechanimsm are copied from standard devices ioctl.
- * We have the list of command plus a structure descibing the
- * data exchanged...
- * Note that to add these ioctl, I was obliged to modify :
- *     # net/core/dev.c (two place + add include)
- *     # net/ipv4/af_inet.c (one place + add include)
- *
- * /proc/net/wireless is a copy of /proc/net/dev.
- * We have a structure for data passed from the driver to /proc/net/wireless
- * Too add this, I've modified :
- *     # net/core/dev.c (two other places)
- *     # include/linux/netdevice.h (one place)
- *     # include/linux/proc_fs.h (one place)
- *
- * New driver API (2002 -> onward) :
- * -------------------------------
- * This file is only concerned with the user space API and common definitions.
- * The new driver API is defined and documented in :
- *     # include/net/iw_handler.h
- *
- * Note as well that /proc/net/wireless implementation has now moved in :
- *     # net/core/wireless.c
- *
- * Wireless Events (2002 -> onward) :
- * --------------------------------
- * Events are defined at the end of this file, and implemented in :
- *     # net/core/wireless.c
- *
- * Other comments :
- * --------------
- * Do not add here things that are redundant with other mechanisms
- * (drivers init, ifconfig, /proc/net/dev, ...) and with are not
- * wireless specific.
- *
- * These wireless extensions are not magic : each driver has to provide
- * support for them...
- *
- * IMPORTANT NOTE : As everything in the kernel, this is very much a
- * work in progress. Contact me if you have ideas of improvements...
- */
-
-/***************************** INCLUDES *****************************/
-
- /* jkm - replaced linux headers with C library headers, added typedefs */
-#if 0
-/* To minimise problems in user space, I might remove those headers
- * at some point. Jean II */
-#include <linux/types.h>               /* for "caddr_t" et al          */
-#include <linux/socket.h>              /* for "struct sockaddr" et al  */
-#include <linux/if.h>                  /* for IFNAMSIZ and co... */
-#else
-#include <sys/types.h>
-#include <net/if.h>
-typedef __uint32_t __u32;
-typedef __int32_t __s32;
-typedef __uint16_t __u16;
-typedef __int16_t __s16;
-typedef __uint8_t __u8;
-#ifndef __user
-#define __user
-#endif /* __user */
-#endif
-
-/***************************** VERSION *****************************/
-/*
- * This constant is used to know the availability of the wireless
- * extensions and to know which version of wireless extensions it is
- * (there is some stuff that will be added in the future...)
- * I just plan to increment with each new version.
- */
-#define WIRELESS_EXT   19
-
-/*
- * Changes :
- *
- * V2 to V3
- * --------
- *     Alan Cox start some incompatibles changes. I've integrated a bit more.
- *     - Encryption renamed to Encode to avoid US regulation problems
- *     - Frequency changed from float to struct to avoid problems on old 386
- *
- * V3 to V4
- * --------
- *     - Add sensitivity
- *
- * V4 to V5
- * --------
- *     - Missing encoding definitions in range
- *     - Access points stuff
- *
- * V5 to V6
- * --------
- *     - 802.11 support (ESSID ioctls)
- *
- * V6 to V7
- * --------
- *     - define IW_ESSID_MAX_SIZE and IW_MAX_AP
- *
- * V7 to V8
- * --------
- *     - Changed my e-mail address
- *     - More 802.11 support (nickname, rate, rts, frag)
- *     - List index in frequencies
- *
- * V8 to V9
- * --------
- *     - Support for 'mode of operation' (ad-hoc, managed...)
- *     - Support for unicast and multicast power saving
- *     - Change encoding to support larger tokens (>64 bits)
- *     - Updated iw_params (disable, flags) and use it for NWID
- *     - Extracted iw_point from iwreq for clarity
- *
- * V9 to V10
- * ---------
- *     - Add PM capability to range structure
- *     - Add PM modifier : MAX/MIN/RELATIVE
- *     - Add encoding option : IW_ENCODE_NOKEY
- *     - Add TxPower ioctls (work like TxRate)
- *
- * V10 to V11
- * ----------
- *     - Add WE version in range (help backward/forward compatibility)
- *     - Add retry ioctls (work like PM)
- *
- * V11 to V12
- * ----------
- *     - Add SIOCSIWSTATS to get /proc/net/wireless programatically
- *     - Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space
- *     - Add new statistics (frag, retry, beacon)
- *     - Add average quality (for user space calibration)
- *
- * V12 to V13
- * ----------
- *     - Document creation of new driver API.
- *     - Extract union iwreq_data from struct iwreq (for new driver API).
- *     - Rename SIOCSIWNAME as SIOCSIWCOMMIT
- *
- * V13 to V14
- * ----------
- *     - Wireless Events support : define struct iw_event
- *     - Define additional specific event numbers
- *     - Add "addr" and "param" fields in union iwreq_data
- *     - AP scanning stuff (SIOCSIWSCAN and friends)
- *
- * V14 to V15
- * ----------
- *     - Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg
- *     - Make struct iw_freq signed (both m & e), add explicit padding
- *     - Add IWEVCUSTOM for driver specific event/scanning token
- *     - Add IW_MAX_GET_SPY for driver returning a lot of addresses
- *     - Add IW_TXPOW_RANGE for range of Tx Powers
- *     - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points
- *     - Add IW_MODE_MONITOR for passive monitor
- *
- * V15 to V16
- * ----------
- *     - Increase the number of bitrates in iw_range to 32 (for 802.11g)
- *     - Increase the number of frequencies in iw_range to 32 (for 802.11b+a)
- *     - Reshuffle struct iw_range for increases, add filler
- *     - Increase IW_MAX_AP to 64 for driver returning a lot of addresses
- *     - Remove IW_MAX_GET_SPY because conflict with enhanced spy support
- *     - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy"
- *     - Add IW_ENCODE_TEMP and iw_range->encoding_login_index
- *
- * V16 to V17
- * ----------
- *     - Add flags to frequency -> auto/fixed
- *     - Document (struct iw_quality *)->updated, add new flags (INVALID)
- *     - Wireless Event capability in struct iw_range
- *     - Add support for relative TxPower (yick !)
- *
- * V17 to V18 (From Jouni Malinen <j@w1.fi>)
- * ----------
- *     - Add support for WPA/WPA2
- *     - Add extended encoding configuration (SIOCSIWENCODEEXT and
- *       SIOCGIWENCODEEXT)
- *     - Add SIOCSIWGENIE/SIOCGIWGENIE
- *     - Add SIOCSIWMLME
- *     - Add SIOCSIWPMKSA
- *     - Add struct iw_range bit field for supported encoding capabilities
- *     - Add optional scan request parameters for SIOCSIWSCAN
- *     - Add SIOCSIWAUTH/SIOCGIWAUTH for setting authentication and WPA
- *       related parameters (extensible up to 4096 parameter values)
- *     - Add wireless events: IWEVGENIE, IWEVMICHAELMICFAILURE,
- *       IWEVASSOCREQIE, IWEVASSOCRESPIE, IWEVPMKIDCAND
- *
- * V18 to V19
- * ----------
- *     - Remove (struct iw_point *)->pointer from events and streams
- *     - Remove header includes to help user space
- *     - Increase IW_ENCODING_TOKEN_MAX from 32 to 64
- *     - Add IW_QUAL_ALL_UPDATED and IW_QUAL_ALL_INVALID macros
- *     - Add explicit flag to tell stats are in dBm : IW_QUAL_DBM
- *     - Add IW_IOCTL_IDX() and IW_EVENT_IDX() macros
- */
-
-/**************************** CONSTANTS ****************************/
-
-/* -------------------------- IOCTL LIST -------------------------- */
-
-/* Wireless Identification */
-#define SIOCSIWCOMMIT  0x8B00          /* Commit pending changes to driver */
-#define SIOCGIWNAME    0x8B01          /* get name == wireless protocol */
-/* SIOCGIWNAME is used to verify the presence of Wireless Extensions.
- * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"...
- * Don't put the name of your driver there, it's useless. */
-
-/* Basic operations */
-#define SIOCSIWNWID    0x8B02          /* set network id (pre-802.11) */
-#define SIOCGIWNWID    0x8B03          /* get network id (the cell) */
-#define SIOCSIWFREQ    0x8B04          /* set channel/frequency (Hz) */
-#define SIOCGIWFREQ    0x8B05          /* get channel/frequency (Hz) */
-#define SIOCSIWMODE    0x8B06          /* set operation mode */
-#define SIOCGIWMODE    0x8B07          /* get operation mode */
-#define SIOCSIWSENS    0x8B08          /* set sensitivity (dBm) */
-#define SIOCGIWSENS    0x8B09          /* get sensitivity (dBm) */
-
-/* Informative stuff */
-#define SIOCSIWRANGE   0x8B0A          /* Unused */
-#define SIOCGIWRANGE   0x8B0B          /* Get range of parameters */
-#define SIOCSIWPRIV    0x8B0C          /* Unused */
-#define SIOCGIWPRIV    0x8B0D          /* get private ioctl interface info */
-#define SIOCSIWSTATS   0x8B0E          /* Unused */
-#define SIOCGIWSTATS   0x8B0F          /* Get /proc/net/wireless stats */
-/* SIOCGIWSTATS is strictly used between user space and the kernel, and
- * is never passed to the driver (i.e. the driver will never see it). */
-
-/* Spy support (statistics per MAC address - used for Mobile IP support) */
-#define SIOCSIWSPY     0x8B10          /* set spy addresses */
-#define SIOCGIWSPY     0x8B11          /* get spy info (quality of link) */
-#define SIOCSIWTHRSPY  0x8B12          /* set spy threshold (spy event) */
-#define SIOCGIWTHRSPY  0x8B13          /* get spy threshold */
-
-/* Access Point manipulation */
-#define SIOCSIWAP      0x8B14          /* set access point MAC addresses */
-#define SIOCGIWAP      0x8B15          /* get access point MAC addresses */
-#define SIOCGIWAPLIST  0x8B17          /* Deprecated in favor of scanning */
-#define SIOCSIWSCAN    0x8B18          /* trigger scanning (list cells) */
-#define SIOCGIWSCAN    0x8B19          /* get scanning results */
-
-/* 802.11 specific support */
-#define SIOCSIWESSID   0x8B1A          /* set ESSID (network name) */
-#define SIOCGIWESSID   0x8B1B          /* get ESSID */
-#define SIOCSIWNICKN   0x8B1C          /* set node name/nickname */
-#define SIOCGIWNICKN   0x8B1D          /* get node name/nickname */
-/* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit
- * within the 'iwreq' structure, so we need to use the 'data' member to
- * point to a string in user space, like it is done for RANGE... */
-
-/* Other parameters useful in 802.11 and some other devices */
-#define SIOCSIWRATE    0x8B20          /* set default bit rate (bps) */
-#define SIOCGIWRATE    0x8B21          /* get default bit rate (bps) */
-#define SIOCSIWRTS     0x8B22          /* set RTS/CTS threshold (bytes) */
-#define SIOCGIWRTS     0x8B23          /* get RTS/CTS threshold (bytes) */
-#define SIOCSIWFRAG    0x8B24          /* set fragmentation thr (bytes) */
-#define SIOCGIWFRAG    0x8B25          /* get fragmentation thr (bytes) */
-#define SIOCSIWTXPOW   0x8B26          /* set transmit power (dBm) */
-#define SIOCGIWTXPOW   0x8B27          /* get transmit power (dBm) */
-#define SIOCSIWRETRY   0x8B28          /* set retry limits and lifetime */
-#define SIOCGIWRETRY   0x8B29          /* get retry limits and lifetime */
-
-/* Encoding stuff (scrambling, hardware security, WEP...) */
-#define SIOCSIWENCODE  0x8B2A          /* set encoding token & mode */
-#define SIOCGIWENCODE  0x8B2B          /* get encoding token & mode */
-/* Power saving stuff (power management, unicast and multicast) */
-#define SIOCSIWPOWER   0x8B2C          /* set Power Management settings */
-#define SIOCGIWPOWER   0x8B2D          /* get Power Management settings */
-
-/* WPA : Generic IEEE 802.11 informatiom element (e.g., for WPA/RSN/WMM).
- * This ioctl uses struct iw_point and data buffer that includes IE id and len
- * fields. More than one IE may be included in the request. Setting the generic
- * IE to empty buffer (len=0) removes the generic IE from the driver. Drivers
- * are allowed to generate their own WPA/RSN IEs, but in these cases, drivers
- * are required to report the used IE as a wireless event, e.g., when
- * associating with an AP. */
-#define SIOCSIWGENIE   0x8B30          /* set generic IE */
-#define SIOCGIWGENIE   0x8B31          /* get generic IE */
-
-/* WPA : IEEE 802.11 MLME requests */
-#define SIOCSIWMLME    0x8B16          /* request MLME operation; uses
-                                        * struct iw_mlme */
-/* WPA : Authentication mode parameters */
-#define SIOCSIWAUTH    0x8B32          /* set authentication mode params */
-#define SIOCGIWAUTH    0x8B33          /* get authentication mode params */
-
-/* WPA : Extended version of encoding configuration */
-#define SIOCSIWENCODEEXT 0x8B34                /* set encoding token & mode */
-#define SIOCGIWENCODEEXT 0x8B35                /* get encoding token & mode */
-
-/* WPA2 : PMKSA cache management */
-#define SIOCSIWPMKSA   0x8B36          /* PMKSA cache operation */
-
-/* -------------------- DEV PRIVATE IOCTL LIST -------------------- */
-
-/* These 32 ioctl are wireless device private, for 16 commands.
- * Each driver is free to use them for whatever purpose it chooses,
- * however the driver *must* export the description of those ioctls
- * with SIOCGIWPRIV and *must* use arguments as defined below.
- * If you don't follow those rules, DaveM is going to hate you (reason :
- * it make mixed 32/64bit operation impossible).
- */
-#define SIOCIWFIRSTPRIV        0x8BE0
-#define SIOCIWLASTPRIV 0x8BFF
-/* Previously, we were using SIOCDEVPRIVATE, but we now have our
- * separate range because of collisions with other tools such as
- * 'mii-tool'.
- * We now have 32 commands, so a bit more space ;-).
- * Also, all 'odd' commands are only usable by root and don't return the
- * content of ifr/iwr to user (but you are not obliged to use the set/get
- * convention, just use every other two command). More details in iwpriv.c.
- * And I repeat : you are not forced to use them with iwpriv, but you
- * must be compliant with it.
- */
-
-/* ------------------------- IOCTL STUFF ------------------------- */
-
-/* The first and the last (range) */
-#define SIOCIWFIRST    0x8B00
-#define SIOCIWLAST     SIOCIWLASTPRIV          /* 0x8BFF */
-#define IW_IOCTL_IDX(cmd)      ((cmd) - SIOCIWFIRST)
-
-/* Even : get (world access), odd : set (root access) */
-#define IW_IS_SET(cmd) (!((cmd) & 0x1))
-#define IW_IS_GET(cmd) ((cmd) & 0x1)
-
-/* ----------------------- WIRELESS EVENTS ----------------------- */
-/* Those are *NOT* ioctls, do not issue request on them !!! */
-/* Most events use the same identifier as ioctl requests */
-
-#define IWEVTXDROP     0x8C00          /* Packet dropped to excessive retry */
-#define IWEVQUAL       0x8C01          /* Quality part of statistics (scan) */
-#define IWEVCUSTOM     0x8C02          /* Driver specific ascii string */
-#define IWEVREGISTERED 0x8C03          /* Discovered a new node (AP mode) */
-#define IWEVEXPIRED    0x8C04          /* Expired a node (AP mode) */
-#define IWEVGENIE      0x8C05          /* Generic IE (WPA, RSN, WMM, ..)
-                                        * (scan results); This includes id and
-                                        * length fields. One IWEVGENIE may
-                                        * contain more than one IE. Scan
-                                        * results may contain one or more
-                                        * IWEVGENIE events. */
-#define IWEVMICHAELMICFAILURE 0x8C06   /* Michael MIC failure
-                                        * (struct iw_michaelmicfailure)
-                                        */
-#define IWEVASSOCREQIE 0x8C07          /* IEs used in (Re)Association Request.
-                                        * The data includes id and length
-                                        * fields and may contain more than one
-                                        * IE. This event is required in
-                                        * Managed mode if the driver
-                                        * generates its own WPA/RSN IE. This
-                                        * should be sent just before
-                                        * IWEVREGISTERED event for the
-                                        * association. */
-#define IWEVASSOCRESPIE        0x8C08          /* IEs used in (Re)Association
-                                        * Response. The data includes id and
-                                        * length fields and may contain more
-                                        * than one IE. This may be sent
-                                        * between IWEVASSOCREQIE and
-                                        * IWEVREGISTERED events for the
-                                        * association. */
-#define IWEVPMKIDCAND  0x8C09          /* PMKID candidate for RSN
-                                        * pre-authentication
-                                        * (struct iw_pmkid_cand) */
-
-#define IWEVFIRST      0x8C00
-#define IW_EVENT_IDX(cmd)      ((cmd) - IWEVFIRST)
-
-/* ------------------------- PRIVATE INFO ------------------------- */
-/*
- * The following is used with SIOCGIWPRIV. It allow a driver to define
- * the interface (name, type of data) for its private ioctl.
- * Privates ioctl are SIOCIWFIRSTPRIV -> SIOCIWLASTPRIV
- */
-
-#define IW_PRIV_TYPE_MASK      0x7000  /* Type of arguments */
-#define IW_PRIV_TYPE_NONE      0x0000
-#define IW_PRIV_TYPE_BYTE      0x1000  /* Char as number */
-#define IW_PRIV_TYPE_CHAR      0x2000  /* Char as character */
-#define IW_PRIV_TYPE_INT       0x4000  /* 32 bits int */
-#define IW_PRIV_TYPE_FLOAT     0x5000  /* struct iw_freq */
-#define IW_PRIV_TYPE_ADDR      0x6000  /* struct sockaddr */
-
-#define IW_PRIV_SIZE_FIXED     0x0800  /* Variable or fixed number of args */
-
-#define IW_PRIV_SIZE_MASK      0x07FF  /* Max number of those args */
-
-/*
- * Note : if the number of args is fixed and the size < 16 octets,
- * instead of passing a pointer we will put args in the iwreq struct...
- */
-
-/* ----------------------- OTHER CONSTANTS ----------------------- */
-
-/* Maximum frequencies in the range struct */
-#define IW_MAX_FREQUENCIES     32
-/* Note : if you have something like 80 frequencies,
- * don't increase this constant and don't fill the frequency list.
- * The user will be able to set by channel anyway... */
-
-/* Maximum bit rates in the range struct */
-#define IW_MAX_BITRATES                32
-
-/* Maximum tx powers in the range struct */
-#define IW_MAX_TXPOWER         8
-/* Note : if you more than 8 TXPowers, just set the max and min or
- * a few of them in the struct iw_range. */
-
-/* Maximum of address that you may set with SPY */
-#define IW_MAX_SPY             8
-
-/* Maximum of address that you may get in the
-   list of access points in range */
-#define IW_MAX_AP              64
-
-/* Maximum size of the ESSID and NICKN strings */
-#define IW_ESSID_MAX_SIZE      32
-
-/* Modes of operation */
-#define IW_MODE_AUTO   0       /* Let the driver decides */
-#define IW_MODE_ADHOC  1       /* Single cell network */
-#define IW_MODE_INFRA  2       /* Multi cell network, roaming, ... */
-#define IW_MODE_MASTER 3       /* Synchronisation master or Access Point */
-#define IW_MODE_REPEAT 4       /* Wireless Repeater (forwarder) */
-#define IW_MODE_SECOND 5       /* Secondary master/repeater (backup) */
-#define IW_MODE_MONITOR        6       /* Passive monitor (listen only) */
-
-/* Statistics flags (bitmask in updated) */
-#define IW_QUAL_QUAL_UPDATED   0x01    /* Value was updated since last read */
-#define IW_QUAL_LEVEL_UPDATED  0x02
-#define IW_QUAL_NOISE_UPDATED  0x04
-#define IW_QUAL_ALL_UPDATED    0x07
-#define IW_QUAL_DBM            0x08    /* Level + Noise are dBm */
-#define IW_QUAL_QUAL_INVALID   0x10    /* Driver doesn't provide value */
-#define IW_QUAL_LEVEL_INVALID  0x20
-#define IW_QUAL_NOISE_INVALID  0x40
-#define IW_QUAL_ALL_INVALID    0x70
-
-/* Frequency flags */
-#define IW_FREQ_AUTO           0x00    /* Let the driver decides */
-#define IW_FREQ_FIXED          0x01    /* Force a specific value */
-
-/* Maximum number of size of encoding token available
- * they are listed in the range structure */
-#define IW_MAX_ENCODING_SIZES  8
-
-/* Maximum size of the encoding token in bytes */
-#define IW_ENCODING_TOKEN_MAX  64      /* 512 bits (for now) */
-
-/* Flags for encoding (along with the token) */
-#define IW_ENCODE_INDEX                0x00FF  /* Token index (if needed) */
-#define IW_ENCODE_FLAGS                0xFF00  /* Flags defined below */
-#define IW_ENCODE_MODE         0xF000  /* Modes defined below */
-#define IW_ENCODE_DISABLED     0x8000  /* Encoding disabled */
-#define IW_ENCODE_ENABLED      0x0000  /* Encoding enabled */
-#define IW_ENCODE_RESTRICTED   0x4000  /* Refuse non-encoded packets */
-#define IW_ENCODE_OPEN         0x2000  /* Accept non-encoded packets */
-#define IW_ENCODE_NOKEY                0x0800  /* Key is write only, so not present */
-#define IW_ENCODE_TEMP         0x0400  /* Temporary key */
-
-/* Power management flags available (along with the value, if any) */
-#define IW_POWER_ON            0x0000  /* No details... */
-#define IW_POWER_TYPE          0xF000  /* Type of parameter */
-#define IW_POWER_PERIOD                0x1000  /* Value is a period/duration of  */
-#define IW_POWER_TIMEOUT       0x2000  /* Value is a timeout (to go asleep) */
-#define IW_POWER_MODE          0x0F00  /* Power Management mode */
-#define IW_POWER_UNICAST_R     0x0100  /* Receive only unicast messages */
-#define IW_POWER_MULTICAST_R   0x0200  /* Receive only multicast messages */
-#define IW_POWER_ALL_R         0x0300  /* Receive all messages though PM */
-#define IW_POWER_FORCE_S       0x0400  /* Force PM procedure for sending unicast */
-#define IW_POWER_REPEATER      0x0800  /* Repeat broadcast messages in PM period */
-#define IW_POWER_MODIFIER      0x000F  /* Modify a parameter */
-#define IW_POWER_MIN           0x0001  /* Value is a minimum  */
-#define IW_POWER_MAX           0x0002  /* Value is a maximum */
-#define IW_POWER_RELATIVE      0x0004  /* Value is not in seconds/ms/us */
-
-/* Transmit Power flags available */
-#define IW_TXPOW_TYPE          0x00FF  /* Type of value */
-#define IW_TXPOW_DBM           0x0000  /* Value is in dBm */
-#define IW_TXPOW_MWATT         0x0001  /* Value is in mW */
-#define IW_TXPOW_RELATIVE      0x0002  /* Value is in arbitrary units */
-#define IW_TXPOW_RANGE         0x1000  /* Range of value between min/max */
-
-/* Retry limits and lifetime flags available */
-#define IW_RETRY_ON            0x0000  /* No details... */
-#define IW_RETRY_TYPE          0xF000  /* Type of parameter */
-#define IW_RETRY_LIMIT         0x1000  /* Maximum number of retries*/
-#define IW_RETRY_LIFETIME      0x2000  /* Maximum duration of retries in us */
-#define IW_RETRY_MODIFIER      0x000F  /* Modify a parameter */
-#define IW_RETRY_MIN           0x0001  /* Value is a minimum  */
-#define IW_RETRY_MAX           0x0002  /* Value is a maximum */
-#define IW_RETRY_RELATIVE      0x0004  /* Value is not in seconds/ms/us */
-
-/* Scanning request flags */
-#define IW_SCAN_DEFAULT                0x0000  /* Default scan of the driver */
-#define IW_SCAN_ALL_ESSID      0x0001  /* Scan all ESSIDs */
-#define IW_SCAN_THIS_ESSID     0x0002  /* Scan only this ESSID */
-#define IW_SCAN_ALL_FREQ       0x0004  /* Scan all Frequencies */
-#define IW_SCAN_THIS_FREQ      0x0008  /* Scan only this Frequency */
-#define IW_SCAN_ALL_MODE       0x0010  /* Scan all Modes */
-#define IW_SCAN_THIS_MODE      0x0020  /* Scan only this Mode */
-#define IW_SCAN_ALL_RATE       0x0040  /* Scan all Bit-Rates */
-#define IW_SCAN_THIS_RATE      0x0080  /* Scan only this Bit-Rate */
-/* struct iw_scan_req scan_type */
-#define IW_SCAN_TYPE_ACTIVE 0
-#define IW_SCAN_TYPE_PASSIVE 1
-/* Maximum size of returned data */
-#define IW_SCAN_MAX_DATA       4096    /* In bytes */
-
-/* Max number of char in custom event - use multiple of them if needed */
-#define IW_CUSTOM_MAX          256     /* In bytes */
-
-/* Generic information element */
-#define IW_GENERIC_IE_MAX      1024
-
-/* MLME requests (SIOCSIWMLME / struct iw_mlme) */
-#define IW_MLME_DEAUTH         0
-#define IW_MLME_DISASSOC       1
-
-/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */
-#define IW_AUTH_INDEX          0x0FFF
-#define IW_AUTH_FLAGS          0xF000
-/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095)
- * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the
- * parameter that is being set/get to; value will be read/written to
- * struct iw_param value field) */
-#define IW_AUTH_WPA_VERSION            0
-#define IW_AUTH_CIPHER_PAIRWISE                1
-#define IW_AUTH_CIPHER_GROUP           2
-#define IW_AUTH_KEY_MGMT               3
-#define IW_AUTH_TKIP_COUNTERMEASURES   4
-#define IW_AUTH_DROP_UNENCRYPTED       5
-#define IW_AUTH_80211_AUTH_ALG         6
-#define IW_AUTH_WPA_ENABLED            7
-#define IW_AUTH_RX_UNENCRYPTED_EAPOL   8
-#define IW_AUTH_ROAMING_CONTROL                9
-#define IW_AUTH_PRIVACY_INVOKED                10
-#define IW_AUTH_CIPHER_GROUP_MGMT      11
-#define IW_AUTH_MFP                    12
-
-/* IW_AUTH_WPA_VERSION values (bit field) */
-#define IW_AUTH_WPA_VERSION_DISABLED   0x00000001
-#define IW_AUTH_WPA_VERSION_WPA                0x00000002
-#define IW_AUTH_WPA_VERSION_WPA2       0x00000004
-
-/* IW_AUTH_PAIRWISE_CIPHER and IW_AUTH_GROUP_CIPHER values (bit field) */
-#define IW_AUTH_CIPHER_NONE    0x00000001
-#define IW_AUTH_CIPHER_WEP40   0x00000002
-#define IW_AUTH_CIPHER_TKIP    0x00000004
-#define IW_AUTH_CIPHER_CCMP    0x00000008
-#define IW_AUTH_CIPHER_WEP104  0x00000010
-
-/* IW_AUTH_KEY_MGMT values (bit field) */
-#define IW_AUTH_KEY_MGMT_802_1X        1
-#define IW_AUTH_KEY_MGMT_PSK   2
-
-/* IW_AUTH_80211_AUTH_ALG values (bit field) */
-#define IW_AUTH_ALG_OPEN_SYSTEM        0x00000001
-#define IW_AUTH_ALG_SHARED_KEY 0x00000002
-#define IW_AUTH_ALG_LEAP       0x00000004
-
-/* IW_AUTH_ROAMING_CONTROL values */
-#define IW_AUTH_ROAMING_ENABLE 0       /* driver/firmware based roaming */
-#define IW_AUTH_ROAMING_DISABLE        1       /* user space program used for roaming
-                                        * control */
-
-/* IW_AUTH_MFP (management frame protection) values */
-#define IW_AUTH_MFP_DISABLED   0       /* MFP disabled */
-#define IW_AUTH_MFP_OPTIONAL   1       /* MFP optional */
-#define IW_AUTH_MFP_REQUIRED   2       /* MFP required */
-
-/* SIOCSIWENCODEEXT definitions */
-#define IW_ENCODE_SEQ_MAX_SIZE 8
-/* struct iw_encode_ext ->alg */
-#define IW_ENCODE_ALG_NONE     0
-#define IW_ENCODE_ALG_WEP      1
-#define IW_ENCODE_ALG_TKIP     2
-#define IW_ENCODE_ALG_CCMP     3
-#define IW_ENCODE_ALG_PMK      4
-#define IW_ENCODE_ALG_AES_CMAC 5
-/* struct iw_encode_ext ->ext_flags */
-#define IW_ENCODE_EXT_TX_SEQ_VALID     0x00000001
-#define IW_ENCODE_EXT_RX_SEQ_VALID     0x00000002
-#define IW_ENCODE_EXT_GROUP_KEY                0x00000004
-#define IW_ENCODE_EXT_SET_TX_KEY       0x00000008
-
-/* IWEVMICHAELMICFAILURE : struct iw_michaelmicfailure ->flags */
-#define IW_MICFAILURE_KEY_ID   0x00000003 /* Key ID 0..3 */
-#define IW_MICFAILURE_GROUP    0x00000004
-#define IW_MICFAILURE_PAIRWISE 0x00000008
-#define IW_MICFAILURE_STAKEY   0x00000010
-#define IW_MICFAILURE_COUNT    0x00000060 /* 1 or 2 (0 = count not supported)
-                                           */
-
-/* Bit field values for enc_capa in struct iw_range */
-#define IW_ENC_CAPA_WPA                0x00000001
-#define IW_ENC_CAPA_WPA2       0x00000002
-#define IW_ENC_CAPA_CIPHER_TKIP        0x00000004
-#define IW_ENC_CAPA_CIPHER_CCMP        0x00000008
-#define IW_ENC_CAPA_4WAY_HANDSHAKE     0x00000010
-
-/* Event capability macros - in (struct iw_range *)->event_capa
- * Because we have more than 32 possible events, we use an array of
- * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */
-#define IW_EVENT_CAPA_BASE(cmd)                ((cmd >= SIOCIWFIRSTPRIV) ? \
-                                        (cmd - SIOCIWFIRSTPRIV + 0x60) : \
-                                        (cmd - SIOCSIWCOMMIT))
-#define IW_EVENT_CAPA_INDEX(cmd)       (IW_EVENT_CAPA_BASE(cmd) >> 5)
-#define IW_EVENT_CAPA_MASK(cmd)                (1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F))
-/* Event capability constants - event autogenerated by the kernel
- * This list is valid for most 802.11 devices, customise as needed... */
-#define IW_EVENT_CAPA_K_0      (IW_EVENT_CAPA_MASK(0x8B04) | \
-                                IW_EVENT_CAPA_MASK(0x8B06) | \
-                                IW_EVENT_CAPA_MASK(0x8B1A))
-#define IW_EVENT_CAPA_K_1      (IW_EVENT_CAPA_MASK(0x8B2A))
-/* "Easy" macro to set events in iw_range (less efficient) */
-#define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd))
-#define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; }
-
-
-/****************************** TYPES ******************************/
-
-/* --------------------------- SUBTYPES --------------------------- */
-/*
- *     Generic format for most parameters that fit in an int
- */
-struct iw_param
-{
-  __s32                value;          /* The value of the parameter itself */
-  __u8         fixed;          /* Hardware should not use auto select */
-  __u8         disabled;       /* Disable the feature */
-  __u16                flags;          /* Various specifc flags (if any) */
-};
-
-/*
- *     For all data larger than 16 octets, we need to use a
- *     pointer to memory allocated in user space.
- */
-struct iw_point
-{
-  void __user  *pointer;       /* Pointer to the data  (in user space) */
-  __u16                length;         /* number of fields or size in bytes */
-  __u16                flags;          /* Optional params */
-};
-
-/*
- *     A frequency
- *     For numbers lower than 10^9, we encode the number in 'm' and
- *     set 'e' to 0
- *     For number greater than 10^9, we divide it by the lowest power
- *     of 10 to get 'm' lower than 10^9, with 'm'= f / (10^'e')...
- *     The power of 10 is in 'e', the result of the division is in 'm'.
- */
-struct iw_freq
-{
-       __s32           m;              /* Mantissa */
-       __s16           e;              /* Exponent */
-       __u8            i;              /* List index (when in range struct) */
-       __u8            flags;          /* Flags (fixed/auto) */
-};
-
-/*
- *     Quality of the link
- */
-struct iw_quality
-{
-       __u8            qual;           /* link quality (%retries, SNR,
-                                          %missed beacons or better...) */
-       __u8            level;          /* signal level (dBm) */
-       __u8            noise;          /* noise level (dBm) */
-       __u8            updated;        /* Flags to know if updated */
-};
-
-/*
- *     Packet discarded in the wireless adapter due to
- *     "wireless" specific problems...
- *     Note : the list of counter and statistics in net_device_stats
- *     is already pretty exhaustive, and you should use that first.
- *     This is only additional stats...
- */
-struct iw_discarded
-{
-       __u32           nwid;           /* Rx : Wrong nwid/essid */
-       __u32           code;           /* Rx : Unable to code/decode (WEP) */
-       __u32           fragment;       /* Rx : Can't perform MAC reassembly */
-       __u32           retries;        /* Tx : Max MAC retries num reached */
-       __u32           misc;           /* Others cases */
-};
-
-/*
- *     Packet/Time period missed in the wireless adapter due to
- *     "wireless" specific problems...
- */
-struct iw_missed
-{
-       __u32           beacon;         /* Missed beacons/superframe */
-};
-
-/*
- *     Quality range (for spy threshold)
- */
-struct iw_thrspy
-{
-       struct sockaddr         addr;           /* Source address (hw/mac) */
-       struct iw_quality       qual;           /* Quality of the link */
-       struct iw_quality       low;            /* Low threshold */
-       struct iw_quality       high;           /* High threshold */
-};
-
-/*
- *     Optional data for scan request
- *
- *     Note: these optional parameters are controlling parameters for the
- *     scanning behavior, these do not apply to getting scan results
- *     (SIOCGIWSCAN). Drivers are expected to keep a local BSS table and
- *     provide a merged results with all BSSes even if the previous scan
- *     request limited scanning to a subset, e.g., by specifying an SSID.
- *     Especially, scan results are required to include an entry for the
- *     current BSS if the driver is in Managed mode and associated with an AP.
- */
-struct iw_scan_req
-{
-       __u8            scan_type; /* IW_SCAN_TYPE_{ACTIVE,PASSIVE} */
-       __u8            essid_len;
-       __u8            num_channels; /* num entries in channel_list;
-                                      * 0 = scan all allowed channels */
-       __u8            flags; /* reserved as padding; use zero, this may
-                               * be used in the future for adding flags
-                               * to request different scan behavior */
-       struct sockaddr bssid; /* ff:ff:ff:ff:ff:ff for broadcast BSSID or
-                               * individual address of a specific BSS */
-
-       /*
-        * Use this ESSID if IW_SCAN_THIS_ESSID flag is used instead of using
-        * the current ESSID. This allows scan requests for specific ESSID
-        * without having to change the current ESSID and potentially breaking
-        * the current association.
-        */
-       __u8            essid[IW_ESSID_MAX_SIZE];
-
-       /*
-        * Optional parameters for changing the default scanning behavior.
-        * These are based on the MLME-SCAN.request from IEEE Std 802.11.
-        * TU is 1.024 ms. If these are set to 0, driver is expected to use
-        * reasonable default values. min_channel_time defines the time that
-        * will be used to wait for the first reply on each channel. If no
-        * replies are received, next channel will be scanned after this. If
-        * replies are received, total time waited on the channel is defined by
-        * max_channel_time.
-        */
-       __u32           min_channel_time; /* in TU */
-       __u32           max_channel_time; /* in TU */
-
-       struct iw_freq  channel_list[IW_MAX_FREQUENCIES];
-};
-
-/* ------------------------- WPA SUPPORT ------------------------- */
-
-/*
- *     Extended data structure for get/set encoding (this is used with
- *     SIOCSIWENCODEEXT/SIOCGIWENCODEEXT. struct iw_point and IW_ENCODE_*
- *     flags are used in the same way as with SIOCSIWENCODE/SIOCGIWENCODE and
- *     only the data contents changes (key data -> this structure, including
- *     key data).
- *
- *     If the new key is the first group key, it will be set as the default
- *     TX key. Otherwise, default TX key index is only changed if
- *     IW_ENCODE_EXT_SET_TX_KEY flag is set.
- *
- *     Key will be changed with SIOCSIWENCODEEXT in all cases except for
- *     special "change TX key index" operation which is indicated by setting
- *     key_len = 0 and ext_flags |= IW_ENCODE_EXT_SET_TX_KEY.
- *
- *     tx_seq/rx_seq are only used when respective
- *     IW_ENCODE_EXT_{TX,RX}_SEQ_VALID flag is set in ext_flags. Normal
- *     TKIP/CCMP operation is to set RX seq with SIOCSIWENCODEEXT and start
- *     TX seq from zero whenever key is changed. SIOCGIWENCODEEXT is normally
- *     used only by an Authenticator (AP or an IBSS station) to get the
- *     current TX sequence number. Using TX_SEQ_VALID for SIOCSIWENCODEEXT and
- *     RX_SEQ_VALID for SIOCGIWENCODEEXT are optional, but can be useful for
- *     debugging/testing.
- */
-struct iw_encode_ext
-{
-       __u32           ext_flags; /* IW_ENCODE_EXT_* */
-       __u8            tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
-       __u8            rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
-       struct sockaddr addr; /* ff:ff:ff:ff:ff:ff for broadcast/multicast
-                              * (group) keys or unicast address for
-                              * individual keys */
-       __u16           alg; /* IW_ENCODE_ALG_* */
-       __u16           key_len;
-       __u8            key[0];
-};
-
-/* SIOCSIWMLME data */
-struct iw_mlme
-{
-       __u16           cmd; /* IW_MLME_* */
-       __u16           reason_code;
-       struct sockaddr addr;
-};
-
-/* SIOCSIWPMKSA data */
-#define IW_PMKSA_ADD           1
-#define IW_PMKSA_REMOVE                2
-#define IW_PMKSA_FLUSH         3
-
-#define IW_PMKID_LEN   16
-
-struct iw_pmksa
-{
-       __u32           cmd; /* IW_PMKSA_* */
-       struct sockaddr bssid;
-       __u8            pmkid[IW_PMKID_LEN];
-};
-
-/* IWEVMICHAELMICFAILURE data */
-struct iw_michaelmicfailure
-{
-       __u32           flags;
-       struct sockaddr src_addr;
-       __u8            tsc[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
-};
-
-/* IWEVPMKIDCAND data */
-#define IW_PMKID_CAND_PREAUTH  0x00000001 /* RNS pre-authentication enabled */
-struct iw_pmkid_cand
-{
-       __u32           flags; /* IW_PMKID_CAND_* */
-       __u32           index; /* the smaller the index, the higher the
-                               * priority */
-       struct sockaddr bssid;
-};
-
-/* ------------------------ WIRELESS STATS ------------------------ */
-/*
- * Wireless statistics (used for /proc/net/wireless)
- */
-struct iw_statistics
-{
-       __u16           status;         /* Status
-                                        * - device dependent for now */
-
-       struct iw_quality       qual;           /* Quality of the link
-                                                * (instant/mean/max) */
-       struct iw_discarded     discard;        /* Packet discarded counts */
-       struct iw_missed        miss;           /* Packet missed counts */
-};
-
-/* ------------------------ IOCTL REQUEST ------------------------ */
-/*
- * This structure defines the payload of an ioctl, and is used 
- * below.
- *
- * Note that this structure should fit on the memory footprint
- * of iwreq (which is the same as ifreq), which mean a max size of
- * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
- * You should check this when increasing the structures defined
- * above in this file...
- */
-union  iwreq_data
-{
-       /* Config - generic */
-       char            name[IFNAMSIZ];
-       /* Name : used to verify the presence of  wireless extensions.
-        * Name of the protocol/provider... */
-
-       struct iw_point essid;          /* Extended network name */
-       struct iw_param nwid;           /* network id (or domain - the cell) */
-       struct iw_freq  freq;           /* frequency or channel :
-                                        * 0-1000 = channel
-                                        * > 1000 = frequency in Hz */
-
-       struct iw_param sens;           /* signal level threshold */
-       struct iw_param bitrate;        /* default bit rate */
-       struct iw_param txpower;        /* default transmit power */
-       struct iw_param rts;            /* RTS threshold threshold */
-       struct iw_param frag;           /* Fragmentation threshold */
-       __u32           mode;           /* Operation mode */
-       struct iw_param retry;          /* Retry limits & lifetime */
-
-       struct iw_point encoding;       /* Encoding stuff : tokens */
-       struct iw_param power;          /* PM duration/timeout */
-       struct iw_quality qual;         /* Quality part of statistics */
-
-       struct sockaddr ap_addr;        /* Access point address */
-       struct sockaddr addr;           /* Destination address (hw/mac) */
-
-       struct iw_param param;          /* Other small parameters */
-       struct iw_point data;           /* Other large parameters */
-};
-
-/*
- * The structure to exchange data for ioctl.
- * This structure is the same as 'struct ifreq', but (re)defined for
- * convenience...
- * Do I need to remind you about structure size (32 octets) ?
- */
-struct iwreq 
-{
-       union
-       {
-               char    ifrn_name[IFNAMSIZ];    /* if name, e.g. "eth0" */
-       } ifr_ifrn;
-
-       /* Data part (defined just above) */
-       union   iwreq_data      u;
-};
-
-/* -------------------------- IOCTL DATA -------------------------- */
-/*
- *     For those ioctl which want to exchange mode data that what could
- *     fit in the above structure...
- */
-
-/*
- *     Range of parameters
- */
-
-struct iw_range
-{
-       /* Informative stuff (to choose between different interface) */
-       __u32           throughput;     /* To give an idea... */
-       /* In theory this value should be the maximum benchmarked
-        * TCP/IP throughput, because with most of these devices the
-        * bit rate is meaningless (overhead an co) to estimate how
-        * fast the connection will go and pick the fastest one.
-        * I suggest people to play with Netperf or any benchmark...
-        */
-
-       /* NWID (or domain id) */
-       __u32           min_nwid;       /* Minimal NWID we are able to set */
-       __u32           max_nwid;       /* Maximal NWID we are able to set */
-
-       /* Old Frequency (backward compat - moved lower ) */
-       __u16           old_num_channels;
-       __u8            old_num_frequency;
-
-       /* Wireless event capability bitmasks */
-       __u32           event_capa[6];
-
-       /* signal level threshold range */
-       __s32           sensitivity;
-
-       /* Quality of link & SNR stuff */
-       /* Quality range (link, level, noise)
-        * If the quality is absolute, it will be in the range [0 ; max_qual],
-        * if the quality is dBm, it will be in the range [max_qual ; 0].
-        * Don't forget that we use 8 bit arithmetics... */
-       struct iw_quality       max_qual;       /* Quality of the link */
-       /* This should contain the average/typical values of the quality
-        * indicator. This should be the threshold between a "good" and
-        * a "bad" link (example : monitor going from green to orange).
-        * Currently, user space apps like quality monitors don't have any
-        * way to calibrate the measurement. With this, they can split
-        * the range between 0 and max_qual in different quality level
-        * (using a geometric subdivision centered on the average).
-        * I expect that people doing the user space apps will feedback
-        * us on which value we need to put in each driver... */
-       struct iw_quality       avg_qual;       /* Quality of the link */
-
-       /* Rates */
-       __u8            num_bitrates;   /* Number of entries in the list */
-       __s32           bitrate[IW_MAX_BITRATES];       /* list, in bps */
-
-       /* RTS threshold */
-       __s32           min_rts;        /* Minimal RTS threshold */
-       __s32           max_rts;        /* Maximal RTS threshold */
-
-       /* Frag threshold */
-       __s32           min_frag;       /* Minimal frag threshold */
-       __s32           max_frag;       /* Maximal frag threshold */
-
-       /* Power Management duration & timeout */
-       __s32           min_pmp;        /* Minimal PM period */
-       __s32           max_pmp;        /* Maximal PM period */
-       __s32           min_pmt;        /* Minimal PM timeout */
-       __s32           max_pmt;        /* Maximal PM timeout */
-       __u16           pmp_flags;      /* How to decode max/min PM period */
-       __u16           pmt_flags;      /* How to decode max/min PM timeout */
-       __u16           pm_capa;        /* What PM options are supported */
-
-       /* Encoder stuff */
-       __u16   encoding_size[IW_MAX_ENCODING_SIZES];   /* Different token sizes */
-       __u8    num_encoding_sizes;     /* Number of entry in the list */
-       __u8    max_encoding_tokens;    /* Max number of tokens */
-       /* For drivers that need a "login/passwd" form */
-       __u8    encoding_login_index;   /* token index for login token */
-
-       /* Transmit power */
-       __u16           txpower_capa;   /* What options are supported */
-       __u8            num_txpower;    /* Number of entries in the list */
-       __s32           txpower[IW_MAX_TXPOWER];        /* list, in bps */
-
-       /* Wireless Extension version info */
-       __u8            we_version_compiled;    /* Must be WIRELESS_EXT */
-       __u8            we_version_source;      /* Last update of source */
-
-       /* Retry limits and lifetime */
-       __u16           retry_capa;     /* What retry options are supported */
-       __u16           retry_flags;    /* How to decode max/min retry limit */
-       __u16           r_time_flags;   /* How to decode max/min retry life */
-       __s32           min_retry;      /* Minimal number of retries */
-       __s32           max_retry;      /* Maximal number of retries */
-       __s32           min_r_time;     /* Minimal retry lifetime */
-       __s32           max_r_time;     /* Maximal retry lifetime */
-
-       /* Frequency */
-       __u16           num_channels;   /* Number of channels [0; num - 1] */
-       __u8            num_frequency;  /* Number of entry in the list */
-       struct iw_freq  freq[IW_MAX_FREQUENCIES];       /* list */
-       /* Note : this frequency list doesn't need to fit channel numbers,
-        * because each entry contain its channel index */
-
-       __u32           enc_capa; /* IW_ENC_CAPA_* bit field */
-};
-
-/*
- * Private ioctl interface information
- */
-struct iw_priv_args
-{
-       __u32           cmd;            /* Number of the ioctl to issue */
-       __u16           set_args;       /* Type and number of args */
-       __u16           get_args;       /* Type and number of args */
-       char            name[IFNAMSIZ]; /* Name of the extension */
-};
-
-/* ----------------------- WIRELESS EVENTS ----------------------- */
-/*
- * Wireless events are carried through the rtnetlink socket to user
- * space. They are encapsulated in the IFLA_WIRELESS field of
- * a RTM_NEWLINK message.
- */
-
-/*
- * A Wireless Event. Contains basically the same data as the ioctl...
- */
-struct iw_event
-{
-       __u16           len;                    /* Real lenght of this stuff */
-       __u16           cmd;                    /* Wireless IOCTL */
-       union iwreq_data        u;              /* IOCTL fixed payload */
-};
-
-/* Size of the Event prefix (including padding and alignement junk) */
-#define IW_EV_LCP_LEN  (sizeof(struct iw_event) - sizeof(union iwreq_data))
-/* Size of the various events */
-#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ)
-#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32))
-#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq))
-#define IW_EV_PARAM_LEN        (IW_EV_LCP_LEN + sizeof(struct iw_param))
-#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr))
-#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality))
-
-/* iw_point events are special. First, the payload (extra data) come at
- * the end of the event, so they are bigger than IW_EV_POINT_LEN. Second,
- * we omit the pointer, so start at an offset. */
-#define IW_EV_POINT_OFF (((char *) &(((struct iw_point *) NULL)->length)) - \
-                         (char *) NULL)
-#define IW_EV_POINT_LEN        (IW_EV_LCP_LEN + sizeof(struct iw_point) - \
-                        IW_EV_POINT_OFF)
-
-#endif /* _LINUX_WIRELESS_H */
index 0efe7ab..3035301 100644 (file)
@@ -68,6 +68,7 @@ typedef enum {
        EAP_TYPE_IKEV2 = 49 /* RFC 5106 */,
        EAP_TYPE_AKA_PRIME = 50 /* draft-arkko-eap-aka-kdf-10.txt */,
        EAP_TYPE_GPSK = 51 /* RFC 5433 */,
+       EAP_TYPE_PWD = 52 /* RFC 5931 */,
        EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
 } EapType;
 
index 4de34a8..d3406f3 100644 (file)
@@ -133,9 +133,9 @@ u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
 
        wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
                        "expansion", keys.master_key, keys.master_key_len);
-       if (tls_prf(keys.master_key, keys.master_key_len,
-                   label, rnd, keys.client_random_len +
-                   keys.server_random_len, out, block_size + len))
+       if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
+                            label, rnd, keys.client_random_len +
+                            keys.server_random_len, out, block_size + len))
                goto fail;
        os_free(rnd);
        os_memmove(out, out + block_size, len);
index 3a64b8e..8a701d2 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP-PEAP common routines
- * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ * 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
@@ -18,9 +18,9 @@
 #include "crypto/sha1.h"
 #include "eap_peap_common.h"
 
-void peap_prfplus(int version, const u8 *key, size_t key_len,
-                 const char *label, const u8 *seed, size_t seed_len,
-                 u8 *buf, size_t buf_len)
+int peap_prfplus(int version, const u8 *key, size_t key_len,
+                const char *label, const u8 *seed, size_t seed_len,
+                u8 *buf, size_t buf_len)
 {
        unsigned char counter = 0;
        size_t pos, plen;
@@ -75,7 +75,8 @@ void peap_prfplus(int version, const u8 *key, size_t key_len,
        while (pos < buf_len) {
                counter++;
                plen = buf_len - pos;
-               hmac_sha1_vector(key, key_len, 5, addr, len, hash);
+               if (hmac_sha1_vector(key, key_len, 5, addr, len, hash) < 0)
+                       return -1;
                if (plen >= SHA1_MAC_LEN) {
                        os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
                        pos += SHA1_MAC_LEN;
@@ -85,4 +86,6 @@ void peap_prfplus(int version, const u8 *key, size_t key_len,
                }
                len[0] = SHA1_MAC_LEN;
        }
+
+       return 0;
 }
index f59afb0..f182078 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP-PEAP common routines
- * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ * 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
@@ -15,8 +15,8 @@
 #ifndef EAP_PEAP_COMMON_H
 #define EAP_PEAP_COMMON_H
 
-void peap_prfplus(int version, const u8 *key, size_t key_len,
-                 const char *label, const u8 *seed, size_t seed_len,
-                 u8 *buf, size_t buf_len);
+int peap_prfplus(int version, const u8 *key, size_t key_len,
+                const char *label, const u8 *seed, size_t seed_len,
+                u8 *buf, size_t buf_len);
 
 #endif /* EAP_PEAP_COMMON_H */
diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
new file mode 100644 (file)
index 0000000..0dbdff2
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+#include "common.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)
+{
+       u8 allzero[SHA256_DIGEST_LENGTH];
+
+       os_memset(allzero, 0, SHA256_DIGEST_LENGTH);
+       HMAC_Init(ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256());
+}
+
+
+void H_Update(HMAC_CTX *ctx, const u8 *data, int len)
+{
+       HMAC_Update(ctx, data, len);
+}
+
+
+void H_Final(HMAC_CTX *ctx, u8 *digest)
+{
+       unsigned int mdlen = SHA256_DIGEST_LENGTH;
+
+       HMAC_Final(ctx, digest, &mdlen);
+       HMAC_CTX_cleanup(ctx);
+}
+
+
+/* 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)
+{
+       HMAC_CTX hctx;
+       unsigned char digest[SHA256_DIGEST_LENGTH];
+       u16 i, ctr, L;
+       int resultbytelen, len = 0;
+       unsigned int mdlen = SHA256_DIGEST_LENGTH;
+       unsigned char mask = 0xff;
+
+       resultbytelen = (resultbitlen + 7)/8;
+       ctr = 0;
+       L = htons(resultbitlen);
+       while (len < resultbytelen) {
+               ctr++; i = htons(ctr);
+               HMAC_Init(&hctx, key, keylen, EVP_sha256());
+               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)
+                       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) {
+               mask <<= (8 - (resultbitlen % 8));
+               result[resultbytelen - 1] &= mask;
+       }
+}
+
+
+/*
+ * compute a "random" secret point on an elliptic curve based
+ * on the password and identities.
+ */
+int compute_password_element(EAP_PWD_group *grp, u16 num,
+                            u8 *password, int password_len,
+                            u8 *id_server, int id_server_len,
+                            u8 *id_peer, int id_peer_len, u8 *token)
+{
+       BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
+       HMAC_CTX ctx;
+       unsigned char pwe_digest[SHA256_DIGEST_LENGTH], *prfbuf = NULL, ctr;
+       int nid, is_odd, primebitlen, primebytelen, ret = 0;
+
+       switch (num) { /* from IANA registry for IKE D-H groups */
+        case 19:
+               nid = NID_X9_62_prime256v1;
+               break;
+        case 20:
+               nid = NID_secp384r1;
+               break;
+        case 21:
+               nid = NID_secp521r1;
+               break;
+        case 25:
+               nid = NID_X9_62_prime192v1;
+               break;
+        case 26:
+               nid = NID_secp224r1;
+               break;
+        default:
+               wpa_printf(MSG_INFO, "EAP-pwd: unsupported group %d", num);
+               return -1;
+       }
+
+       grp->pwe = NULL;
+       grp->order = NULL;
+       grp->prime = NULL;
+
+       if ((grp->group = EC_GROUP_new_by_curve_name(nid)) == NULL) {
+               wpa_printf(MSG_INFO, "EAP-pwd: unable to create EC_GROUP");
+               goto fail;
+       }
+
+       if (((rnd = BN_new()) == NULL) ||
+           ((cofactor = BN_new()) == NULL) ||
+           ((grp->pwe = EC_POINT_new(grp->group)) == NULL) ||
+           ((grp->order = BN_new()) == NULL) ||
+           ((grp->prime = BN_new()) == NULL) ||
+           ((x_candidate = BN_new()) == NULL)) {
+               wpa_printf(MSG_INFO, "EAP-pwd: unable to create bignums");
+               goto fail;
+       }
+
+       if (!EC_GROUP_get_curve_GFp(grp->group, grp->prime, NULL, NULL, NULL))
+       {
+               wpa_printf(MSG_INFO, "EAP-pwd: unable to get prime for GFp "
+                          "curve");
+               goto fail;
+       }
+       if (!EC_GROUP_get_order(grp->group, grp->order, NULL)) {
+               wpa_printf(MSG_INFO, "EAP-pwd: unable to get order for curve");
+               goto fail;
+       }
+       if (!EC_GROUP_get_cofactor(grp->group, cofactor, NULL)) {
+               wpa_printf(MSG_INFO, "EAP-pwd: unable to get cofactor for "
+                          "curve");
+               goto fail;
+       }
+       primebitlen = BN_num_bits(grp->prime);
+       primebytelen = BN_num_bytes(grp->prime);
+       if ((prfbuf = os_malloc(primebytelen)) == NULL) {
+               wpa_printf(MSG_INFO, "EAP-pwd: unable to malloc space for prf "
+                          "buffer");
+               goto fail;
+       }
+       os_memset(prfbuf, 0, primebytelen);
+       ctr = 0;
+       while (1) {
+               if (ctr > 10) {
+                       wpa_printf(MSG_INFO, "EAP-pwd: unable to find random "
+                                  "point on curve for group %d, something's "
+                                  "fishy", num);
+                       goto fail;
+               }
+               ctr++;
+
+               /*
+                * compute counter-mode password value and stretch to prime
+                *    pwd-seed = H(token | peer-id | server-id | password |
+                *                 counter)
+                */
+               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);
+
+               BN_bin2bn(prfbuf, primebytelen, x_candidate);
+
+               /*
+                * eap_pwd_kdf() returns a string of bits 0..primebitlen but
+                * BN_bin2bn will treat that string of bits as a big endian
+                * number. If the primebitlen is not an even multiple of 8
+                * then excessive bits-- those _after_ primebitlen-- so now
+                * we have to shift right the amount we masked off.
+                */
+               if (primebitlen % 8)
+                       BN_rshift(x_candidate, x_candidate,
+                                 (8 - (primebitlen % 8)));
+
+               if (BN_ucmp(x_candidate, grp->prime) >= 0)
+                       continue;
+
+               wpa_hexdump(MSG_DEBUG, "EAP-pwd: x_candidate",
+                           prfbuf, primebytelen);
+
+               /*
+                * need to unambiguously identify the solution, if there is
+                * one...
+                */
+               if (BN_is_odd(rnd))
+                       is_odd = 1;
+               else
+                       is_odd = 0;
+
+               /*
+                * solve the quadratic equation, if it's not solvable then we
+                * don't have a point
+                */
+               if (!EC_POINT_set_compressed_coordinates_GFp(grp->group,
+                                                            grp->pwe,
+                                                            x_candidate,
+                                                            is_odd, NULL))
+                       continue;
+               /*
+                * If there's a solution to the equation then the point must be
+                * on the curve so why check again explicitly? OpenSSL code
+                * says this is required by X9.62. We're not X9.62 but it can't
+                * hurt just to be sure.
+                */
+               if (!EC_POINT_is_on_curve(grp->group, grp->pwe, NULL)) {
+                       wpa_printf(MSG_INFO, "EAP-pwd: point is not on curve");
+                       continue;
+               }
+
+               if (BN_cmp(cofactor, BN_value_one())) {
+                       /* make sure the point is not in a small sub-group */
+                       if (!EC_POINT_mul(grp->group, grp->pwe, NULL, grp->pwe,
+                                         cofactor, NULL)) {
+                               wpa_printf(MSG_INFO, "EAP-pwd: cannot "
+                                          "multiply generator by order");
+                               continue;
+                       }
+                       if (EC_POINT_is_at_infinity(grp->group, grp->pwe)) {
+                               wpa_printf(MSG_INFO, "EAP-pwd: point is at "
+                                          "infinity");
+                               continue;
+                       }
+               }
+               /* if we got here then we have a new generator. */
+               break;
+       }
+       wpa_printf(MSG_DEBUG, "EAP-pwd: found a PWE in %d tries", ctr);
+       grp->group_num = num;
+       if (0) {
+ fail:
+               EC_GROUP_free(grp->group);
+               EC_POINT_free(grp->pwe);
+               BN_free(grp->order);
+               BN_free(grp->prime);
+               os_free(grp);
+               grp = NULL;
+               ret = 1;
+       }
+       /* cleanliness and order.... */
+       BN_free(cofactor);
+       BN_free(x_candidate);
+       BN_free(rnd);
+       os_free(prfbuf);
+
+       return ret;
+}
+
+
+int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, BIGNUM *k,
+                BIGNUM *peer_scalar, BIGNUM *server_scalar,
+                u8 *commit_peer, u8 *commit_server,
+                u32 *ciphersuite, u8 *msk, u8 *emsk)
+{
+       HMAC_CTX ctx;
+       u8 mk[SHA256_DIGEST_LENGTH], *cruft;
+       u8 session_id[SHA256_DIGEST_LENGTH + 1];
+       u8 msk_emsk[EAP_MSK_LEN + EAP_EMSK_LEN];
+       int offset;
+
+       if ((cruft = os_malloc(BN_num_bytes(grp->prime))) == NULL)
+               return -1;
+
+       /*
+        * first compute the session-id = TypeCode | H(ciphersuite | scal_p |
+        *      scal_s)
+        */
+       session_id[0] = EAP_TYPE_PWD;
+       H_Init(&ctx);
+       H_Update(&ctx, (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));
+       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]);
+
+       /* then compute MK = H(k | commit-peer | commit-server) */
+       H_Init(&ctx);
+       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);
+
+       /* 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);
+
+       os_memcpy(msk, msk_emsk, EAP_MSK_LEN);
+       os_memcpy(emsk, msk_emsk + EAP_MSK_LEN, EAP_EMSK_LEN);
+
+       os_free(cruft);
+
+       return 1;
+}
diff --git a/src/eap_common/eap_pwd_common.h b/src/eap_common/eap_pwd_common.h
new file mode 100644 (file)
index 0000000..4b841b7
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#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
+ * TODO: support one based on a prime field
+ */
+typedef struct group_definition_ {
+       u16 group_num;
+       EC_GROUP *group;
+       EC_POINT *pwe;
+       BIGNUM *order;
+       BIGNUM *prime;
+} EAP_PWD_group;
+
+/*
+ * EAP-pwd header, included on all payloads
+ * L(1 bit) | M(1 bit) | exch(6 bits) | total_length(if L is set)
+ */
+
+#define EAP_PWD_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))
+
+/* EAP-pwd-ID payload */
+struct eap_pwd_id {
+       be16 group_num;
+       u8 random_function;
+#define EAP_PWD_DEFAULT_RAND_FUNC       1
+       u8 prf;
+#define EAP_PWD_DEFAULT_PRF             1
+       u8 token[4];
+       u8 prep;
+#define EAP_PWD_PREP_NONE               0
+#define EAP_PWD_PREP_MS                 1
+       u8 identity[0];     /* length inferred from payload */
+} STRUCT_PACKED;
+
+/* common routines */
+int compute_password_element(EAP_PWD_group *, u16, u8 *, int, u8 *, int, u8 *,
+                            int, u8 *);
+int compute_keys(EAP_PWD_group *, BN_CTX *, BIGNUM *, BIGNUM *, BIGNUM *,
+                u8 *, u8 *, u32 *, u8 *, u8 *);
+void H_Init(HMAC_CTX *);
+void H_Update(HMAC_CTX *, const u8 *, int);
+void H_Final(HMAC_CTX *, u8 *);
+
+#endif  /* EAP_PWD_COMMON_H */
index 56b4ded..0b37b0b 100644 (file)
@@ -20,6 +20,7 @@
 #include "crypto/crypto.h"
 #include "crypto/sha1.h"
 #include "crypto/sha256.h"
+#include "crypto/random.h"
 #include "eap_common/eap_defs.h"
 #include "eap_common/eap_sim_common.h"
 
@@ -1121,8 +1122,8 @@ int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
        if (pos == NULL)
                return -1;
        msg->iv = (pos - wpabuf_head_u8(msg->buf)) + 4;
-       if (os_get_random(wpabuf_mhead_u8(msg->buf) + msg->iv,
-                         EAP_SIM_IV_LEN)) {
+       if (random_get_bytes(wpabuf_mhead_u8(msg->buf) + msg->iv,
+                            EAP_SIM_IV_LEN)) {
                msg->iv = 0;
                return -1;
        }
index 67754d8..003c288 100644 (file)
@@ -18,6 +18,7 @@
 #include "crypto/crypto.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
+#include "crypto/random.h"
 #include "ikev2_common.h"
 
 
@@ -639,7 +640,7 @@ int ikev2_build_encrypted(int encr_id, int integ_id, struct ikev2_keys *keys,
        phdr->flags = 0;
 
        iv = wpabuf_put(msg, iv_len);
-       if (os_get_random(iv, iv_len)) {
+       if (random_get_bytes(iv, iv_len)) {
                wpa_printf(MSG_INFO, "IKEV2: Could not generate IV");
                return -1;
        }
index c96a070..31a2b0d 100644 (file)
@@ -139,7 +139,7 @@ enum {
        IKEV2_TRANSFORM_ESN = 5
 };
 
-/* IKEv2 Tranform Type 1 (Encryption Algorithm) */
+/* IKEv2 Transform Type 1 (Encryption Algorithm) */
 enum {
        ENCR_DES_IV64 = 1,
        ENCR_DES = 2,
index b9f186b..91fa4a9 100644 (file)
@@ -37,6 +37,7 @@
 #define STATE_MACHINE_DEBUG_PREFIX "EAP"
 
 #define EAP_MAX_AUTH_ROUNDS 50
+#define EAP_CLIENT_TIMEOUT_DEFAULT 60
 
 
 static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
@@ -146,6 +147,7 @@ SM_STATE(EAP, INITIALIZE)
        sm->methodState = METHOD_NONE;
        sm->allowNotifications = TRUE;
        sm->decision = DECISION_FAIL;
+       sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
        eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
        eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
        eapol_set_bool(sm, EAPOL_eapFail, FALSE);
@@ -268,6 +270,8 @@ SM_STATE(EAP, GET_METHOD)
                goto nak;
        }
 
+       sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
+
        wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP method: "
                   "vendor %u method %u (%s)",
                   sm->reqVendor, method, sm->m->name);
@@ -1165,7 +1169,6 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
 {
        struct eap_sm *sm = ctx;
        char *hash_hex = NULL;
-       char *cert_hex = NULL;
 
        switch (ev) {
        case TLS_CERT_CHAIN_FAILURE:
@@ -1177,6 +1180,9 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
                        data->cert_fail.reason_txt);
                break;
        case TLS_PEER_CERTIFICATE:
+               if (!sm->eapol_cb->notify_cert)
+                       break;
+
                if (data->peer_cert.hash) {
                        size_t len = data->peer_cert.hash_len * 2 + 1;
                        hash_hex = os_malloc(len);
@@ -1186,31 +1192,15 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
                                                 data->peer_cert.hash_len);
                        }
                }
-               wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
-                       "depth=%d subject='%s'%s%s",
-                       data->peer_cert.depth, data->peer_cert.subject,
-                       hash_hex ? " hash=" : "", hash_hex ? hash_hex : "");
-
-               if (data->peer_cert.cert) {
-                       size_t len = wpabuf_len(data->peer_cert.cert) * 2 + 1;
-                       cert_hex = os_malloc(len);
-                       if (cert_hex == NULL)
-                               break;
-                       wpa_snprintf_hex(cert_hex, len,
-                                        wpabuf_head(data->peer_cert.cert),
-                                        wpabuf_len(data->peer_cert.cert));
-                       wpa_msg_ctrl(sm->msg_ctx, MSG_INFO,
-                                    WPA_EVENT_EAP_PEER_CERT
-                                    "depth=%d subject='%s' cert=%s",
-                                    data->peer_cert.depth,
-                                    data->peer_cert.subject,
-                                    cert_hex);
-               }
+
+               sm->eapol_cb->notify_cert(sm->eapol_ctx,
+                                         data->peer_cert.depth,
+                                         data->peer_cert.subject,
+                                         hash_hex, data->peer_cert.cert);
                break;
        }
 
        os_free(hash_hex);
-       os_free(cert_hex);
 }
 
 
@@ -1241,7 +1231,7 @@ struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
        sm->eapol_ctx = eapol_ctx;
        sm->eapol_cb = eapol_cb;
        sm->msg_ctx = msg_ctx;
-       sm->ClientTimeout = 60;
+       sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
        sm->wps = conf->wps;
 
        os_memset(&tlsconf, 0, sizeof(tlsconf));
@@ -1253,6 +1243,7 @@ struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
 #endif /* CONFIG_FIPS */
        tlsconf.event_cb = eap_peer_sm_tls_event;
        tlsconf.cb_ctx = sm;
+       tlsconf.cert_in_cb = conf->cert_in_cb;
        sm->ssl_ctx = tls_init(&tlsconf);
        if (sm->ssl_ctx == NULL) {
                wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
@@ -1477,16 +1468,11 @@ int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
 
 
 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
-typedef enum {
-       TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP, TYPE_PIN, TYPE_NEW_PASSWORD,
-       TYPE_PASSPHRASE
-} eap_ctrl_req_type;
-
-static void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type,
+static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
                           const char *msg, size_t msglen)
 {
        struct eap_peer_config *config;
-       char *field, *txt, *tmp;
+       char *txt = NULL, *tmp;
 
        if (sm == NULL)
                return;
@@ -1494,29 +1480,20 @@ static void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type,
        if (config == NULL)
                return;
 
-       switch (type) {
-       case TYPE_IDENTITY:
-               field = "IDENTITY";
-               txt = "Identity";
+       switch (field) {
+       case WPA_CTRL_REQ_EAP_IDENTITY:
                config->pending_req_identity++;
                break;
-       case TYPE_PASSWORD:
-               field = "PASSWORD";
-               txt = "Password";
+       case WPA_CTRL_REQ_EAP_PASSWORD:
                config->pending_req_password++;
                break;
-       case TYPE_NEW_PASSWORD:
-               field = "NEW_PASSWORD";
-               txt = "New Password";
+       case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
                config->pending_req_new_password++;
                break;
-       case TYPE_PIN:
-               field = "PIN";
-               txt = "PIN";
+       case WPA_CTRL_REQ_EAP_PIN:
                config->pending_req_pin++;
                break;
-       case TYPE_OTP:
-               field = "OTP";
+       case WPA_CTRL_REQ_EAP_OTP:
                if (msg) {
                        tmp = os_malloc(msglen + 3);
                        if (tmp == NULL)
@@ -1535,9 +1512,7 @@ static void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type,
                        txt = config->pending_req_otp;
                }
                break;
-       case TYPE_PASSPHRASE:
-               field = "PASSPHRASE";
-               txt = "Private key passphrase";
+       case WPA_CTRL_REQ_EAP_PASSPHRASE:
                config->pending_req_passphrase++;
                break;
        default:
@@ -1551,6 +1526,13 @@ static void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type,
 #define eap_sm_request(sm, type, msg, msglen) do { } while (0)
 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
 
+const char * eap_sm_get_method_name(struct eap_sm *sm)
+{
+       if (sm->m == NULL)
+               return "UNKNOWN";
+       return sm->m->name;
+}
+
 
 /**
  * eap_sm_request_identity - Request identity from user (ctrl_iface)
@@ -1563,7 +1545,7 @@ static void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type,
  */
 void eap_sm_request_identity(struct eap_sm *sm)
 {
-       eap_sm_request(sm, TYPE_IDENTITY, NULL, 0);
+       eap_sm_request(sm, WPA_CTRL_REQ_EAP_IDENTITY, NULL, 0);
 }
 
 
@@ -1578,7 +1560,7 @@ void eap_sm_request_identity(struct eap_sm *sm)
  */
 void eap_sm_request_password(struct eap_sm *sm)
 {
-       eap_sm_request(sm, TYPE_PASSWORD, NULL, 0);
+       eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSWORD, NULL, 0);
 }
 
 
@@ -1593,7 +1575,7 @@ void eap_sm_request_password(struct eap_sm *sm)
  */
 void eap_sm_request_new_password(struct eap_sm *sm)
 {
-       eap_sm_request(sm, TYPE_NEW_PASSWORD, NULL, 0);
+       eap_sm_request(sm, WPA_CTRL_REQ_EAP_NEW_PASSWORD, NULL, 0);
 }
 
 
@@ -1608,7 +1590,7 @@ void eap_sm_request_new_password(struct eap_sm *sm)
  */
 void eap_sm_request_pin(struct eap_sm *sm)
 {
-       eap_sm_request(sm, TYPE_PIN, NULL, 0);
+       eap_sm_request(sm, WPA_CTRL_REQ_EAP_PIN, NULL, 0);
 }
 
 
@@ -1624,7 +1606,7 @@ void eap_sm_request_pin(struct eap_sm *sm)
  */
 void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len)
 {
-       eap_sm_request(sm, TYPE_OTP, msg, msg_len);
+       eap_sm_request(sm, WPA_CTRL_REQ_EAP_OTP, msg, msg_len);
 }
 
 
@@ -1639,7 +1621,7 @@ void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len)
  */
 void eap_sm_request_passphrase(struct eap_sm *sm)
 {
-       eap_sm_request(sm, TYPE_PASSPHRASE, NULL, 0);
+       eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSPHRASE, NULL, 0);
 }
 
 
@@ -1923,6 +1905,15 @@ const char * eap_get_config_phase2(struct eap_sm *sm)
 }
 
 
+int eap_get_config_fragment_size(struct eap_sm *sm)
+{
+       struct eap_peer_config *config = eap_get_config(sm);
+       if (config == NULL)
+               return -1;
+       return config->fragment_size;
+}
+
+
 /**
  * eap_key_available - Get key availability (eapKeyAvailable variable)
  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
index 40d0b69..f35197f 100644 (file)
@@ -216,11 +216,22 @@ struct eapol_callbacks {
        /**
         * eap_param_needed - Notify that EAP parameter is needed
         * @ctx: eapol_ctx from eap_peer_sm_init() call
-        * @field: Field name (e.g., "IDENTITY")
+        * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY)
         * @txt: User readable text describing the required parameter
         */
-       void (*eap_param_needed)(void *ctx, const char *field,
+       void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field,
                                 const char *txt);
+
+       /**
+        * notify_cert - Notification of a peer certificate
+        * @ctx: eapol_ctx from eap_peer_sm_init() call
+        * @depth: Depth in certificate chain (0 = server)
+        * @subject: Subject of the peer certificate
+        * @cert_hash: SHA-256 hash of the certificate
+        * @cert: Peer certificate
+        */
+       void (*notify_cert)(void *ctx, int depth, const char *subject,
+                           const char *cert_hash, const struct wpabuf *cert);
 };
 
 /**
@@ -251,6 +262,11 @@ struct eap_config {
         * This is only used by EAP-WSC and can be left %NULL if not available.
         */
        struct wps_context *wps;
+
+       /**
+        * cert_in_cb - Include server certificates in callback
+        */
+       int cert_in_cb;
 };
 
 struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
@@ -261,6 +277,7 @@ int eap_peer_sm_step(struct eap_sm *sm);
 void eap_sm_abort(struct eap_sm *sm);
 int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen,
                      int verbose);
+const char * eap_sm_get_method_name(struct eap_sm *sm);
 struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted);
 void eap_sm_request_identity(struct eap_sm *sm);
 void eap_sm_request_password(struct eap_sm *sm);
index 182f01a..766764b 100644 (file)
@@ -235,21 +235,20 @@ static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
 
 static void eap_aka_clear_identities(struct eap_aka_data *data, int id)
 {
-       wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old%s%s%s",
-                  id & CLEAR_PSEUDONYM ? " pseudonym" : "",
-                  id & CLEAR_REAUTH_ID ? " reauth_id" : "",
-                  id & CLEAR_EAP_ID ? " eap_id" : "");
        if (id & CLEAR_PSEUDONYM) {
+               wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old pseudonym");
                os_free(data->pseudonym);
                data->pseudonym = NULL;
                data->pseudonym_len = 0;
        }
        if (id & CLEAR_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) {
+               wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old eap_id");
                os_free(data->last_eap_identity);
                data->last_eap_identity = NULL;
                data->last_eap_identity_len = 0;
@@ -880,11 +879,11 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
                                            EAP_AKA_UNABLE_TO_PROCESS_PACKET);
        }
 
-       /* Old reauthentication and pseudonym identities must not be used
-        * anymore. In other words, if no new identities are received, full
-        * authentication will be used on next reauthentication. */
-       eap_aka_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID |
-                                CLEAR_EAP_ID);
+       /* Old reauthentication identity must not be used anymore. In
+        * other words, if no new identities are received, full
+        * authentication will be used on next reauthentication (using
+        * pseudonym identity or permanent identity). */
+       eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
 
        if (attr->encr_data) {
                u8 *decrypted;
index 5d3e69d..3cfb41a 100644 (file)
@@ -444,8 +444,9 @@ static int eap_fast_phase2_request(struct eap_sm *sm,
                return 0;
        }
 
-       if (data->phase2_priv == NULL &&
-           eap_fast_init_phase2_method(sm, data) < 0) {
+       if ((data->phase2_priv == NULL &&
+            eap_fast_init_phase2_method(sm, data) < 0) ||
+           data->phase2_method == NULL) {
                wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize "
                           "Phase 2 EAP method %d", *pos);
                ret->methodState = METHOD_DONE;
@@ -542,7 +543,7 @@ static struct wpabuf * eap_fast_tlv_pac_ack(void)
 
 static struct wpabuf * eap_fast_process_eap_payload_tlv(
        struct eap_sm *sm, struct eap_fast_data *data,
-       struct eap_method_ret *ret, const struct eap_hdr *req,
+       struct eap_method_ret *ret,
        u8 *eap_payload_tlv, size_t eap_payload_tlv_len)
 {
        struct eap_hdr *hdr;
@@ -1037,11 +1038,15 @@ static struct wpabuf * eap_fast_process_pac(struct eap_sm *sm,
        } else {
                /*
                 * This is PAC refreshing, i.e., normal authentication that is
-                * expected to be completed with an EAP-Success.
+                * expected to be completed with an EAP-Success. However,
+                * RFC 5422, Section 3.5 allows EAP-Failure to be sent even
+                * after protected success exchange in case of EAP-Fast
+                * provisioning, so we better use DECISION_COND_SUCC here
+                * instead of DECISION_UNCOND_SUCC.
                 */
                wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV "
                           "- PAC refreshing completed successfully");
-               ret->decision = DECISION_UNCOND_SUCC;
+               ret->decision = DECISION_COND_SUCC;
        }
        ret->methodState = METHOD_DONE;
        return eap_fast_tlv_pac_ack();
@@ -1184,7 +1189,7 @@ static int eap_fast_process_decrypted(struct eap_sm *sm,
 
        if (tlv.eap_payload_tlv) {
                tmp = eap_fast_process_eap_payload_tlv(
-                       sm, data, ret, req, tlv.eap_payload_tlv,
+                       sm, data, ret, tlv.eap_payload_tlv,
                        tlv.eap_payload_tlv_len);
                resp = wpabuf_concat(resp, tmp);
        }
index 541cce5..4037288 100644 (file)
@@ -497,6 +497,7 @@ static void eap_fast_write(char **buf, char **pos, size_t *buf_len,
                        *buf = NULL;
                        return;
                }
+               *pos = nbuf + (*pos - *buf);
                *buf = nbuf;
                *buf_len += need;
        }
index f6a1955..5037c60 100644 (file)
@@ -15,6 +15,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/random.h"
 #include "eap_peer/eap_i.h"
 #include "eap_common/eap_gpsk_common.h"
 
@@ -326,7 +327,7 @@ static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
        wpabuf_put_be16(resp, data->id_server_len);
        wpabuf_put_data(resp, data->id_server, data->id_server_len);
 
-       if (os_get_random(data->rand_peer, EAP_GPSK_RAND_LEN)) {
+       if (random_get_bytes(data->rand_peer, EAP_GPSK_RAND_LEN)) {
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data "
                           "for RAND_Peer");
                eap_gpsk_state(data, FAILURE);
index e7c826e..afca611 100644 (file)
@@ -345,6 +345,7 @@ const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len);
 void eap_clear_config_otp(struct eap_sm *sm);
 const char * eap_get_config_phase1(struct eap_sm *sm);
 const char * eap_get_config_phase2(struct eap_sm *sm);
+int eap_get_config_fragment_size(struct eap_sm *sm);
 struct eap_peer_config * eap_get_config(struct eap_sm *sm);
 void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob);
 const struct wpa_config_blob *
index a7c94a4..6a8efcd 100644 (file)
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "crypto/ms_funcs.h"
 #include "crypto/crypto.h"
+#include "crypto/random.h"
 #include "eap_i.h"
 
 #define LEAP_VERSION 1
@@ -167,7 +168,7 @@ static struct wpabuf * eap_leap_process_success(struct eap_sm *sm, void *priv,
        wpabuf_put_u8(resp, 0); /* unused */
        wpabuf_put_u8(resp, LEAP_CHALLENGE_LEN);
        pos = wpabuf_put(resp, LEAP_CHALLENGE_LEN);
-       if (os_get_random(pos, LEAP_CHALLENGE_LEN)) {
+       if (random_get_bytes(pos, LEAP_CHALLENGE_LEN)) {
                wpa_printf(MSG_WARNING, "EAP-LEAP: Failed to read random data "
                           "for challenge");
                wpabuf_free(resp);
index 3b0af05..937fd45 100644 (file)
@@ -77,6 +77,8 @@ EapType eap_peer_get_type(const char *name, int *vendor)
 const char * eap_get_name(int vendor, EapType type)
 {
        struct eap_method *m;
+       if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
+               return "expanded";
        for (m = eap_methods; m; m = m->next) {
                if (m->vendor == vendor && m->method == type)
                        return m->name;
index 384c61b..4330b57 100644 (file)
@@ -109,5 +109,6 @@ int eap_peer_wsc_register(void);
 int eap_peer_ikev2_register(void);
 int eap_peer_vendor_test_register(void);
 int eap_peer_tnc_register(void);
+int eap_peer_pwd_register(void);
 
 #endif /* EAP_METHODS_H */
index cd410d9..321e9f7 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "common.h"
 #include "crypto/ms_funcs.h"
+#include "crypto/random.h"
 #include "common/wpa_ctrl.h"
 #include "mschapv2.h"
 #include "eap_i.h"
@@ -199,7 +200,7 @@ static struct wpabuf * eap_mschapv2_challenge_reply(
                           "in Phase 1");
                peer_challenge = data->peer_challenge;
                os_memset(r->peer_challenge, 0, MSCHAPV2_CHAL_LEN);
-       } else if (os_get_random(peer_challenge, MSCHAPV2_CHAL_LEN)) {
+       } else if (random_get_bytes(peer_challenge, MSCHAPV2_CHAL_LEN)) {
                wpabuf_free(resp);
                return NULL;
        }
@@ -564,7 +565,7 @@ static struct wpabuf * eap_mschapv2_change_password(
        }
 
        /* Peer-Challenge */
-       if (os_get_random(cp->peer_challenge, MSCHAPV2_CHAL_LEN))
+       if (random_get_bytes(cp->peer_challenge, MSCHAPV2_CHAL_LEN))
                goto fail;
 
        /* Reserved, must be zero */
index 2e04831..d42a7f8 100644 (file)
@@ -15,6 +15,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/random.h"
 #include "eap_common/eap_pax_common.h"
 #include "eap_i.h"
 
@@ -174,7 +175,7 @@ static struct wpabuf * eap_pax_process_std_1(struct eap_pax_data *data,
                            pos, left);
        }
 
-       if (os_get_random(data->rand.r.y, EAP_PAX_RAND_LEN)) {
+       if (random_get_bytes(data->rand.r.y, EAP_PAX_RAND_LEN)) {
                wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data");
                ret->ignore = TRUE;
                return NULL;
index 2b72084..7cb8213 100644 (file)
@@ -196,7 +196,7 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv)
  * @nak_type: TLV type (EAP_TLV_*)
  * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure
  *
- * This funtion builds an EAP-TLV NAK message. The caller is responsible for
+ * This function builds an EAP-TLV NAK message. The caller is responsible for
  * freeing the returned buffer.
  */
 static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type)
@@ -285,8 +285,10 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
         * in the end of the label just before ISK; is that just a typo?)
         */
        wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
-       peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",
-                    isk, sizeof(isk), imck, sizeof(imck));
+       if (peap_prfplus(data->peap_version, tk, 40,
+                        "Inner Methods Compound Keys",
+                        isk, sizeof(isk), imck, sizeof(imck)) < 0)
+               return -1;
        wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
                        imck, sizeof(imck));
 
@@ -346,8 +348,8 @@ static int eap_tlv_add_cryptobinding(struct eap_sm *sm,
  * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE)
  * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure
  *
- * This funtion builds an EAP-TLV Result message. The caller is responsible for
- * freeing the returned buffer.
+ * This function builds an EAP-TLV Result message. The caller is responsible
+ * for freeing the returned buffer.
  */
 static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm,
                                            struct eap_peap_data *data,
@@ -1247,9 +1249,12 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
                 * termination for this label while the one used for deriving
                 * IPMK|CMK did not use null termination.
                 */
-               peap_prfplus(data->peap_version, data->ipmk, 40,
-                            "Session Key Generating Function",
-                            (u8 *) "\00", 1, csk, sizeof(csk));
+               if (peap_prfplus(data->peap_version, data->ipmk, 40,
+                                "Session Key Generating Function",
+                                (u8 *) "\00", 1, csk, sizeof(csk)) < 0) {
+                       os_free(key);
+                       return NULL;
+               }
                wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
                os_memcpy(key, csk, EAP_TLS_KEY_LEN);
                wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
index ccf871e..592ef13 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "common.h"
 #include "crypto/aes_wrap.h"
+#include "crypto/random.h"
 #include "eap_common/eap_psk_common.h"
 #include "eap_i.h"
 
@@ -130,7 +131,7 @@ static struct wpabuf * eap_psk_process_1(struct eap_psk_data *data,
        wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S",
                          data->id_s, data->id_s_len);
 
-       if (os_get_random(data->rand_p, EAP_PSK_RAND_LEN)) {
+       if (random_get_bytes(data->rand_p, EAP_PSK_RAND_LEN)) {
                wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data");
                ret->ignore = TRUE;
                return NULL;
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
new file mode 100644 (file)
index 0000000..1957c82
--- /dev/null
@@ -0,0 +1,762 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_peer/eap_i.h"
+#include "eap_common/eap_pwd_common.h"
+
+
+struct eap_pwd_data {
+       enum {
+               PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req, SUCCESS, FAILURE
+       } state;
+       u8 *id_peer;
+       size_t id_peer_len;
+       u8 *id_server;
+       size_t id_server_len;
+       u8 *password;
+       size_t password_len;
+       u16 group_num;
+       EAP_PWD_group *grp;
+
+       BIGNUM *k;
+       BIGNUM *private_value;
+       BIGNUM *server_scalar;
+       BIGNUM *my_scalar;
+       EC_POINT *my_element;
+       EC_POINT *server_element;
+
+       u8 msk[EAP_MSK_LEN];
+       u8 emsk[EAP_EMSK_LEN];
+
+       BN_CTX *bnctx;
+};
+
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static const char * eap_pwd_state_txt(int state)
+{
+       switch (state) {
+        case PWD_ID_Req:
+               return "PWD-ID-Req";
+        case PWD_Commit_Req:
+               return "PWD-Commit-Req";
+        case PWD_Confirm_Req:
+               return "PWD-Confirm-Req";
+        case SUCCESS:
+               return "SUCCESS";
+        case FAILURE:
+               return "FAILURE";
+        default:
+               return "PWD-UNK";
+       }
+}
+#endif  /* CONFIG_NO_STDOUT_DEBUG */
+
+
+static void eap_pwd_state(struct eap_pwd_data *data, int state)
+{
+       wpa_printf(MSG_INFO, "EAP-PWD: %s -> %s",
+                  eap_pwd_state_txt(data->state), eap_pwd_state_txt(state));
+       data->state = state;
+}
+
+
+static void * eap_pwd_init(struct eap_sm *sm)
+{
+       struct eap_pwd_data *data;
+       const u8 *identity, *password;
+       size_t identity_len, password_len;
+
+       password = eap_get_config_password(sm, &password_len);
+       if (password == NULL) {
+               wpa_printf(MSG_INFO, "EAP-PWD: No password configured!");
+               return NULL;
+       }
+
+       identity = eap_get_config_identity(sm, &identity_len);
+       if (identity == NULL) {
+               wpa_printf(MSG_INFO, "EAP-PWD: No identity configured!");
+               return NULL;
+       }
+
+       if ((data = os_zalloc(sizeof(*data))) == NULL) {
+               wpa_printf(MSG_INFO, "EAP-PWD: memory allocation data fail");
+               return NULL;
+       }
+
+       if ((data->bnctx = BN_CTX_new()) == NULL) {
+               wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
+               os_free(data);
+               return NULL;
+       }
+
+       if ((data->id_peer = os_malloc(identity_len)) == NULL) {
+               wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
+               BN_CTX_free(data->bnctx);
+               os_free(data);
+               return NULL;
+       }
+
+       os_memcpy(data->id_peer, identity, identity_len);
+       data->id_peer_len = identity_len;
+
+       if ((data->password = os_malloc(password_len)) == NULL) {
+               wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail");
+               BN_CTX_free(data->bnctx);
+               os_free(data->id_peer);
+               os_free(data);
+               return NULL;
+       }
+       os_memcpy(data->password, password, password_len);
+       data->password_len = password_len;
+
+       data->state = PWD_ID_Req;
+
+       return data;
+}
+
+
+static void eap_pwd_deinit(struct eap_sm *sm, void *priv)
+{
+       struct eap_pwd_data *data = priv;
+
+       BN_free(data->private_value);
+       BN_free(data->server_scalar);
+       BN_free(data->my_scalar);
+       BN_free(data->k);
+       BN_CTX_free(data->bnctx);
+       EC_POINT_free(data->my_element);
+       EC_POINT_free(data->server_element);
+       os_free(data->id_peer);
+       os_free(data->id_server);
+       os_free(data->password);
+       if (data->grp) {
+               EC_GROUP_free(data->grp->group);
+               EC_POINT_free(data->grp->pwe);
+               BN_free(data->grp->order);
+               BN_free(data->grp->prime);
+               os_free(data->grp);
+       }
+       os_free(data);
+}
+
+
+static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_pwd_data *data = priv;
+       u8 *key;
+
+       if (data->state != SUCCESS)
+               return NULL;
+
+       key = os_malloc(EAP_MSK_LEN);
+       if (key == NULL)
+               return NULL;
+
+       os_memcpy(key, data->msk, EAP_MSK_LEN);
+       *len = EAP_MSK_LEN;
+
+       return key;
+}
+
+
+static struct wpabuf *
+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;
+       }
+
+       if (payload_len < sizeof(struct eap_pwd_id)) {
+               ret->ignore = TRUE;
+               return NULL;
+       }
+
+       id = (struct eap_pwd_id *) payload;
+       data->group_num = be_to_host16(id->group_num);
+       if ((id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
+           (id->prf != EAP_PWD_DEFAULT_PRF)) {
+               ret->ignore = TRUE;
+               return NULL;
+       }
+
+       wpa_printf(MSG_DEBUG, "EAP-PWD (peer): server said 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;
+       }
+       data->id_server_len = payload_len - sizeof(struct eap_pwd_id);
+       os_memcpy(data->id_server, id->identity, data->id_server_len);
+       wpa_hexdump_ascii(MSG_INFO, "EAP-PWD (peer): server sent id of",
+                         data->id_server, data->id_server_len);
+
+       if ((data->grp = (EAP_PWD_group *) os_malloc(sizeof(EAP_PWD_group))) ==
+           NULL) {
+               wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
+                          "group");
+               return NULL;
+       }
+
+       /* compute PWE */
+       if (compute_password_element(data->grp, data->group_num,
+                                    data->password, data->password_len,
+                                    data->id_server, data->id_server_len,
+                                    data->id_peer, data->id_peer_len,
+                                    id->token)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute PWE");
+               return NULL;
+       }
+
+       wpa_printf(MSG_INFO, "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);
+
+       eap_pwd_state(data, PWD_Commit_Req);
+
+       return resp;
+}
+
+
+static struct wpabuf *
+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;
+       u8 *ptr, *scalar = NULL, *element = NULL;
+
+       if (((data->private_value = BN_new()) == NULL) ||
+           ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) ||
+           ((cofactor = BN_new()) == NULL) ||
+           ((data->my_scalar = BN_new()) == NULL) ||
+           ((mask = BN_new()) == NULL)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (peer): scalar allocation fail");
+               goto fin;
+       }
+
+       if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) {
+               wpa_printf(MSG_INFO, "EAP-pwd (peer): unable to get cofactor "
+                          "for curve");
+               goto fin;
+       }
+
+       BN_rand_range(data->private_value, data->grp->order);
+       BN_rand_range(mask, data->grp->order);
+       BN_add(data->my_scalar, data->private_value, mask);
+       BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
+              data->bnctx);
+
+       if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
+                         data->grp->pwe, mask, data->bnctx)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (peer): element allocation "
+                          "fail");
+               eap_pwd_state(data, FAILURE);
+               goto fin;
+       }
+
+       if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx))
+       {
+               wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail");
+               goto fin;
+       }
+       BN_free(mask);
+
+       if (((x = BN_new()) == NULL) ||
+           ((y = BN_new()) == NULL)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (peer): point allocation fail");
+               goto fin;
+       }
+
+       /* process the request */
+       if (((data->server_scalar = BN_new()) == NULL) ||
+           ((data->k = BN_new()) == NULL) ||
+           ((K = EC_POINT_new(data->grp->group)) == NULL) ||
+           ((point = EC_POINT_new(data->grp->group)) == NULL) ||
+           ((data->server_element = EC_POINT_new(data->grp->group)) == NULL))
+       {
+               wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation "
+                          "fail");
+               goto fin;
+       }
+
+       /* element, x then y, followed by scalar */
+       ptr = (u8 *) payload;
+       BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x);
+       ptr += BN_num_bytes(data->grp->prime);
+       BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y);
+       ptr += BN_num_bytes(data->grp->prime);
+       BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->server_scalar);
+       if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group,
+                                                data->server_element, x, y,
+                                                data->bnctx)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (peer): setting peer element "
+                          "fail");
+               goto fin;
+       }
+
+       /* check to ensure server's element is not in a small sub-group */
+       if (BN_cmp(cofactor, BN_value_one())) {
+               if (!EC_POINT_mul(data->grp->group, point, NULL,
+                                 data->server_element, cofactor, NULL)) {
+                       wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply "
+                                  "server element by order!\n");
+                       goto fin;
+               }
+               if (EC_POINT_is_at_infinity(data->grp->group, point)) {
+                       wpa_printf(MSG_INFO, "EAP-PWD (peer): server element "
+                                  "is at infinity!\n");
+                       goto fin;
+               }
+       }
+
+       /* compute the shared key, k */
+       if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe,
+                          data->server_scalar, data->bnctx)) ||
+           (!EC_POINT_add(data->grp->group, K, K, data->server_element,
+                          data->bnctx)) ||
+           (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value,
+                          data->bnctx))) {
+               wpa_printf(MSG_INFO, "EAP-PWD (peer): computing shared key "
+                          "fail");
+               goto fin;
+       }
+
+       /* ensure that the shared key isn't in a small sub-group */
+       if (BN_cmp(cofactor, BN_value_one())) {
+               if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor,
+                                 NULL)) {
+                       wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply "
+                                  "shared key point by order");
+                       goto fin;
+               }
+       }
+
+       /*
+        * This check is strictly speaking just for the case above where
+        * co-factor > 1 but it was suggested that even though this is probably
+        * never going to happen it is a simple and safe check "just to be
+        * sure" so let's be safe.
+        */
+       if (EC_POINT_is_at_infinity(data->grp->group, K)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (peer): shared key point is at "
+                          "infinity!\n");
+               goto fin;
+       }
+
+       if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k,
+                                                NULL, data->bnctx)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to extract "
+                          "shared secret from point");
+               goto fin;
+       }
+
+       /* now do the response */
+       if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+                                                data->my_element, x, y,
+                                                data->bnctx)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail");
+               goto fin;
+       }
+
+       if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) ||
+           ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) ==
+            NULL)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (peer): data allocation fail");
+               goto fin;
+       }
+
+       /*
+        * bignums occupy as little memory as possible so one that is
+        * sufficiently smaller than the prime or order might need pre-pending
+        * with zeros.
+        */
+       os_memset(scalar, 0, BN_num_bytes(data->grp->order));
+       os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2);
+       offset = BN_num_bytes(data->grp->order) -
+               BN_num_bytes(data->my_scalar);
+       BN_bn2bin(data->my_scalar, scalar + offset);
+
+       offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+       BN_bn2bin(x, element + offset);
+       offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+       BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
+
+       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)
+               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));
+
+fin:
+       os_free(scalar);
+       os_free(element);
+       BN_free(x);
+       BN_free(y);
+       BN_free(cofactor);
+       EC_POINT_free(K);
+       EC_POINT_free(point);
+       if (resp == NULL)
+               eap_pwd_state(data, FAILURE);
+       else
+               eap_pwd_state(data, PWD_Confirm_Req);
+
+       return resp;
+}
+
+
+static struct wpabuf *
+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;
+       u32 cs;
+       u16 grp;
+       u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
+       int offset;
+
+       /*
+        * first build up the ciphersuite which is group | random_function |
+        *      prf
+        */
+       grp = htons(data->group_num);
+       ptr = (u8 *) &cs;
+       os_memcpy(ptr, &grp, sizeof(u16));
+       ptr += sizeof(u16);
+       *ptr = EAP_PWD_DEFAULT_RAND_FUNC;
+       ptr += sizeof(u8);
+       *ptr = EAP_PWD_DEFAULT_PRF;
+
+       /* each component of the cruft will be at most as big as the prime */
+       if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
+           ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): debug allocation "
+                          "fail");
+               goto fin;
+       }
+
+       /*
+        * server's commit is H(k | server_element | server_scalar |
+        *                      peer_element | peer_scalar | ciphersuite)
+        */
+       H_Init(&ctx);
+
+       /*
+        * zero the memory each time because this is mod prime math and some
+        * value may start with a few zeros and the previous one did not.
+        */
+       os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+       offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
+       BN_bn2bin(data->k, cruft + offset);
+       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+
+       /* server element: x, y */
+       if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+                                                data->server_element, x, y,
+                                                data->bnctx)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
+                          "assignment fail");
+               goto fin;
+       }
+       os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+       offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+       BN_bn2bin(x, cruft + offset);
+       H_Update(&ctx, 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));
+
+       /* 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));
+
+       /* my element: x, y */
+       if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+                                                data->my_element, x, y,
+                                                data->bnctx)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
+                          "assignment fail");
+               goto fin;
+       }
+
+       os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+       offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+       BN_bn2bin(x, cruft + offset);
+       H_Update(&ctx, 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));
+
+       /* 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));
+
+       /* the ciphersuite */
+       H_Update(&ctx, (u8 *) &cs, sizeof(u32));
+
+       /* random function fin */
+       H_Final(&ctx, conf);
+
+       ptr = (u8 *) payload;
+       if (os_memcmp(conf, ptr, SHA256_DIGEST_LENGTH)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify");
+               goto fin;
+       }
+
+       wpa_printf(MSG_DEBUG, "EAP-pwd (peer): confirm verified");
+
+       /*
+        * compute confirm:
+        *  H(k | peer_element | peer_scalar | server_element | server_scalar |
+        *    ciphersuite)
+        */
+       H_Init(&ctx);
+
+       /* 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));
+
+       /* my element */
+       if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+                                                data->my_element, x, y,
+                                                data->bnctx)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point "
+                          "assignment fail");
+               goto fin;
+       }
+       os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+       offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+       BN_bn2bin(x, cruft + offset);
+       H_Update(&ctx, 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));
+
+       /* 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));
+
+       /* server element: x, y */
+       if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+                                                data->server_element, x, y,
+                                                data->bnctx)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point "
+                          "assignment fail");
+               goto fin;
+       }
+       os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+       offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+       BN_bn2bin(x, cruft + offset);
+       H_Update(&ctx, 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));
+
+       /* 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));
+
+       /* the ciphersuite */
+       H_Update(&ctx, (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);
+
+       if (compute_keys(data->grp, data->bnctx, data->k,
+                        data->my_scalar, data->server_scalar, conf, ptr,
+                        &cs, data->msk, data->emsk) < 0) {
+               wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute MSK | "
+                          "EMSK");
+               goto fin;
+       }
+
+fin:
+       os_free(cruft);
+       BN_free(x);
+       BN_free(y);
+       ret->methodState = METHOD_DONE;
+       if (resp == NULL) {
+               ret->decision = DECISION_FAIL;
+               eap_pwd_state(data, FAILURE);
+       } else {
+               ret->decision = DECISION_UNCOND_SUCC;
+               eap_pwd_state(data, SUCCESS);
+       }
+
+       return resp;
+}
+
+
+static struct wpabuf *
+eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
+               const struct wpabuf *reqData)
+{
+       struct eap_pwd_data *data = priv;
+       struct wpabuf *resp = NULL;
+       const u8 *pos;
+       size_t len;
+       u8 exch;
+
+       pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, reqData, &len);
+       if ((pos == NULL) || (len < 1)) {
+               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);
+               break;
+        case EAP_PWD_OPCODE_COMMIT_EXCH:
+               resp = eap_pwd_perform_commit_exchange(sm, data, ret, reqData,
+                                                      pos + 1, len - 1);
+               break;
+        case EAP_PWD_OPCODE_CONFIRM_EXCH:
+               resp = eap_pwd_perform_confirm_exchange(sm, data, ret, reqData,
+                                                       pos + 1, len - 1);
+               break;
+        default:
+               wpa_printf(MSG_INFO, "EAP-pwd: Ignoring message with unknown "
+                          "opcode %d", exch);
+               break;
+       }
+
+       return resp;
+}
+
+
+static Boolean eap_pwd_key_available(struct eap_sm *sm, void *priv)
+{
+       struct eap_pwd_data *data = priv;
+       return data->state == SUCCESS;
+}
+
+
+static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_pwd_data *data = priv;
+       u8 *key;
+
+       if (data->state != SUCCESS)
+               return NULL;
+
+       if ((key = os_malloc(EAP_EMSK_LEN)) == NULL)
+               return NULL;
+
+       os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+       *len = EAP_EMSK_LEN;
+
+       return key;
+}
+
+
+int eap_peer_pwd_register(void)
+{
+       struct eap_method *eap;
+       int ret;
+
+       EVP_add_digest(EVP_sha256());
+       eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+                                   EAP_VENDOR_IETF, EAP_TYPE_PWD, "PWD");
+       if (eap == NULL)
+               return -1;
+
+       eap->init = eap_pwd_init;
+       eap->deinit = eap_pwd_deinit;
+       eap->process = eap_pwd_process;
+       eap->isKeyAvailable = eap_pwd_key_available;
+       eap->getKey = eap_pwd_getkey;
+       eap->get_emsk = eap_pwd_get_emsk;
+
+       ret = eap_peer_method_register(eap);
+       if (ret)
+               eap_peer_method_free(eap);
+       return ret;
+}
index bb06bb2..1474b7f 100644 (file)
@@ -15,6 +15,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/random.h"
 #include "eap_peer/eap_i.h"
 #include "eap_common/eap_sake_common.h"
 
@@ -223,7 +224,7 @@ static struct wpabuf * eap_sake_process_challenge(struct eap_sm *sm,
        wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
                    data->rand_s, EAP_SAKE_RAND_LEN);
 
-       if (os_get_random(data->rand_p, EAP_SAKE_RAND_LEN)) {
+       if (random_get_bytes(data->rand_p, EAP_SAKE_RAND_LEN)) {
                wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
                return NULL;
        }
index 3d8afb2..06fbc5b 100644 (file)
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "pcsc_funcs.h"
 #include "crypto/milenage.h"
+#include "crypto/random.h"
 #include "eap_peer/eap_i.h"
 #include "eap_config.h"
 #include "eap_common/eap_sim_common.h"
@@ -93,7 +94,7 @@ static void * eap_sim_init(struct eap_sm *sm)
        if (data == NULL)
                return NULL;
 
-       if (os_get_random(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
+       if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
                wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
                           "for NONCE_MT");
                os_free(data);
@@ -265,21 +266,20 @@ static int eap_sim_supported_ver(int version)
 
 static void eap_sim_clear_identities(struct eap_sim_data *data, int id)
 {
-       wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old%s%s%s",
-                  id & CLEAR_PSEUDONYM ? " pseudonym" : "",
-                  id & CLEAR_REAUTH_ID ? " reauth_id" : "",
-                  id & CLEAR_EAP_ID ? " eap_id" : "");
-       if (id & CLEAR_PSEUDONYM) {
+       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;
        }
-       if (id & CLEAR_REAUTH_ID) {
+       if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
+               wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old reauth_id");
                os_free(data->reauth_id);
                data->reauth_id = NULL;
                data->reauth_id_len = 0;
        }
-       if (id & CLEAR_EAP_ID) {
+       if ((id & CLEAR_EAP_ID) && data->last_eap_identity) {
+               wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old eap_id");
                os_free(data->last_eap_identity);
                data->last_eap_identity = NULL;
                data->last_eap_identity_len = 0;
@@ -648,11 +648,11 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
                                            EAP_SIM_UNABLE_TO_PROCESS_PACKET);
        }
 
-       /* Old reauthentication and pseudonym identities must not be used
-        * anymore. In other words, if no new identities are received, full
-        * authentication will be used on next reauthentication. */
-       eap_sim_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID |
-                                CLEAR_EAP_ID);
+       /* Old reauthentication identity must not be used anymore. In
+        * other words, if no new reauth identity is received, full
+        * authentication will be used on next reauthentication (using
+        * pseudonym identity or permanent identity). */
+       eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
 
        if (attr->encr_data) {
                u8 *decrypted;
@@ -995,7 +995,7 @@ static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv)
 static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv)
 {
        struct eap_sim_data *data = priv;
-       if (os_get_random(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
+       if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
                wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
                           "for NONCE_MT");
                os_free(data);
index 7bd50f6..2934ba4 100644 (file)
@@ -112,7 +112,6 @@ static int eap_tls_params_from_conf(struct eap_sm *sm,
                wpa_printf(MSG_DEBUG, "TLS: using phase1 config options");
                eap_tls_params_from_conf1(params, config);
        }
-       params->tls_ia = data->tls_ia;
 
        /*
         * Use blob data, if available. Otherwise, leave reference to external
@@ -295,9 +294,9 @@ u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
        os_memcpy(rnd + keys.client_random_len, keys.server_random,
                  keys.server_random_len);
 
-       if (tls_prf(keys.master_key, keys.master_key_len,
-                   label, rnd, keys.client_random_len +
-                   keys.server_random_len, out, len))
+       if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
+                            label, rnd, keys.client_random_len +
+                            keys.server_random_len, out, len))
                goto fail;
 
        os_free(rnd);
@@ -361,7 +360,8 @@ static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data,
                eap_peer_tls_reset_input(data);
                return -1;
        }
-       wpabuf_put_buf(data->tls_in, in_data);
+       if (in_data)
+               wpabuf_put_buf(data->tls_in, in_data);
        data->tls_in_left -= in_len;
 
        if (data->tls_in_left > 0) {
index e9e0998..e9a07b8 100644 (file)
@@ -66,11 +66,6 @@ struct eap_ssl_data {
        int include_tls_length;
 
        /**
-        * tls_ia - Whether TLS/IA is enabled for this TLS connection
-        */
-       int tls_ia;
-
-       /**
         * eap - EAP state machine allocated with eap_peer_sm_init()
         */
        struct eap_sm *eap;
index 6c95f72..da288eb 100644 (file)
@@ -15,7 +15,6 @@
 #include "includes.h"
 
 #include "common.h"
-#include "base64.h"
 #include "eap_i.h"
 #include "tncc.h"
 
index 2573780..612dfa7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-TTLS (RFC 5281)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * 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
 #include "eap_config.h"
 
 
-/* Maximum supported TTLS version
- * 0 = RFC 5281
- * 1 = draft-funk-eap-ttls-v1-00.txt
- */
-#ifndef EAP_TTLS_VERSION
-#define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */
-#endif /* EAP_TTLS_VERSION */
-
-
-#define MSCHAPV2_KEY_LEN 16
-#define MSCHAPV2_NT_RESPONSE_LEN 24
+#define EAP_TTLS_VERSION 0
 
 
 static void eap_ttls_deinit(struct eap_sm *sm, void *priv);
@@ -44,9 +34,8 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv);
 
 struct eap_ttls_data {
        struct eap_ssl_data ssl;
-       int ssl_initialized;
 
-       int ttls_version, force_ttls_version;
+       int ttls_version;
 
        const struct eap_method *phase2_method;
        void *phase2_priv;
@@ -91,22 +80,9 @@ static void * eap_ttls_init(struct eap_sm *sm)
        if (data == NULL)
                return NULL;
        data->ttls_version = EAP_TTLS_VERSION;
-       data->force_ttls_version = -1;
        selected = "EAP";
        data->phase2_type = EAP_TTLS_PHASE2_EAP;
 
-#if EAP_TTLS_VERSION > 0
-       if (config && config->phase1) {
-               const char *pos = os_strstr(config->phase1, "ttlsver=");
-               if (pos) {
-                       data->force_ttls_version = atoi(pos + 8);
-                       data->ttls_version = data->force_ttls_version;
-                       wpa_printf(MSG_DEBUG, "EAP-TTLS: Forced TTLS version "
-                                  "%d", data->force_ttls_version);
-               }
-       }
-#endif /* EAP_TTLS_VERSION */
-
        if (config && config->phase2) {
                if (os_strstr(config->phase2, "autheap=")) {
                        selected = "EAP";
@@ -140,19 +116,11 @@ static void * eap_ttls_init(struct eap_sm *sm)
                data->phase2_eap_type.method = EAP_TYPE_NONE;
        }
 
-#if EAP_TTLS_VERSION > 0
-       if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) &&
-           data->ttls_version > 0) {
-               if (data->force_ttls_version > 0) {
-                       wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and "
-                                  "TLS library does not support TLS/IA.",
-                                  data->force_ttls_version);
-                       eap_ttls_deinit(sm, data);
-                       return NULL;
-               }
-               data->ttls_version = 0;
+       if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
+               wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
+               eap_ttls_deinit(sm, data);
+               return NULL;
        }
-#endif /* EAP_TTLS_VERSION */
 
        return data;
 }
@@ -176,8 +144,7 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
                return;
        eap_ttls_phase2_eap_deinit(sm, data);
        os_free(data->phase2_eap_types);
-       if (data->ssl_initialized)
-               eap_peer_tls_ssl_deinit(sm, &data->ssl);
+       eap_peer_tls_ssl_deinit(sm, &data->ssl);
        os_free(data->key_data);
        wpabuf_free(data->pending_phase2_req);
        os_free(data);
@@ -202,7 +169,7 @@ static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id,
        }
 
        avp->avp_code = host_to_be32(avp_code);
-       avp->avp_length = host_to_be32((flags << 24) | (hdrlen + len));
+       avp->avp_length = host_to_be32((flags << 24) | (u32) (hdrlen + len));
 
        return avphdr + hdrlen;
 }
@@ -246,39 +213,6 @@ static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code,
 }
 
 
-#if EAP_TTLS_VERSION > 0
-static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm,
-                                           struct eap_ttls_data *data,
-                                           const u8 *key, size_t key_len)
-{
-       u8 *buf;
-       size_t buf_len;
-       int ret;
-
-       if (key) {
-               buf_len = 2 + key_len;
-               buf = os_malloc(buf_len);
-               if (buf == NULL)
-                       return -1;
-               WPA_PUT_BE16(buf, key_len);
-               os_memcpy(buf + 2, key, key_len);
-       } else {
-               buf = NULL;
-               buf_len = 0;
-       }
-
-       wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner "
-                       "secret permutation", buf, buf_len);
-       ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx,
-                                                    data->ssl.conn,
-                                                    buf, buf_len);
-       os_free(buf);
-
-       return ret;
-}
-#endif /* EAP_TTLS_VERSION */
-
-
 static int eap_ttls_v0_derive_key(struct eap_sm *sm,
                                  struct eap_ttls_data *data)
 {
@@ -298,156 +232,10 @@ static int eap_ttls_v0_derive_key(struct eap_sm *sm,
 }
 
 
-#if EAP_TTLS_VERSION > 0
-static int eap_ttls_v1_derive_key(struct eap_sm *sm,
-                                 struct eap_ttls_data *data)
-{
-       struct tls_keys keys;
-       u8 *rnd;
-
-       os_free(data->key_data);
-       data->key_data = NULL;
-
-       os_memset(&keys, 0, sizeof(keys));
-       if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
-           keys.client_random == NULL || keys.server_random == NULL ||
-           keys.inner_secret == NULL) {
-               wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
-                          "client random, or server random to derive keying "
-                          "material");
-               return -1;
-       }
-
-       rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-       data->key_data = os_malloc(EAP_TLS_KEY_LEN);
-       if (rnd == NULL || data->key_data == NULL) {
-               wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation");
-               os_free(rnd);
-               os_free(data->key_data);
-               data->key_data = NULL;
-               return -1;
-       }
-       os_memcpy(rnd, keys.client_random, keys.client_random_len);
-       os_memcpy(rnd + keys.client_random_len, keys.server_random,
-                 keys.server_random_len);
-
-       if (tls_prf(keys.inner_secret, keys.inner_secret_len,
-                   "ttls v1 keying material", rnd, keys.client_random_len +
-                   keys.server_random_len, data->key_data, EAP_TLS_KEY_LEN)) {
-               wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key");
-               os_free(rnd);
-               os_free(data->key_data);
-               data->key_data = NULL;
-               return -1;
-       }
-
-       wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random",
-                   rnd, keys.client_random_len + keys.server_random_len);
-       wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret",
-                       keys.inner_secret, keys.inner_secret_len);
-
-       os_free(rnd);
-
-       wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
-                       data->key_data, EAP_TLS_KEY_LEN);
-
-       return 0;
-}
-#endif /* EAP_TTLS_VERSION */
-
-
 static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
                                        struct eap_ttls_data *data, size_t len)
 {
-#if EAP_TTLS_VERSION > 0
-       struct tls_keys keys;
-       u8 *challenge, *rnd;
-#endif /* EAP_TTLS_VERSION */
-
-       if (data->ttls_version == 0) {
-               return eap_peer_tls_derive_key(sm, &data->ssl,
-                                              "ttls challenge", len);
-       }
-
-#if EAP_TTLS_VERSION > 0
-
-       os_memset(&keys, 0, sizeof(keys));
-       if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
-           keys.client_random == NULL || keys.server_random == NULL ||
-           keys.inner_secret == NULL) {
-               wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
-                          "client random, or server random to derive "
-                          "implicit challenge");
-               return NULL;
-       }
-
-       rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-       challenge = os_malloc(len);
-       if (rnd == NULL || challenge == NULL) {
-               wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit "
-                          "challenge derivation");
-               os_free(rnd);
-               os_free(challenge);
-               return NULL;
-       }
-       os_memcpy(rnd, keys.server_random, keys.server_random_len);
-       os_memcpy(rnd + keys.server_random_len, keys.client_random,
-                 keys.client_random_len);
-
-       if (tls_prf(keys.inner_secret, keys.inner_secret_len,
-                   "inner application challenge", rnd,
-                   keys.client_random_len + keys.server_random_len,
-                   challenge, len)) {
-               wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit "
-                          "challenge");
-               os_free(rnd);
-               os_free(challenge);
-               return NULL;
-       }
-
-       os_free(rnd);
-
-       wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge",
-                       challenge, len);
-
-       return challenge;
-
-#else /* EAP_TTLS_VERSION */
-
-       return NULL;
-
-#endif /* EAP_TTLS_VERSION */
-}
-
-
-static void eap_ttlsv1_phase2_eap_finish(struct eap_sm *sm,
-                                        struct eap_ttls_data *data,
-                                        struct eap_method_ret *ret)
-{
-#if EAP_TTLS_VERSION > 0
-       if (data->ttls_version > 0) {
-               const struct eap_method *m = data->phase2_method;
-               void *priv = data->phase2_priv;
-
-               /* TTLSv1 requires TLS/IA FinalPhaseFinished */
-               if (ret->decision == DECISION_UNCOND_SUCC)
-                       ret->decision = DECISION_COND_SUCC;
-               ret->methodState = METHOD_CONT;
-
-               if (ret->decision == DECISION_COND_SUCC &&
-                   m->isKeyAvailable && m->getKey &&
-                   m->isKeyAvailable(sm, priv)) {
-                       u8 *key;
-                       size_t key_len;
-                       key = m->getKey(sm, priv, &key_len);
-                       if (key) {
-                               eap_ttls_ia_permute_inner_secret(
-                                       sm, data, key, key_len);
-                               os_free(key);
-                       }
-               }
-       }
-#endif /* EAP_TTLS_VERSION */
+       return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len);
 }
 
 
@@ -494,7 +282,6 @@ static int eap_ttls_phase2_eap_process(struct eap_sm *sm,
                ret->methodState = iret.methodState;
                ret->decision = iret.decision;
        }
-       eap_ttlsv1_phase2_eap_finish(sm, data, ret);
 
        return 0;
 }
@@ -615,26 +402,6 @@ static int eap_ttls_phase2_request_eap(struct eap_sm *sm,
 }
 
 
-static void eap_ttlsv1_permute_inner(struct eap_sm *sm,
-                                    struct eap_ttls_data *data)
-{
-#if EAP_TTLS_VERSION > 0
-       u8 session_key[2 * MSCHAPV2_KEY_LEN];
-
-       if (data->ttls_version == 0)
-               return;
-
-       get_asymetric_start_key(data->master_key, session_key,
-                               MSCHAPV2_KEY_LEN, 0, 0);
-       get_asymetric_start_key(data->master_key,
-                               session_key + MSCHAPV2_KEY_LEN,
-                               MSCHAPV2_KEY_LEN, 1, 0);
-       eap_ttls_ia_permute_inner_secret(sm, data, session_key,
-                                        sizeof(session_key));
-#endif /* EAP_TTLS_VERSION */
-}
-
-
 static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
                                            struct eap_ttls_data *data,
                                            struct eap_method_ret *ret,
@@ -702,8 +469,6 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
        }
        data->auth_response_valid = 1;
 
-       eap_ttlsv1_permute_inner(sm, data);
-
        pos += 24;
        os_free(challenge);
        AVP_PAD(buf, pos);
@@ -711,7 +476,7 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
        wpabuf_put(msg, pos - buf);
        *resp = msg;
 
-       if (sm->workaround && data->ttls_version == 0) {
+       if (sm->workaround) {
                /* At least FreeRADIUS seems to be terminating
                 * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success
                 * packet. */
@@ -798,17 +563,10 @@ static int eap_ttls_phase2_request_mschap(struct eap_sm *sm,
        wpabuf_put(msg, pos - buf);
        *resp = msg;
 
-       if (data->ttls_version > 0) {
-               /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success,
-                * so do not allow connection to be terminated yet. */
-               ret->methodState = METHOD_CONT;
-               ret->decision = DECISION_COND_SUCC;
-       } else {
-               /* EAP-TTLS/MSCHAP does not provide tunneled success
-                * notification, so assume that Phase2 succeeds. */
-               ret->methodState = METHOD_DONE;
-               ret->decision = DECISION_COND_SUCC;
-       }
+       /* EAP-TTLS/MSCHAP does not provide tunneled success
+        * notification, so assume that Phase2 succeeds. */
+       ret->methodState = METHOD_DONE;
+       ret->decision = DECISION_COND_SUCC;
 
        return 0;
 }
@@ -859,17 +617,10 @@ static int eap_ttls_phase2_request_pap(struct eap_sm *sm,
        wpabuf_put(msg, pos - buf);
        *resp = msg;
 
-       if (data->ttls_version > 0) {
-               /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success,
-                * so do not allow connection to be terminated yet. */
-               ret->methodState = METHOD_CONT;
-               ret->decision = DECISION_COND_SUCC;
-       } else {
-               /* EAP-TTLS/PAP does not provide tunneled success notification,
-                * so assume that Phase2 succeeds. */
-               ret->methodState = METHOD_DONE;
-               ret->decision = DECISION_COND_SUCC;
-       }
+       /* EAP-TTLS/PAP does not provide tunneled success notification,
+        * so assume that Phase2 succeeds. */
+       ret->methodState = METHOD_DONE;
+       ret->decision = DECISION_COND_SUCC;
 
        return 0;
 }
@@ -942,17 +693,10 @@ static int eap_ttls_phase2_request_chap(struct eap_sm *sm,
        wpabuf_put(msg, pos - buf);
        *resp = msg;
 
-       if (data->ttls_version > 0) {
-               /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success,
-                * so do not allow connection to be terminated yet. */
-               ret->methodState = METHOD_CONT;
-               ret->decision = DECISION_COND_SUCC;
-       } else {
-               /* EAP-TTLS/CHAP does not provide tunneled success
-                * notification, so assume that Phase2 succeeds. */
-               ret->methodState = METHOD_DONE;
-               ret->decision = DECISION_COND_SUCC;
-       }
+       /* EAP-TTLS/CHAP does not provide tunneled success
+        * notification, so assume that Phase2 succeeds. */
+       ret->methodState = METHOD_DONE;
+       ret->decision = DECISION_COND_SUCC;
 
        return 0;
 }
@@ -1027,36 +771,6 @@ static int eap_ttls_phase2_request(struct eap_sm *sm,
 }
 
 
-#if EAP_TTLS_VERSION > 0
-static struct wpabuf * eap_ttls_build_phase_finished(
-       struct eap_sm *sm, struct eap_ttls_data *data, int id, int final)
-{
-       struct wpabuf *req, *buf;
-
-       buf = tls_connection_ia_send_phase_finished(sm->ssl_ctx,
-                                                   data->ssl.conn,
-                                                   final);
-       if (buf == NULL)
-               return NULL;
-
-       req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS,
-                           1 + wpabuf_len(buf),
-                           EAP_CODE_RESPONSE, id);
-       if (req == NULL) {
-               wpabuf_free(buf);
-               return NULL;
-       }
-
-       wpabuf_put_u8(req, data->ttls_version);
-       wpabuf_put_buf(req, buf);
-       wpabuf_free(buf);
-       eap_update_len(req);
-
-       return req;
-}
-#endif /* EAP_TTLS_VERSION */
-
-
 struct ttls_parse_avp {
        u8 *mschapv2;
        u8 *eapdata;
@@ -1366,19 +1080,9 @@ static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
 
        wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 "
                   "authentication succeeded");
-       if (data->ttls_version > 0) {
-               /*
-                * EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report
-                * success, so do not allow connection to be terminated
-                * yet.
-                */
-               ret->methodState = METHOD_CONT;
-               ret->decision = DECISION_COND_SUCC;
-       } else {
-               ret->methodState = METHOD_DONE;
-               ret->decision = DECISION_UNCOND_SUCC;
-               data->phase2_success = 1;
-       }
+       ret->methodState = METHOD_DONE;
+       ret->decision = DECISION_UNCOND_SUCC;
+       data->phase2_success = 1;
 
        /*
         * Reply with empty data; authentication server will reply
@@ -1493,24 +1197,6 @@ static int eap_ttls_process_decrypted(struct eap_sm *sm,
 }
 
 
-#if EAP_TTLS_VERSION > 0
-static void eap_ttls_final_phase_finished(struct eap_sm *sm,
-                                         struct eap_ttls_data *data,
-                                         struct eap_method_ret *ret,
-                                         u8 identifier,
-                                         struct wpabuf **out_data)
-{
-       wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished received");
-       wpa_printf(MSG_INFO, "EAP-TTLS: TLS/IA authentication succeeded");
-       ret->methodState = METHOD_DONE;
-       ret->decision = DECISION_UNCOND_SUCC;
-       data->phase2_success = 1;
-       *out_data = eap_ttls_build_phase_finished(sm, data, identifier, 1);
-       eap_ttls_v1_derive_key(sm, data);
-}
-#endif /* EAP_TTLS_VERSION */
-
-
 static int eap_ttls_implicit_identity_request(struct eap_sm *sm,
                                              struct eap_ttls_data *data,
                                              struct eap_method_ret *ret,
@@ -1534,6 +1220,21 @@ static int eap_ttls_implicit_identity_request(struct eap_sm *sm,
                           "processing failed");
                retval = -1;
        } else {
+               struct eap_peer_config *config = eap_get_config(sm);
+               if (resp == NULL &&
+                   (config->pending_req_identity ||
+                    config->pending_req_password ||
+                    config->pending_req_otp ||
+                    config->pending_req_new_password)) {
+                       /*
+                        * Use empty buffer to force implicit request
+                        * processing when EAP request is re-processed after
+                        * user input.
+                        */
+                       wpabuf_free(data->pending_phase2_req);
+                       data->pending_phase2_req = wpabuf_alloc(0);
+               }
+
                retval = eap_ttls_encrypt_response(sm, data, resp, identifier,
                                                   out_data);
        }
@@ -1627,17 +1328,6 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
        if (retval)
                goto done;
 
-#if EAP_TTLS_VERSION > 0
-       if (data->ttls_version > 0 &&
-           (in_decrypted == NULL || wpabuf_len(in_decrypted) == 0) &&
-           tls_connection_ia_final_phase_finished(sm->ssl_ctx,
-                                                  data->ssl.conn)) {
-               eap_ttls_final_phase_finished(sm, data, ret, identifier,
-                                             out_data);
-               goto done;
-       }
-#endif /* EAP_TTLS_VERSION */
-
 continue_req:
        data->phase2_start = 0;
 
@@ -1662,46 +1352,6 @@ done:
 }
 
 
-static int eap_ttls_process_start(struct eap_sm *sm,
-                                 struct eap_ttls_data *data, u8 flags,
-                                 struct eap_method_ret *ret)
-{
-       struct eap_peer_config *config = eap_get_config(sm);
-
-       wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own ver=%d)",
-                  flags & EAP_TLS_VERSION_MASK, data->ttls_version);
-#if EAP_TTLS_VERSION > 0
-       if ((flags & EAP_TLS_VERSION_MASK) < data->ttls_version)
-               data->ttls_version = flags & EAP_TLS_VERSION_MASK;
-       if (data->force_ttls_version >= 0 &&
-           data->force_ttls_version != data->ttls_version) {
-               wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to select "
-                          "forced TTLS version %d",
-                          data->force_ttls_version);
-               ret->methodState = METHOD_DONE;
-               ret->decision = DECISION_FAIL;
-               ret->allowNotifications = FALSE;
-               return -1;
-       }
-       wpa_printf(MSG_DEBUG, "EAP-TTLS: Using TTLS version %d",
-                  data->ttls_version);
-
-       if (data->ttls_version > 0)
-               data->ssl.tls_ia = 1;
-#endif /* EAP_TTLS_VERSION */
-       if (!data->ssl_initialized &&
-           eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
-               wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
-               return -1;
-       }
-       data->ssl_initialized = 1;
-
-       wpa_printf(MSG_DEBUG, "EAP-TTLS: Start");
-
-       return 0;
-}
-
-
 static int eap_ttls_process_handshake(struct eap_sm *sm,
                                      struct eap_ttls_data *data,
                                      struct eap_method_ret *ret,
@@ -1725,8 +1375,7 @@ static int eap_ttls_process_handshake(struct eap_sm *sm,
                        ret->methodState = METHOD_MAY_CONT;
                }
                data->phase2_start = 1;
-               if (data->ttls_version == 0)
-                       eap_ttls_v0_derive_key(sm, data);
+               eap_ttls_v0_derive_key(sm, data);
 
                if (*out_data == NULL || wpabuf_len(*out_data) == 0) {
                        if (eap_ttls_decrypt(sm, data, ret, identifier,
@@ -1761,7 +1410,7 @@ static void eap_ttls_check_auth_status(struct eap_sm *sm,
                                       struct eap_ttls_data *data,
                                       struct eap_method_ret *ret)
 {
-       if (data->ttls_version == 0 && ret->methodState == METHOD_DONE) {
+       if (ret->methodState == METHOD_DONE) {
                ret->allowNotifications = FALSE;
                if (ret->decision == DECISION_UNCOND_SUCC ||
                    ret->decision == DECISION_COND_SUCC) {
@@ -1779,8 +1428,7 @@ static void eap_ttls_check_auth_status(struct eap_sm *sm,
                        }
 #endif /* EAP_TNC */
                }
-       } else if (data->ttls_version == 0 &&
-                  ret->methodState == METHOD_MAY_CONT &&
+       } else if (ret->methodState == METHOD_MAY_CONT &&
                   (ret->decision == DECISION_UNCOND_SUCC ||
                    ret->decision == DECISION_COND_SUCC)) {
                        wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
@@ -1808,8 +1456,9 @@ static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv,
        id = eap_get_id(reqData);
 
        if (flags & EAP_TLS_FLAGS_START) {
-               if (eap_ttls_process_start(sm, data, flags, ret) < 0)
-                       return NULL;
+               wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own "
+                          "ver=%d)", flags & EAP_TLS_VERSION_MASK,
+                          data->ttls_version);
 
                /* RFC 5281, Ch. 9.2:
                 * "This packet MAY contain additional information in the form
@@ -1817,13 +1466,6 @@ static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv,
                 * For now, ignore any potential extra data.
                 */
                left = 0;
-       } else if (!data->ssl_initialized) {
-               wpa_printf(MSG_DEBUG, "EAP-TTLS: First message did not "
-                          "include Start flag");
-               ret->methodState = METHOD_DONE;
-               ret->decision = DECISION_FAIL;
-               ret->allowNotifications = FALSE;
-               return NULL;
        }
 
        resp = NULL;
index 8317f72..09d8a1c 100644 (file)
@@ -203,6 +203,10 @@ static void * eap_wsc_init(struct eap_sm *sm)
                return NULL;
        }
 
+       pos = os_strstr(phase1, "dev_pw_id=");
+       if (pos && cfg.pin)
+               cfg.dev_pw_id = atoi(pos + 10);
+
        res = eap_wsc_new_ap_settings(&new_ap_settings, phase1);
        if (res < 0) {
                os_free(data);
@@ -219,10 +223,16 @@ static void * eap_wsc_init(struct eap_sm *sm)
                os_free(data);
                return NULL;
        }
-       data->fragment_size = WSC_FRAGMENT_SIZE;
+       res = eap_get_config_fragment_size(sm);
+       if (res > 0)
+               data->fragment_size = res;
+       else
+               data->fragment_size = WSC_FRAGMENT_SIZE;
+       wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment size limit %u",
+                  (unsigned int) data->fragment_size);
 
        if (registrar && cfg.pin) {
-               wps_registrar_add_pin(data->wps_ctx->registrar, NULL,
+               wps_registrar_add_pin(data->wps_ctx->registrar, NULL, NULL,
                                      cfg.pin, cfg.pin_len, 0);
        }
 
index 309a331..acd7611 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "common.h"
 #include "crypto/dh_groups.h"
+#include "crypto/random.h"
 #include "ikev2.h"
 
 
@@ -424,7 +425,7 @@ static int ikev2_process_kei(struct ikev2_responder_data *data,
        }
 
        /* RFC 4306, Section 3.4:
-        * The length of DH public value MUST be equal to the lenght of the
+        * The length of DH public value MUST be equal to the length of the
         * prime modulus.
         */
        if (kei_len - 4 != data->dh->prime_len) {
@@ -1133,7 +1134,7 @@ static struct wpabuf * ikev2_build_sa_init(struct ikev2_responder_data *data)
                    data->r_spi, IKEV2_SPI_LEN);
 
        data->r_nonce_len = IKEV2_NONCE_MIN_LEN;
-       if (os_get_random(data->r_nonce, data->r_nonce_len))
+       if (random_get_bytes(data->r_nonce, data->r_nonce_len))
                return NULL;
 #ifdef CCNS_PL
        /* Zeros are removed incorrectly from the beginning of the nonces in
index eaaa168..a70d70c 100644 (file)
@@ -180,11 +180,11 @@ TNC_Result TNC_TNCC_ReportMessageTypes(
        imc = tnc_imc[imcID];
        os_free(imc->supported_types);
        imc->supported_types =
-               os_malloc(typeCount * sizeof(TNC_MessageTypeList));
+               os_malloc(typeCount * sizeof(TNC_MessageType));
        if (imc->supported_types == NULL)
                return TNC_RESULT_FATAL;
        os_memcpy(imc->supported_types, supportedTypes,
-                 typeCount * sizeof(TNC_MessageTypeList));
+                 typeCount * sizeof(TNC_MessageType));
        imc->num_supported_types = typeCount;
 
        return TNC_RESULT_SUCCESS;
index 92400a5..d5f8f1d 100644 (file)
@@ -22,8 +22,6 @@
 
 struct eap_sm;
 
-#define EAP_MAX_METHODS 8
-
 #define EAP_TTLS_AUTH_PAP 1
 #define EAP_TTLS_AUTH_CHAP 2
 #define EAP_TTLS_AUTH_MSCHAP 4
@@ -95,6 +93,7 @@ struct eap_config {
        void *eap_sim_db_priv;
        Boolean backend_auth;
        int eap_server;
+       u16 pwd_group;
        u8 *pac_opaque_encr_key;
        u8 *eap_fast_a_id;
        size_t eap_fast_a_id_len;
@@ -106,7 +105,11 @@ struct eap_config {
        int tnc;
        struct wps_context *wps;
        const struct wpabuf *assoc_wps_ie;
+       const struct wpabuf *assoc_p2p_ie;
        const u8 *peer_addr;
+       int fragment_size;
+
+       int pbc_in_m1;
 };
 
 
@@ -120,5 +123,6 @@ void eap_sm_pending_cb(struct eap_sm *sm);
 int eap_sm_method_pending(struct eap_sm *sm);
 const u8 * eap_get_identity(struct eap_sm *sm, size_t *len);
 struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm);
+void eap_server_clear_identity(struct eap_sm *sm);
 
 #endif /* EAP_H */
index 4269a8c..f48cf71 100644 (file)
@@ -119,7 +119,7 @@ struct eap_sm {
 
        /* Full authenticator state machine local variables */
 
-       /* Long-term (maintained betwen packets) */
+       /* Long-term (maintained between packets) */
        EapType currentMethod;
        int currentId;
        enum {
@@ -181,12 +181,19 @@ struct eap_sm {
        int pac_key_refresh_time;
        int eap_sim_aka_result_ind;
        int tnc;
+       u16 pwd_group;
        struct wps_context *wps;
        struct wpabuf *assoc_wps_ie;
+       struct wpabuf *assoc_p2p_ie;
 
        Boolean start_reauth;
 
        u8 peer_addr[ETH_ALEN];
+
+       /* Fragmentation size for EAP method init() handler */
+       int fragment_size;
+
+       int pbc_in_m1;
 };
 
 int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
index 5d4d92c..4a5296e 100644 (file)
@@ -49,5 +49,6 @@ int eap_server_fast_register(void);
 int eap_server_wsc_register(void);
 int eap_server_ikev2_register(void);
 int eap_server_tnc_register(void);
+int eap_server_pwd_register(void);
 
 #endif /* EAP_SERVER_METHODS_H */
index fdc26f9..7a5beb6 100644 (file)
@@ -136,6 +136,14 @@ SM_STATE(EAP, INITIALIZE)
 {
        SM_ENTRY(EAP, INITIALIZE);
 
+       if (sm->eap_if.eapRestart && !sm->eap_server && sm->identity) {
+               /*
+                * Need to allow internal Identity method to be used instead
+                * of passthrough at the beginning of reauthentication.
+                */
+               eap_server_clear_identity(sm);
+       }
+
        sm->currentId = -1;
        sm->eap_if.eapSuccess = FALSE;
        sm->eap_if.eapFail = FALSE;
@@ -1028,9 +1036,12 @@ void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len)
 
        not_found:
                /* not found - remove from the list */
-               os_memmove(&sm->user->methods[i], &sm->user->methods[i + 1],
-                          (EAP_MAX_METHODS - i - 1) *
-                          sizeof(sm->user->methods[0]));
+               if (i + 1 < EAP_MAX_METHODS) {
+                       os_memmove(&sm->user->methods[i],
+                                  &sm->user->methods[i + 1],
+                                  (EAP_MAX_METHODS - i - 1) *
+                                  sizeof(sm->user->methods[0]));
+               }
                sm->user->methods[EAP_MAX_METHODS - 1].vendor =
                        EAP_VENDOR_IETF;
                sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE;
@@ -1255,8 +1266,13 @@ struct eap_sm * eap_server_sm_init(void *eapol_ctx,
        sm->wps = conf->wps;
        if (conf->assoc_wps_ie)
                sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie);
+       if (conf->assoc_p2p_ie)
+               sm->assoc_p2p_ie = wpabuf_dup(conf->assoc_p2p_ie);
        if (conf->peer_addr)
                os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN);
+       sm->fragment_size = conf->fragment_size;
+       sm->pwd_group = conf->pwd_group;
+       sm->pbc_in_m1 = conf->pbc_in_m1;
 
        wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
 
@@ -1291,6 +1307,7 @@ void eap_server_sm_deinit(struct eap_sm *sm)
        os_free(sm->eap_if.aaaEapKeyData);
        eap_user_free(sm->user);
        wpabuf_free(sm->assoc_wps_ie);
+       wpabuf_free(sm->assoc_p2p_ie);
        os_free(sm);
 }
 
@@ -1362,3 +1379,18 @@ struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm)
 {
        return &sm->eap_if;
 }
+
+
+/**
+ * eap_server_clear_identity - Clear EAP identity information
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ *
+ * This function can be used to clear the EAP identity information in the EAP
+ * server context. This allows the EAP/Identity method to be used again after
+ * EAPOL-Start or EAPOL-Logoff.
+ */
+void eap_server_clear_identity(struct eap_sm *sm)
+{
+       os_free(sm->identity);
+       sm->identity = NULL;
+}
index 4e7db48..0f25ffd 100644 (file)
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "crypto/sha256.h"
 #include "crypto/crypto.h"
+#include "crypto/random.h"
 #include "eap_common/eap_sim_common.h"
 #include "eap_server/eap_i.h"
 #include "eap_server/eap_sim_db.h"
@@ -132,14 +133,13 @@ static void * eap_aka_prime_init(struct eap_sm *sm)
                return NULL;
 
        data->eap_method = EAP_TYPE_AKA_PRIME;
-       data->network_name = os_malloc(os_strlen(network_name));
+       data->network_name = (u8 *) os_strdup(network_name);
        if (data->network_name == NULL) {
                os_free(data);
                return NULL;
        }
 
        data->network_name_len = os_strlen(network_name);
-       os_memcpy(data->network_name, network_name, data->network_name_len);
 
        data->state = IDENTITY;
        eap_aka_determine_identity(sm, data, 1, 0);
@@ -440,7 +440,7 @@ static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm,
 
        wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication");
 
-       if (os_get_random(data->nonce_s, EAP_SIM_NONCE_S_LEN))
+       if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN))
                return NULL;
        wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S",
                        data->nonce_s, EAP_SIM_NONCE_S_LEN);
index 39beb33..ba17e98 100644 (file)
@@ -18,6 +18,7 @@
 #include "crypto/aes_wrap.h"
 #include "crypto/sha1.h"
 #include "crypto/tls.h"
+#include "crypto/random.h"
 #include "eap_common/eap_tlv_common.h"
 #include "eap_common/eap_fast_common.h"
 #include "eap_i.h"
@@ -642,7 +643,7 @@ static struct wpabuf * eap_fast_build_crypto_binding(
        binding->version = EAP_FAST_VERSION;
        binding->received_version = data->peer_version;
        binding->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST;
-       if (os_get_random(binding->nonce, sizeof(binding->nonce)) < 0) {
+       if (random_get_bytes(binding->nonce, sizeof(binding->nonce)) < 0) {
                wpabuf_free(buf);
                return NULL;
        }
@@ -692,7 +693,7 @@ static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm,
        struct eap_tlv_result_tlv *result;
        struct os_time now;
 
-       if (os_get_random(pac_key, EAP_FAST_PAC_KEY_LEN) < 0 ||
+       if (random_get_bytes(pac_key, EAP_FAST_PAC_KEY_LEN) < 0 ||
            os_get_time(&now) < 0)
                return NULL;
        wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Generated PAC-Key",
index d0c7559..a794806 100644 (file)
@@ -15,6 +15,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/random.h"
 #include "eap_server/eap_i.h"
 #include "eap_common/eap_gpsk_common.h"
 
@@ -120,7 +121,7 @@ static struct wpabuf * eap_gpsk_build_gpsk_1(struct eap_sm *sm,
 
        wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-1");
 
-       if (os_get_random(data->rand_server, EAP_GPSK_RAND_LEN)) {
+       if (random_get_bytes(data->rand_server, EAP_GPSK_RAND_LEN)) {
                wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to get random data");
                eap_gpsk_state(data, FAILURE);
                return NULL;
index 06074ee..ec4fa87 100644 (file)
@@ -93,7 +93,8 @@ static void * eap_ikev2_init(struct eap_sm *sm)
        if (data == NULL)
                return NULL;
        data->state = MSG;
-       data->fragment_size = IKEV2_FRAGMENT_SIZE;
+       data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size :
+               IKEV2_FRAGMENT_SIZE;
        data->ikev2.state = SA_INIT;
        data->ikev2.peer_auth = PEER_AUTH_SECRET;
        data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2");
index dee2dc5..d03ec53 100644 (file)
@@ -15,6 +15,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/random.h"
 #include "eap_i.h"
 #include "eap_common/chap.h"
 
@@ -52,7 +53,7 @@ static struct wpabuf * eap_md5_buildReq(struct eap_sm *sm, void *priv, u8 id)
        struct eap_md5_data *data = priv;
        struct wpabuf *req;
 
-       if (os_get_random(data->challenge, CHALLENGE_LEN)) {
+       if (random_get_bytes(data->challenge, CHALLENGE_LEN)) {
                wpa_printf(MSG_ERROR, "EAP-MD5: Failed to get random data");
                data->state = FAILURE;
                return NULL;
index 900a5dd..4d241a4 100644 (file)
@@ -167,6 +167,8 @@ void eap_server_unregister_methods(void)
 const char * eap_server_get_name(int vendor, EapType type)
 {
        struct eap_method *m;
+       if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
+               return "expanded";
        for (m = eap_methods; m; m = m->next) {
                if (m->vendor == vendor && m->method == type)
                        return m->name;
index 39d1c6e..f5ee7f4 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "common.h"
 #include "crypto/ms_funcs.h"
+#include "crypto/random.h"
 #include "eap_i.h"
 
 
@@ -109,7 +110,7 @@ static struct wpabuf * eap_mschapv2_build_challenge(
        size_t ms_len;
 
        if (!data->auth_challenge_from_tls &&
-           os_get_random(data->auth_challenge, CHALLENGE_LEN)) {
+           random_get_bytes(data->auth_challenge, CHALLENGE_LEN)) {
                wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to get random "
                           "data");
                data->state = FAILURE;
@@ -404,9 +405,12 @@ static void eap_mschapv2_process_response(struct eap_sm *sm,
                if (sm->user->password_hash) {
                        pw_hash = sm->user->password;
                } else {
-                       nt_password_hash(sm->user->password,
-                                        sm->user->password_len,
-                                        pw_hash_buf);
+                       if (nt_password_hash(sm->user->password,
+                                            sm->user->password_len,
+                                            pw_hash_buf) < 0) {
+                               data->state = FAILURE;
+                               return;
+                       }
                        pw_hash = pw_hash_buf;
                }
                generate_authenticator_response_pwhash(
index 1dc023b..4d64269 100644 (file)
@@ -15,6 +15,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/random.h"
 #include "eap_server/eap_i.h"
 #include "eap_common/eap_pax_common.h"
 
@@ -82,7 +83,7 @@ static struct wpabuf * eap_pax_build_std_1(struct eap_sm *sm,
 
        wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-1 (sending)");
 
-       if (os_get_random(data->rand.r.x, EAP_PAX_RAND_LEN)) {
+       if (random_get_bytes(data->rand.r.x, EAP_PAX_RAND_LEN)) {
                wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data");
                data->state = FAILURE;
                return NULL;
index 674ecd2..50e79c0 100644 (file)
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "crypto/sha1.h"
 #include "crypto/tls.h"
+#include "crypto/random.h"
 #include "eap_i.h"
 #include "eap_tls_common.h"
 #include "eap_common/eap_tlv_common.h"
@@ -350,8 +351,12 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
         * in the end of the label just before ISK; is that just a typo?)
         */
        wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
-       peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",
-                    isk, sizeof(isk), imck, sizeof(imck));
+       if (peap_prfplus(data->peap_version, tk, 40,
+                        "Inner Methods Compound Keys",
+                        isk, sizeof(isk), imck, sizeof(imck)) < 0) {
+               os_free(tk);
+               return -1;
+       }
        wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
                        imck, sizeof(imck));
 
@@ -414,7 +419,7 @@ static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,
 #endif /* EAP_SERVER_TNC */
 
                if (eap_peap_derive_cmk(sm, data) < 0 ||
-                   os_get_random(data->binding_nonce, 32)) {
+                   random_get_bytes(data->binding_nonce, 32)) {
                        wpabuf_free(buf);
                        return NULL;
                }
@@ -1059,8 +1064,6 @@ static void eap_peap_process_phase2(struct eap_sm *sm,
        wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
                            in_decrypted);
 
-       hdr = wpabuf_head(in_decrypted);
-
        if (data->peap_version == 0 && data->state != PHASE2_TLV) {
                const struct eap_hdr *resp;
                struct eap_hdr *nhdr;
@@ -1319,9 +1322,10 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
                 * termination for this label while the one used for deriving
                 * IPMK|CMK did not use null termination.
                 */
-               peap_prfplus(data->peap_version, data->ipmk, 40,
-                            "Session Key Generating Function",
-                            (u8 *) "\00", 1, csk, sizeof(csk));
+               if (peap_prfplus(data->peap_version, data->ipmk, 40,
+                                "Session Key Generating Function",
+                                (u8 *) "\00", 1, csk, sizeof(csk)) < 0)
+                       return NULL;
                wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
                eapKeyData = os_malloc(EAP_TLS_KEY_LEN);
                if (eapKeyData) {
index 4c30346..fb299ae 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "common.h"
 #include "crypto/aes_wrap.h"
+#include "crypto/random.h"
 #include "eap_common/eap_psk_common.h"
 #include "eap_server/eap_i.h"
 
@@ -66,7 +67,7 @@ static struct wpabuf * eap_psk_build_1(struct eap_sm *sm,
 
        wpa_printf(MSG_DEBUG, "EAP-PSK: PSK-1 (sending)");
 
-       if (os_get_random(data->rand_s, EAP_PSK_RAND_LEN)) {
+       if (random_get_bytes(data->rand_s, EAP_PSK_RAND_LEN)) {
                wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data");
                data->state = FAILURE;
                return NULL;
@@ -124,8 +125,10 @@ static struct wpabuf * eap_psk_build_3(struct eap_sm *sm,
 
        os_memcpy(buf, data->id_s, data->id_s_len);
        os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
-       if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s))
+       if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) {
+               os_free(buf);
                goto fail;
+       }
        os_free(buf);
 
        if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, data->msk,
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
new file mode 100644 (file)
index 0000000..4c6f4d1
--- /dev/null
@@ -0,0 +1,863 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_server/eap_i.h"
+#include "eap_common/eap_pwd_common.h"
+
+
+struct eap_pwd_data {
+       enum {
+               PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req, SUCCESS, FAILURE
+       } state;
+       u8 *id_peer;
+       size_t id_peer_len;
+       u8 *id_server;
+       size_t id_server_len;
+       u8 *password;
+       size_t password_len;
+       u32 token;
+       u16 group_num;
+       EAP_PWD_group *grp;
+
+       BIGNUM *k;
+       BIGNUM *private_value;
+       BIGNUM *peer_scalar;
+       BIGNUM *my_scalar;
+       EC_POINT *my_element;
+       EC_POINT *peer_element;
+
+       u8 my_confirm[SHA256_DIGEST_LENGTH];
+
+       u8 msk[EAP_MSK_LEN];
+       u8 emsk[EAP_EMSK_LEN];
+
+       BN_CTX *bnctx;
+};
+
+
+static const char * eap_pwd_state_txt(int state)
+{
+       switch (state) {
+        case PWD_ID_Req:
+               return "PWD-ID-Req";
+        case PWD_Commit_Req:
+               return "PWD-Commit-Req";
+        case PWD_Confirm_Req:
+               return "PWD-Confirm-Req";
+        case SUCCESS:
+               return "SUCCESS";
+        case FAILURE:
+               return "FAILURE";
+        default:
+               return "PWD-Unk";
+       }
+}
+
+
+static void eap_pwd_state(struct eap_pwd_data *data, int state)
+{
+       wpa_printf(MSG_DEBUG, "EAP-pwd: %s -> %s",
+                  eap_pwd_state_txt(data->state), eap_pwd_state_txt(state));
+       data->state = state;
+}
+
+
+static void * eap_pwd_init(struct eap_sm *sm)
+{
+       struct eap_pwd_data *data;
+
+       if (sm->user == NULL || sm->user->password == NULL ||
+           sm->user->password_len == 0) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): Password is not "
+                          "configured");
+               return NULL;
+       }
+
+       data = os_zalloc(sizeof(*data));
+       if (data == NULL)
+               return NULL;
+
+       data->group_num = sm->pwd_group;
+       wpa_printf(MSG_DEBUG, "EAP-pwd: Selected group number %d",
+                  data->group_num);
+       data->state = PWD_ID_Req;
+
+       data->id_server = (u8 *) os_strdup("server");
+       if (data->id_server)
+               data->id_server_len = os_strlen((char *) data->id_server);
+
+       data->password = os_malloc(sm->user->password_len);
+       if (data->password == NULL) {
+               wpa_printf(MSG_INFO, "EAP-PWD: Memory allocation password "
+                          "fail");
+               os_free(data->id_server);
+               os_free(data);
+               return NULL;
+       }
+       data->password_len = sm->user->password_len;
+       os_memcpy(data->password, sm->user->password, data->password_len);
+
+       data->bnctx = BN_CTX_new();
+       if (data->bnctx == NULL) {
+               wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
+               os_free(data->password);
+               os_free(data->id_server);
+               os_free(data);
+               return NULL;
+       }
+
+       return data;
+}
+
+
+static void eap_pwd_reset(struct eap_sm *sm, void *priv)
+{
+       struct eap_pwd_data *data = priv;
+
+       BN_free(data->private_value);
+       BN_free(data->peer_scalar);
+       BN_free(data->my_scalar);
+       BN_free(data->k);
+       BN_CTX_free(data->bnctx);
+       EC_POINT_free(data->my_element);
+       EC_POINT_free(data->peer_element);
+       os_free(data->id_peer);
+       os_free(data->id_server);
+       os_free(data->password);
+       if (data->grp) {
+               EC_GROUP_free(data->grp->group);
+               EC_POINT_free(data->grp->pwe);
+               BN_free(data->grp->order);
+               BN_free(data->grp->prime);
+               os_free(data->grp);
+       }
+       os_free(data);
+}
+
+
+static struct wpabuf *
+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) {
+               eap_pwd_state(data, FAILURE);
+               return NULL;
+       }
+
+       /* 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;
+}
+
+
+static struct wpabuf *
+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 (((data->private_value = BN_new()) == NULL) ||
+           ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) ||
+           ((data->my_scalar = BN_new()) == NULL) ||
+           ((mask = BN_new()) == NULL)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): scalar allocation "
+                          "fail");
+               goto fin;
+       }
+
+       BN_rand_range(data->private_value, data->grp->order);
+       BN_rand_range(mask, data->grp->order);
+       BN_add(data->my_scalar, data->private_value, mask);
+       BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
+              data->bnctx);
+
+       if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
+                         data->grp->pwe, mask, data->bnctx)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): element allocation "
+                          "fail");
+               eap_pwd_state(data, FAILURE);
+               goto fin;
+       }
+
+       if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx))
+       {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): element inversion "
+                          "fail");
+               goto fin;
+       }
+       BN_free(mask);
+
+       if (((x = BN_new()) == NULL) ||
+           ((y = BN_new()) == NULL)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): point allocation "
+                          "fail");
+               goto fin;
+       }
+       if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+                                                data->my_element, x, y,
+                                                data->bnctx)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): point assignment "
+                          "fail");
+               goto fin;
+       }
+
+       if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) ||
+           ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) ==
+            NULL)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): data allocation fail");
+               goto fin;
+       }
+
+       /*
+        * bignums occupy as little memory as possible so one that is
+        * sufficiently smaller than the prime or order might need pre-pending
+        * with zeros.
+        */
+       os_memset(scalar, 0, BN_num_bytes(data->grp->order));
+       os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2);
+       offset = BN_num_bytes(data->grp->order) -
+               BN_num_bytes(data->my_scalar);
+       BN_bn2bin(data->my_scalar, scalar + offset);
+
+       offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+       BN_bn2bin(x, element + offset);
+       offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+       BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
+
+       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)
+               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));
+
+fin:
+       os_free(scalar);
+       os_free(element);
+       BN_free(x);
+       BN_free(y);
+       if (req == 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)
+{
+       struct wpabuf *req = NULL;
+       BIGNUM *x = NULL, *y = NULL;
+       HMAC_CTX ctx;
+       u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
+       u16 grp;
+       int offset;
+
+       wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request");
+
+       /* Each component of the cruft will be at most as big as the prime */
+       if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
+           ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): debug allocation "
+                          "fail");
+               goto fin;
+       }
+
+       /*
+        * commit is H(k | server_element | server_scalar | peer_element |
+        *             peer_scalar | ciphersuite)
+        */
+       H_Init(&ctx);
+
+       /*
+        * Zero the memory each time because this is mod prime math and some
+        * value may start with a few zeros and the previous one did not.
+        *
+        * First is k
+        */
+       os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+       offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
+       BN_bn2bin(data->k, cruft + offset);
+       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+
+       /* server element: x, y */
+       if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+                                                data->my_element, x, y,
+                                                data->bnctx)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
+                          "assignment fail");
+               goto fin;
+       }
+
+       os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+       offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+       BN_bn2bin(x, cruft + offset);
+       H_Update(&ctx, 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));
+
+       /* 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));
+
+       /* peer element: x, y */
+       if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+                                                data->peer_element, x, y,
+                                                data->bnctx)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
+                          "assignment fail");
+               goto fin;
+       }
+
+       os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+       offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+       BN_bn2bin(x, cruft + offset);
+       H_Update(&ctx, 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));
+
+       /* 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));
+
+       /* ciphersuite */
+       grp = htons(data->group_num);
+       os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+       ptr = cruft;
+       os_memcpy(ptr, &grp, sizeof(u16));
+       ptr += sizeof(u16);
+       *ptr = EAP_PWD_DEFAULT_RAND_FUNC;
+       ptr += sizeof(u8);
+       *ptr = EAP_PWD_DEFAULT_PRF;
+       ptr += sizeof(u8);
+       H_Update(&ctx, cruft, ptr-cruft);
+
+       /* all done with the random function */
+       H_Final(&ctx, conf);
+       os_memcpy(data->my_confirm, conf, SHA256_DIGEST_LENGTH);
+
+       req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
+                           1 + SHA256_DIGEST_LENGTH,
+                           EAP_CODE_REQUEST, id);
+       if (req == NULL)
+               goto fin;
+
+       wpabuf_put_u8(req, EAP_PWD_OPCODE_CONFIRM_EXCH);
+       wpabuf_put_data(req, conf, SHA256_DIGEST_LENGTH);
+
+fin:
+       os_free(cruft);
+       BN_free(x);
+       BN_free(y);
+       if (req == NULL)
+               eap_pwd_state(data, FAILURE);
+
+       return req;
+}
+
+
+static struct wpabuf *
+eap_pwd_build_req(struct eap_sm *sm, void *priv, u8 id)
+{
+       struct eap_pwd_data *data = priv;
+
+       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:
+               wpa_printf(MSG_INFO, "EAP-pwd: Unknown state %d in build_req",
+                          data->state);
+               break;
+       }
+
+       return NULL;
+}
+
+
+static Boolean eap_pwd_check(struct eap_sm *sm, void *priv,
+                            struct wpabuf *respData)
+{
+       struct eap_pwd_data *data = priv;
+       const u8 *pos;
+       size_t len;
+
+       pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
+       if (pos == NULL || len < 1) {
+               wpa_printf(MSG_INFO, "EAP-pwd: Invalid frame");
+               return TRUE;
+       }
+
+       wpa_printf(MSG_DEBUG, "EAP-pwd: Received frame: opcode=%d", *pos);
+
+       if (data->state == PWD_ID_Req && *pos == EAP_PWD_OPCODE_ID_EXCH)
+               return FALSE;
+
+       if (data->state == PWD_Commit_Req &&
+           *pos == EAP_PWD_OPCODE_COMMIT_EXCH)
+               return FALSE;
+
+       if (data->state == PWD_Confirm_Req &&
+           *pos == EAP_PWD_OPCODE_CONFIRM_EXCH)
+               return FALSE;
+
+       wpa_printf(MSG_INFO, "EAP-pwd: Unexpected opcode=%d in state=%d",
+                  *pos, data->state);
+
+       return TRUE;
+}
+
+
+static void eap_pwd_process_id_resp(struct eap_sm *sm,
+                                   struct eap_pwd_data *data,
+                                   const u8 *payload, size_t payload_len)
+{
+       struct eap_pwd_id *id;
+
+       if (payload_len < sizeof(struct eap_pwd_id)) {
+               wpa_printf(MSG_INFO, "EAP-pwd: Invalid ID response");
+               return;
+       }
+
+       id = (struct eap_pwd_id *) payload;
+       if ((data->group_num != be_to_host16(id->group_num)) ||
+           (id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
+           (os_memcmp(id->token, (u8 *)&data->token, sizeof(data->token))) ||
+           (id->prf != EAP_PWD_DEFAULT_PRF)) {
+               wpa_printf(MSG_INFO, "EAP-pwd: peer changed parameters");
+               eap_pwd_state(data, FAILURE);
+               return;
+       }
+       data->id_peer = os_malloc(payload_len - sizeof(struct eap_pwd_id));
+       if (data->id_peer == NULL) {
+               wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
+               return;
+       }
+       data->id_peer_len = payload_len - sizeof(struct eap_pwd_id);
+       os_memcpy(data->id_peer, id->identity, data->id_peer_len);
+       wpa_hexdump_ascii(MSG_DEBUG, "EAP-PWD (server): peer sent id of",
+                         data->id_peer, data->id_peer_len);
+
+       if ((data->grp = os_malloc(sizeof(EAP_PWD_group))) == NULL) {
+               wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
+                          "group");
+               return;
+       }
+       if (compute_password_element(data->grp, data->group_num,
+                                    data->password, data->password_len,
+                                    data->id_server, data->id_server_len,
+                                    data->id_peer, data->id_peer_len,
+                                    (u8 *) &data->token)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): unable to compute "
+                          "PWE");
+               return;
+       }
+       wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...",
+                  BN_num_bits(data->grp->prime));
+
+       eap_pwd_state(data, PWD_Commit_Req);
+}
+
+
+static void
+eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
+                           const u8 *payload, size_t payload_len)
+{
+       u8 *ptr;
+       BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
+       EC_POINT *K = NULL, *point = NULL;
+       int res = 0;
+
+       wpa_printf(MSG_DEBUG, "EAP-pwd: Received commit response");
+
+       if (((data->peer_scalar = BN_new()) == NULL) ||
+           ((data->k = BN_new()) == NULL) ||
+           ((cofactor = BN_new()) == NULL) ||
+           ((x = BN_new()) == NULL) ||
+           ((y = BN_new()) == NULL) ||
+           ((point = EC_POINT_new(data->grp->group)) == NULL) ||
+           ((K = EC_POINT_new(data->grp->group)) == NULL) ||
+           ((data->peer_element = EC_POINT_new(data->grp->group)) == NULL)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
+                          "fail");
+               goto fin;
+       }
+
+       if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): unable to get "
+                          "cofactor for curve");
+               goto fin;
+       }
+
+       /* element, x then y, followed by scalar */
+       ptr = (u8 *) payload;
+       BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x);
+       ptr += BN_num_bytes(data->grp->prime);
+       BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y);
+       ptr += BN_num_bytes(data->grp->prime);
+       BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->peer_scalar);
+       if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group,
+                                                data->peer_element, x, y,
+                                                data->bnctx)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element "
+                          "fail");
+               goto fin;
+       }
+
+       /* check to ensure peer's element is not in a small sub-group */
+       if (BN_cmp(cofactor, BN_value_one())) {
+               if (!EC_POINT_mul(data->grp->group, point, NULL,
+                                 data->peer_element, cofactor, NULL)) {
+                       wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
+                                  "multiply peer element by order");
+                       goto fin;
+               }
+               if (EC_POINT_is_at_infinity(data->grp->group, point)) {
+                       wpa_printf(MSG_INFO, "EAP-PWD (server): peer element "
+                                  "is at infinity!\n");
+                       goto fin;
+               }
+       }
+
+       /* compute the shared key, k */
+       if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe,
+                          data->peer_scalar, data->bnctx)) ||
+           (!EC_POINT_add(data->grp->group, K, K, data->peer_element,
+                          data->bnctx)) ||
+           (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value,
+                          data->bnctx))) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): computing shared key "
+                          "fail");
+               goto fin;
+       }
+
+       /* ensure that the shared key isn't in a small sub-group */
+       if (BN_cmp(cofactor, BN_value_one())) {
+               if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor,
+                                 NULL)) {
+                       wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
+                                  "multiply shared key point by order!\n");
+                       goto fin;
+               }
+       }
+
+       /*
+        * This check is strictly speaking just for the case above where
+        * co-factor > 1 but it was suggested that even though this is probably
+        * never going to happen it is a simple and safe check "just to be
+        * sure" so let's be safe.
+        */
+       if (EC_POINT_is_at_infinity(data->grp->group, K)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): shared key point is "
+                          "at infinity");
+               goto fin;
+       }
+       if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k,
+                                                NULL, data->bnctx)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): unable to extract "
+                          "shared secret from secret point");
+               goto fin;
+       }
+       res = 1;
+
+fin:
+       EC_POINT_free(K);
+       EC_POINT_free(point);
+       BN_free(cofactor);
+       BN_free(x);
+       BN_free(y);
+
+       if (res)
+               eap_pwd_state(data, PWD_Confirm_Req);
+       else
+               eap_pwd_state(data, FAILURE);
+}
+
+
+static void
+eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
+                            const u8 *payload, size_t payload_len)
+{
+       BIGNUM *x = NULL, *y = NULL;
+       HMAC_CTX ctx;
+       u32 cs;
+       u16 grp;
+       u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
+       int offset;
+
+       /* build up the ciphersuite: group | random_function | prf */
+       grp = htons(data->group_num);
+       ptr = (u8 *) &cs;
+       os_memcpy(ptr, &grp, sizeof(u16));
+       ptr += sizeof(u16);
+       *ptr = EAP_PWD_DEFAULT_RAND_FUNC;
+       ptr += sizeof(u8);
+       *ptr = EAP_PWD_DEFAULT_PRF;
+
+       /* each component of the cruft will be at most as big as the prime */
+       if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
+           ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (peer): allocation fail");
+               goto fin;
+       }
+
+       /*
+        * commit is H(k | peer_element | peer_scalar | server_element |
+        *             server_scalar | ciphersuite)
+        */
+       H_Init(&ctx);
+
+       /* 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));
+
+       /* peer element: x, y */
+       if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+                                                data->peer_element, x, y,
+                                                data->bnctx)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
+                          "assignment fail");
+               goto fin;
+       }
+       os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+       offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+       BN_bn2bin(x, cruft + offset);
+       H_Update(&ctx, 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));
+
+       /* 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));
+
+       /* server element: x, y */
+       if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+                                                data->my_element, x, y,
+                                                data->bnctx)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
+                          "assignment fail");
+               goto fin;
+       }
+
+       os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+       offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+       BN_bn2bin(x, cruft + offset);
+       H_Update(&ctx, 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));
+
+       /* 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));
+
+       /* ciphersuite */
+       os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+       H_Update(&ctx, (u8 *)&cs, sizeof(u32));
+
+       /* all done */
+       H_Final(&ctx, conf);
+
+       ptr = (u8 *) payload;
+       if (os_memcmp(conf, ptr, SHA256_DIGEST_LENGTH)) {
+               wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not "
+                          "verify");
+               goto fin;
+       }
+
+       wpa_printf(MSG_DEBUG, "EAP-pwd (server): confirm verified");
+       if (compute_keys(data->grp, data->bnctx, data->k,
+                        data->peer_scalar, data->my_scalar, conf,
+                        data->my_confirm, &cs, data->msk, data->emsk) < 0)
+               eap_pwd_state(data, FAILURE);
+       else
+               eap_pwd_state(data, SUCCESS);
+
+fin:
+       os_free(cruft);
+       BN_free(x);
+       BN_free(y);
+}
+
+
+static void eap_pwd_process(struct eap_sm *sm, void *priv,
+                           struct wpabuf *respData)
+{
+       struct eap_pwd_data *data = priv;
+       const u8 *pos;
+       size_t len;
+       u8 exch;
+
+       pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
+       if ((pos == NULL) || (len < 1)) {
+               wpa_printf(MSG_INFO, "Bad EAP header! pos %s and len = %d",
+                          (pos == NULL) ? "is NULL" : "is not NULL",
+                          (int) len);
+               return;
+       }
+
+       exch = *pos & 0x3f;
+       switch (exch) {
+       case EAP_PWD_OPCODE_ID_EXCH:
+               eap_pwd_process_id_resp(sm, data, pos + 1, len - 1);
+               break;
+       case EAP_PWD_OPCODE_COMMIT_EXCH:
+               eap_pwd_process_commit_resp(sm, data, pos + 1, len - 1);
+               break;
+        case EAP_PWD_OPCODE_CONFIRM_EXCH:
+               eap_pwd_process_confirm_resp(sm, data, pos + 1, len - 1);
+               break;
+       }
+}
+
+
+static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_pwd_data *data = priv;
+       u8 *key;
+
+       if (data->state != SUCCESS)
+               return NULL;
+
+       key = os_malloc(EAP_MSK_LEN);
+       if (key == NULL)
+               return NULL;
+
+       os_memcpy(key, data->msk, EAP_MSK_LEN);
+       *len = EAP_MSK_LEN;
+
+       return key;
+}
+
+
+static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_pwd_data *data = priv;
+       u8 *key;
+
+       if (data->state != SUCCESS)
+               return NULL;
+
+       key = os_malloc(EAP_EMSK_LEN);
+       if (key == NULL)
+               return NULL;
+
+       os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+       *len = EAP_EMSK_LEN;
+
+       return key;
+}
+
+
+static Boolean eap_pwd_is_success(struct eap_sm *sm, void *priv)
+{
+       struct eap_pwd_data *data = priv;
+       return data->state == SUCCESS;
+}
+
+
+static Boolean eap_pwd_is_done(struct eap_sm *sm, void *priv)
+{
+       struct eap_pwd_data *data = priv;
+       return (data->state == SUCCESS) || (data->state == FAILURE);
+}
+
+
+int eap_server_pwd_register(void)
+{
+       struct eap_method *eap;
+       int ret;
+       struct timeval tp;
+       struct timezone tz;
+       u32 sr;
+
+       EVP_add_digest(EVP_sha256());
+
+       sr = 0xdeaddada;
+       (void) gettimeofday(&tp, &tz);
+       sr ^= (tp.tv_sec ^ tp.tv_usec);
+       srandom(sr);
+
+       eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+                                     EAP_VENDOR_IETF, EAP_TYPE_PWD,
+                                     "PWD");
+       if (eap == NULL)
+               return -1;
+
+       eap->init = eap_pwd_init;
+       eap->reset = eap_pwd_reset;
+       eap->buildReq = eap_pwd_build_req;
+       eap->check = eap_pwd_check;
+       eap->process = eap_pwd_process;
+       eap->isDone = eap_pwd_is_done;
+       eap->getKey = eap_pwd_getkey;
+       eap->get_emsk = eap_pwd_get_emsk;
+       eap->isSuccess = eap_pwd_is_success;
+
+       ret = eap_server_method_register(eap);
+       if (ret)
+               eap_server_method_free(eap);
+       return ret;
+}
+
index ce4848f..a9b515f 100644 (file)
@@ -15,6 +15,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/random.h"
 #include "eap_server/eap_i.h"
 #include "eap_common/eap_sake_common.h"
 
@@ -166,7 +167,7 @@ static struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm,
 
        wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge");
 
-       if (os_get_random(data->rand_s, EAP_SAKE_RAND_LEN)) {
+       if (random_get_bytes(data->rand_s, EAP_SAKE_RAND_LEN)) {
                wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
                data->state = FAILURE;
                return NULL;
index 436c655..29df2ff 100644 (file)
@@ -15,6 +15,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/random.h"
 #include "eap_server/eap_i.h"
 #include "eap_common/eap_sim_common.h"
 #include "eap_server/eap_sim_db.h"
@@ -232,7 +233,7 @@ static struct wpabuf * eap_sim_build_reauth(struct eap_sm *sm,
 
        wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Re-authentication");
 
-       if (os_get_random(data->nonce_s, EAP_SIM_NONCE_S_LEN))
+       if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN))
                return NULL;
        wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: NONCE_S",
                        data->nonce_s, EAP_SIM_NONCE_S_LEN);
index 25ae683..0bb9d14 100644 (file)
@@ -45,8 +45,7 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
                return -1;
        }
 
-       /* TODO: make this configurable */
-       data->tls_out_limit = 1398;
+       data->tls_out_limit = sm->fragment_size > 0 ? sm->fragment_size : 1398;
        if (data->phase2) {
                /* Limit the fragment size in the inner TLS authentication
                 * since the outer authentication with EAP-PEAP does not yet
@@ -95,9 +94,9 @@ u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
        os_memcpy(rnd + keys.client_random_len, keys.server_random,
                  keys.server_random_len);
 
-       if (tls_prf(keys.master_key, keys.master_key_len,
-                   label, rnd, keys.client_random_len +
-                   keys.server_random_len, out, len))
+       if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
+                            label, rnd, keys.client_random_len +
+                            keys.server_random_len, out, len))
                goto fail;
 
        os_free(rnd);
index f3b70ed..a2d6f17 100644 (file)
@@ -91,7 +91,8 @@ static void * eap_tnc_init(struct eap_sm *sm)
                return NULL;
        }
 
-       data->fragment_size = 1300;
+       data->fragment_size = sm->fragment_size > 100 ?
+               sm->fragment_size - 98 : 1300;
 
        return data;
 }
index 702c50c..398d0f1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP-TTLS (RFC 5281)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * 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
 #include "eap_common/eap_ttls.h"
 
 
-/* Maximum supported TTLS version
- * 0 = RFC 5281
- * 1 = draft-funk-eap-ttls-v1-00.txt
- */
-#ifndef EAP_TTLS_VERSION
-#define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */
-#endif /* EAP_TTLS_VERSION */
-
-
-#define MSCHAPV2_KEY_LEN 16
+#define EAP_TTLS_VERSION 0
 
 
 static void eap_ttls_reset(struct eap_sm *sm, void *priv);
@@ -43,17 +34,15 @@ struct eap_ttls_data {
        struct eap_ssl_data ssl;
        enum {
                START, PHASE1, PHASE2_START, PHASE2_METHOD,
-               PHASE2_MSCHAPV2_RESP, PHASE_FINISHED, SUCCESS, FAILURE
+               PHASE2_MSCHAPV2_RESP, SUCCESS, FAILURE
        } state;
 
        int ttls_version;
-       int force_version;
        const struct eap_method *phase2_method;
        void *phase2_priv;
        int mschapv2_resp_ok;
        u8 mschapv2_auth_response[20];
        u8 mschapv2_ident;
-       int tls_ia_configured;
        struct wpabuf *pending_phase2_eap_resp;
        int tnc_started;
 };
@@ -72,8 +61,6 @@ static const char * eap_ttls_state_txt(int state)
                return "PHASE2_METHOD";
        case PHASE2_MSCHAPV2_RESP:
                return "PHASE2_MSCHAPV2_RESP";
-       case PHASE_FINISHED:
-               return "PHASE_FINISHED";
        case SUCCESS:
                return "SUCCESS";
        case FAILURE:
@@ -111,7 +98,8 @@ static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id,
        }
 
        avp->avp_code = host_to_be32(avp_code);
-       avp->avp_length = host_to_be32((flags << 24) | (hdrlen + len));
+       avp->avp_length = host_to_be32(((u32) flags << 24) |
+                                      ((u32) (hdrlen + len)));
 
        return avphdr + hdrlen;
 }
@@ -320,54 +308,8 @@ fail:
 static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
                                        struct eap_ttls_data *data, size_t len)
 {
-       struct tls_keys keys;
-       u8 *challenge, *rnd;
-
-       if (data->ttls_version == 0) {
-               return eap_server_tls_derive_key(sm, &data->ssl,
-                                                "ttls challenge", len);
-       }
-
-       os_memset(&keys, 0, sizeof(keys));
-       if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
-           keys.client_random == NULL || keys.server_random == NULL ||
-           keys.inner_secret == NULL) {
-               wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
-                          "client random, or server random to derive "
-                          "implicit challenge");
-               return NULL;
-       }
-
-       rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-       challenge = os_malloc(len);
-       if (rnd == NULL || challenge == NULL) {
-               wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit "
-                          "challenge derivation");
-               os_free(rnd);
-               os_free(challenge);
-               return NULL;
-       }
-       os_memcpy(rnd, keys.server_random, keys.server_random_len);
-       os_memcpy(rnd + keys.server_random_len, keys.client_random,
-                 keys.client_random_len);
-
-       if (tls_prf(keys.inner_secret, keys.inner_secret_len,
-                   "inner application challenge", rnd,
-                   keys.client_random_len + keys.server_random_len,
-                   challenge, len)) {
-               wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit "
-                          "challenge");
-               os_free(rnd);
-               os_free(challenge);
-               return NULL;
-       }
-
-       os_free(rnd);
-
-       wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge",
-                       challenge, len);
-
-       return challenge;
+       return eap_server_tls_derive_key(sm, &data->ssl, "ttls challenge",
+                                        len);
 }
 
 
@@ -379,27 +321,8 @@ static void * eap_ttls_init(struct eap_sm *sm)
        if (data == NULL)
                return NULL;
        data->ttls_version = EAP_TTLS_VERSION;
-       data->force_version = -1;
-       if (sm->user && sm->user->force_version >= 0) {
-               data->force_version = sm->user->force_version;
-               wpa_printf(MSG_DEBUG, "EAP-TTLS: forcing version %d",
-                          data->force_version);
-               data->ttls_version = data->force_version;
-       }
        data->state = START;
 
-       if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) &&
-           data->ttls_version > 0) {
-               if (data->force_version > 0) {
-                       wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and "
-                                  "TLS library does not support TLS/IA.",
-                                  data->force_version);
-                       eap_ttls_reset(sm, data);
-                       return NULL;
-               }
-               data->ttls_version = 0;
-       }
-
        if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
                wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
                eap_ttls_reset(sm, data);
@@ -516,14 +439,6 @@ static struct wpabuf * eap_ttls_build_phase2_mschapv2(
 }
 
 
-static struct wpabuf * eap_ttls_build_phase_finished(
-       struct eap_sm *sm, struct eap_ttls_data *data, int final)
-{
-       return tls_connection_ia_send_phase_finished(sm->ssl_ctx,
-                                                    data->ssl.conn, final);
-}
-
-
 static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id)
 {
        struct eap_ttls_data *data = priv;
@@ -559,11 +474,6 @@ static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id)
                data->ssl.tls_out_pos = 0;
                data->ssl.tls_out = eap_ttls_build_phase2_mschapv2(sm, data);
                break;
-       case PHASE_FINISHED:
-               wpabuf_free(data->ssl.tls_out);
-               data->ssl.tls_out_pos = 0;
-               data->ssl.tls_out = eap_ttls_build_phase_finished(sm, data, 1);
-               break;
        default:
                wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d",
                           __func__, data->state);
@@ -591,37 +501,6 @@ static Boolean eap_ttls_check(struct eap_sm *sm, void *priv,
 }
 
 
-static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm,
-                                           struct eap_ttls_data *data,
-                                           const u8 *key, size_t key_len)
-{
-       u8 *buf;
-       size_t buf_len;
-       int ret;
-
-       if (key) {
-               buf_len = 2 + key_len;
-               buf = os_malloc(buf_len);
-               if (buf == NULL)
-                       return -1;
-               WPA_PUT_BE16(buf, key_len);
-               os_memcpy(buf + 2, key, key_len);
-       } else {
-               buf = NULL;
-               buf_len = 0;
-       }
-
-       wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner "
-                       "secret permutation", buf, buf_len);
-       ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx,
-                                                    data->ssl.conn,
-                                                    buf, buf_len);
-       os_free(buf);
-
-       return ret;
-}
-
-
 static void eap_ttls_process_phase2_pap(struct eap_sm *sm,
                                        struct eap_ttls_data *data,
                                        const u8 *user_password,
@@ -644,8 +523,7 @@ static void eap_ttls_process_phase2_pap(struct eap_sm *sm,
        }
 
        wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Correct user password");
-       eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED :
-                      SUCCESS);
+       eap_ttls_state(data, SUCCESS);
 }
 
 
@@ -701,8 +579,7 @@ static void eap_ttls_process_phase2_chap(struct eap_sm *sm,
 
        if (os_memcmp(hash, password + 1, EAP_TTLS_CHAP_PASSWORD_LEN) == 0) {
                wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Correct user password");
-               eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED :
-                              SUCCESS);
+               eap_ttls_state(data, SUCCESS);
        } else {
                wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid user password");
                eap_ttls_state(data, FAILURE);
@@ -762,8 +639,7 @@ static void eap_ttls_process_phase2_mschap(struct eap_sm *sm,
 
        if (os_memcmp(nt_response, response + 2 + 24, 24) == 0) {
                wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Correct response");
-               eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED :
-                              SUCCESS);
+               eap_ttls_state(data, SUCCESS);
        } else {
                wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid NT-Response");
                wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Received",
@@ -863,30 +739,6 @@ static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
                wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Correct "
                           "NT-Response");
                data->mschapv2_resp_ok = 1;
-               if (data->ttls_version > 0) {
-                       const u8 *pw_hash;
-                       u8 pw_hash_buf[16], pw_hash_hash[16], master_key[16];
-                       u8 session_key[2 * MSCHAPV2_KEY_LEN];
-
-                       if (sm->user->password_hash)
-                               pw_hash = sm->user->password;
-                       else {
-                               nt_password_hash(sm->user->password,
-                                                sm->user->password_len,
-                                                pw_hash_buf);
-                               pw_hash = pw_hash_buf;
-                       }
-                       hash_nt_password_hash(pw_hash, pw_hash_hash);
-                       get_master_key(pw_hash_hash, nt_response, master_key);
-                       get_asymetric_start_key(master_key, session_key,
-                                               MSCHAPV2_KEY_LEN, 0, 0);
-                       get_asymetric_start_key(master_key,
-                                               session_key + MSCHAPV2_KEY_LEN,
-                                               MSCHAPV2_KEY_LEN, 1, 0);
-                       eap_ttls_ia_permute_inner_secret(sm, data,
-                                                        session_key,
-                                                        sizeof(session_key));
-               }
 
                if (sm->user->password_hash) {
                        generate_authenticator_response_pwhash(
@@ -1030,17 +882,7 @@ static void eap_ttls_process_phase2_eap_response(struct eap_sm *sm,
                }
                break;
        case PHASE2_METHOD:
-               if (data->ttls_version > 0) {
-                       if (m->getKey) {
-                               u8 *key;
-                               size_t key_len;
-                               key = m->getKey(sm, priv, &key_len);
-                               eap_ttls_ia_permute_inner_secret(sm, data,
-                                                                key, key_len);
-                       }
-                       eap_ttls_state(data, PHASE_FINISHED);
-               } else
-                       eap_ttls_state(data, SUCCESS);
+               eap_ttls_state(data, SUCCESS);
                break;
        case FAILURE:
                break;
@@ -1130,23 +972,6 @@ static void eap_ttls_process_phase2(struct eap_sm *sm,
                return;
        }
 
-       if (data->state == PHASE_FINISHED) {
-               if (wpabuf_len(in_decrypted) == 0 &&
-                   tls_connection_ia_final_phase_finished(sm->ssl_ctx,
-                                                          data->ssl.conn)) {
-                       wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished "
-                                  "received");
-                       eap_ttls_state(data, SUCCESS);
-               } else {
-                       wpa_printf(MSG_INFO, "EAP-TTLS: Did not receive valid "
-                                  "FinalPhaseFinished");
-                       eap_ttls_state(data, FAILURE);
-               }
-
-               wpabuf_free(in_decrypted);
-               return;
-       }
-
        wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 EAP",
                            in_decrypted);
 
@@ -1245,15 +1070,6 @@ static int eap_ttls_process_version(struct eap_sm *sm, void *priv,
                data->ttls_version = peer_version;
        }
 
-       if (data->ttls_version > 0 && !data->tls_ia_configured) {
-               if (tls_connection_set_ia(sm->ssl_ctx, data->ssl.conn, 1)) {
-                       wpa_printf(MSG_INFO, "EAP-TTLS: Failed to enable "
-                                  "TLS/IA");
-                       return -1;
-               }
-               data->tls_ia_configured = 1;
-       }
-
        return 0;
 }
 
@@ -1270,7 +1086,6 @@ static void eap_ttls_process_msg(struct eap_sm *sm, void *priv,
                break;
        case PHASE2_START:
        case PHASE2_METHOD:
-       case PHASE_FINISHED:
                eap_ttls_process_phase2(sm, data, data->ssl.tls_in);
                eap_ttls_start_tnc(sm, data);
                break;
@@ -1279,8 +1094,7 @@ static void eap_ttls_process_msg(struct eap_sm *sm, void *priv,
                    0) {
                        wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
                                   "acknowledged response");
-                       eap_ttls_state(data, data->ttls_version > 0 ?
-                                      PHASE_FINISHED : SUCCESS);
+                       eap_ttls_state(data, SUCCESS);
                } else if (!data->mschapv2_resp_ok) {
                        wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
                                   "acknowledged error");
@@ -1321,54 +1135,6 @@ static Boolean eap_ttls_isDone(struct eap_sm *sm, void *priv)
 }
 
 
-static u8 * eap_ttls_v1_derive_key(struct eap_sm *sm,
-                                  struct eap_ttls_data *data)
-{
-       struct tls_keys keys;
-       u8 *rnd, *key;
-
-       os_memset(&keys, 0, sizeof(keys));
-       if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
-           keys.client_random == NULL || keys.server_random == NULL ||
-           keys.inner_secret == NULL) {
-               wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
-                          "client random, or server random to derive keying "
-                          "material");
-               return NULL;
-       }
-
-       rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-       key = os_malloc(EAP_TLS_KEY_LEN);
-       if (rnd == NULL || key == NULL) {
-               wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation");
-               os_free(rnd);
-               os_free(key);
-               return NULL;
-       }
-       os_memcpy(rnd, keys.client_random, keys.client_random_len);
-       os_memcpy(rnd + keys.client_random_len, keys.server_random,
-                 keys.server_random_len);
-
-       if (tls_prf(keys.inner_secret, keys.inner_secret_len,
-                   "ttls v1 keying material", rnd, keys.client_random_len +
-                   keys.server_random_len, key, EAP_TLS_KEY_LEN)) {
-               wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key");
-               os_free(rnd);
-               os_free(key);
-               return NULL;
-       }
-
-       wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random",
-                   rnd, keys.client_random_len + keys.server_random_len);
-       wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret",
-                       keys.inner_secret, keys.inner_secret_len);
-
-       os_free(rnd);
-
-       return key;
-}
-
-
 static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
 {
        struct eap_ttls_data *data = priv;
@@ -1377,14 +1143,9 @@ static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
        if (data->state != SUCCESS)
                return NULL;
 
-       if (data->ttls_version == 0) {
-               eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
-                                                      "ttls keying material",
-                                                      EAP_TLS_KEY_LEN);
-       } else {
-               eapKeyData = eap_ttls_v1_derive_key(sm, data);
-       }
-
+       eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
+                                              "ttls keying material",
+                                              EAP_TLS_KEY_LEN);
        if (eapKeyData) {
                *len = EAP_TLS_KEY_LEN;
                wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
index 77cf9e2..556882d 100644 (file)
@@ -18,6 +18,7 @@
 #include "eloop.h"
 #include "eap_i.h"
 #include "eap_common/eap_wsc_common.h"
+#include "p2p/p2p.h"
 #include "wps/wps.h"
 
 
@@ -135,14 +136,22 @@ static void * eap_wsc_init(struct eap_sm *sm)
        }
        cfg.assoc_wps_ie = sm->assoc_wps_ie;
        cfg.peer_addr = sm->peer_addr;
-       if (0 /* TODO: could provide option for forcing PSK format */)
-                cfg.use_psk_key = 1;
+#ifdef CONFIG_P2P
+       if (sm->assoc_p2p_ie) {
+               wpa_printf(MSG_DEBUG, "EAP-WSC: Prefer PSK format for P2P "
+                          "client");
+               cfg.use_psk_key = 1;
+               cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie);
+       }
+#endif /* CONFIG_P2P */
+       cfg.pbc_in_m1 = sm->pbc_in_m1;
        data->wps = wps_init(&cfg);
        if (data->wps == NULL) {
                os_free(data);
                return NULL;
        }
-       data->fragment_size = WSC_FRAGMENT_SIZE;
+       data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size :
+               WSC_FRAGMENT_SIZE;
 
        return data;
 }
index aba919a..248b216 100644 (file)
@@ -25,6 +25,7 @@
 #include <sys/un.h>
 
 #include "common.h"
+#include "crypto/random.h"
 #include "eap_common/eap_sim_common.h"
 #include "eap_server/eap_sim_db.h"
 #include "eloop.h"
@@ -830,7 +831,7 @@ static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
        char *id, *pos, *end;
        u8 buf[10];
 
-       if (os_get_random(buf, sizeof(buf)))
+       if (random_get_bytes(buf, sizeof(buf)))
                return NULL;
        id = os_malloc(sizeof(buf) * 2 + 2);
        if (id == NULL)
index 435ba26..f5bbb14 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "common.h"
 #include "crypto/dh_groups.h"
+#include "crypto/random.h"
 #include "ikev2.h"
 
 
@@ -403,7 +404,7 @@ static int ikev2_process_ker(struct ikev2_initiator_data *data,
        }
 
        /* RFC 4306, Section 3.4:
-        * The length of DH public value MUST be equal to the lenght of the
+        * The length of DH public value MUST be equal to the length of the
         * prime modulus.
         */
        if (ker_len - 4 != data->dh->prime_len) {
@@ -1100,7 +1101,7 @@ static struct wpabuf * ikev2_build_sa_init(struct ikev2_initiator_data *data)
                    data->i_spi, IKEV2_SPI_LEN);
 
        data->i_nonce_len = IKEV2_NONCE_MIN_LEN;
-       if (os_get_random(data->i_nonce, data->i_nonce_len))
+       if (random_get_bytes(data->i_nonce, data->i_nonce_len))
                return NULL;
        wpa_hexdump(MSG_DEBUG, "IKEV2: Ni", data->i_nonce, data->i_nonce_len);
 
@@ -1148,7 +1149,7 @@ static struct wpabuf * ikev2_build_sa_auth(struct ikev2_initiator_data *data)
                if (data->shared_secret == NULL)
                        return NULL;
                data->shared_secret_len = 16;
-               if (os_get_random(data->shared_secret, 16))
+               if (random_get_bytes(data->shared_secret, 16))
                        return NULL;
        } else {
                os_free(data->shared_secret);
index 497b51a..637b6f8 100644 (file)
@@ -234,11 +234,11 @@ TNC_Result TNC_TNCS_ReportMessageTypes(
                return TNC_RESULT_INVALID_PARAMETER;
        os_free(imv->supported_types);
        imv->supported_types =
-               os_malloc(typeCount * sizeof(TNC_MessageTypeList));
+               os_malloc(typeCount * sizeof(TNC_MessageType));
        if (imv->supported_types == NULL)
                return TNC_RESULT_FATAL;
        os_memcpy(imv->supported_types, supportedTypes,
-                 typeCount * sizeof(TNC_MessageTypeList));
+                 typeCount * sizeof(TNC_MessageType));
        imv->num_supported_types = typeCount;
 
        return TNC_RESULT_SUCCESS;
index a1976e8..e600954 100644 (file)
@@ -762,7 +762,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, void *sta_ctx)
+                int flags, const struct wpabuf *assoc_wps_ie,
+                const struct wpabuf *assoc_p2p_ie, void *sta_ctx)
 {
        struct eapol_state_machine *sm;
        struct eap_config eap_conf;
@@ -829,7 +830,11 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
        eap_conf.tnc = eapol->conf.tnc;
        eap_conf.wps = eapol->conf.wps;
        eap_conf.assoc_wps_ie = assoc_wps_ie;
+       eap_conf.assoc_p2p_ie = assoc_p2p_ie;
        eap_conf.peer_addr = addr;
+       eap_conf.fragment_size = eapol->conf.fragment_size;
+       eap_conf.pwd_group = eapol->conf.pwd_group;
+       eap_conf.pbc_in_m1 = eapol->conf.pbc_in_m1;
        sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
        if (sm->eap == NULL) {
                eapol_auth_free(sm);
@@ -1012,7 +1017,7 @@ static struct eapol_callbacks eapol_cb =
 
 int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx)
 {
-       if (sm == NULL || ctx != sm->eap)
+       if (sm == NULL || ctx == NULL || ctx != sm->eap)
                return -1;
 
        eap_sm_pending_cb(sm->eap);
@@ -1034,6 +1039,8 @@ static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
        dst->msg_ctx = src->msg_ctx;
        dst->eap_sim_db_priv = src->eap_sim_db_priv;
        os_free(dst->eap_req_id_text);
+       dst->pwd_group = src->pwd_group;
+       dst->pbc_in_m1 = src->pbc_in_m1;
        if (src->eap_req_id_text) {
                dst->eap_req_id_text = os_malloc(src->eap_req_id_text_len);
                if (dst->eap_req_id_text == NULL)
@@ -1077,6 +1084,7 @@ static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
        dst->eap_sim_aka_result_ind = src->eap_sim_aka_result_ind;
        dst->tnc = src->tnc;
        dst->wps = src->wps;
+       dst->fragment_size = src->fragment_size;
        return 0;
 }
 
index ef943ad..724bf8b 100644 (file)
@@ -40,6 +40,9 @@ struct eapol_auth_config {
        int eap_sim_aka_result_ind;
        int tnc;
        struct wps_context *wps;
+       int fragment_size;
+       u16 pwd_group;
+       int pbc_in_m1;
 
        /* Opaque context pointer to owner data for callback functions */
        void *ctx;
@@ -79,7 +82,8 @@ struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
 void eapol_auth_deinit(struct eapol_authenticator *eapol);
 struct eapol_state_machine *
 eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
-                int flags, const struct wpabuf *assoc_wps_ie, void *sta_ctx);
+                int flags, const struct wpabuf *assoc_wps_ie,
+                const struct wpabuf *assoc_p2p_ie, void *sta_ctx);
 void eapol_auth_free(struct eapol_state_machine *sm);
 void eapol_auth_step(struct eapol_state_machine *sm);
 void eapol_auth_dump_state(FILE *f, const char *prefix,
index 77cd564..ffc6619 100644 (file)
@@ -561,7 +561,7 @@ SM_STEP(SUPP_BE)
                 * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
                 * and SUCCESS based on eapFail and eapSuccess, respectively.
                 * However, IEEE Std 802.1X-2004 is also specifying that
-                * eapNoResp should be set in conjuction with eapSuccess and
+                * eapNoResp should be set in conjunction with eapSuccess and
                 * eapFail which would mean that more than one of the
                 * transitions here would be activated at the same time.
                 * Skipping RESPONSE and/or RECEIVE states in these cases can
@@ -1029,6 +1029,21 @@ void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
 }
 
 
+/**
+ * eapol_sm_get_method_name - Get EAPOL method name
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * Returns: Static string containing name of current eap method or NULL
+ */
+const char * eapol_sm_get_method_name(struct eapol_sm *sm)
+{
+       if (sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED ||
+           sm->suppPortStatus != Authorized)
+               return NULL;
+
+       return eap_sm_get_method_name(sm->eap);
+}
+
+
 #ifdef CONFIG_CTRL_IFACE
 /**
  * eapol_sm_get_status - Get EAPOL state machine status
@@ -1798,7 +1813,7 @@ static void eapol_sm_notify_pending(void *ctx)
 
 
 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
-static void eapol_sm_eap_param_needed(void *ctx, const char *field,
+static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
                                      const char *txt)
 {
        struct eapol_sm *sm = ctx;
@@ -1810,6 +1825,15 @@ static void eapol_sm_eap_param_needed(void *ctx, const char *field,
 #define eapol_sm_eap_param_needed NULL
 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
 
+static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject,
+                                const char *cert_hash,
+                                const struct wpabuf *cert)
+{
+       struct eapol_sm *sm = ctx;
+       if (sm->ctx->cert_cb)
+               sm->ctx->cert_cb(sm->ctx->ctx, depth, subject,
+                                cert_hash, cert);
+}
 
 static struct eapol_callbacks eapol_cb =
 {
@@ -1822,7 +1846,8 @@ static struct eapol_callbacks eapol_cb =
        eapol_sm_set_config_blob,
        eapol_sm_get_config_blob,
        eapol_sm_notify_pending,
-       eapol_sm_eap_param_needed
+       eapol_sm_eap_param_needed,
+       eapol_sm_notify_cert
 };
 
 
@@ -1858,6 +1883,7 @@ struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
        conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
        conf.pkcs11_module_path = ctx->pkcs11_module_path;
        conf.wps = ctx->wps;
+       conf.cert_in_cb = ctx->cert_in_cb;
 
        sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
        if (sm->eap == NULL) {
index 1d2a32b..bcb00b5 100644 (file)
@@ -208,10 +208,10 @@ struct eapol_ctx {
        /**
         * eap_param_needed - Notify that EAP parameter is needed
         * @ctx: Callback context (ctx)
-        * @field: Field name (e.g., "IDENTITY")
+        * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY)
         * @txt: User readable text describing the required parameter
         */
-       void (*eap_param_needed)(void *ctx, const char *field,
+       void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field,
                                 const char *txt);
 
        /**
@@ -220,6 +220,22 @@ struct eapol_ctx {
         * @authorized: Whether the supplicant port is now in authorized state
         */
        void (*port_cb)(void *ctx, int authorized);
+
+       /**
+        * cert_cb - Notification of a peer certificate
+        * @ctx: Callback context (ctx)
+        * @depth: Depth in certificate chain (0 = server)
+        * @subject: Subject of the peer certificate
+        * @cert_hash: SHA-256 hash of the certificate
+        * @cert: Peer certificate
+        */
+       void (*cert_cb)(void *ctx, int depth, const char *subject,
+                       const char *cert_hash, const struct wpabuf *cert);
+
+       /**
+        * cert_in_cb - Include server certificates in callback
+        */
+       int cert_in_cb;
 };
 
 
@@ -255,6 +271,7 @@ void eapol_sm_notify_ctrl_response(struct eapol_sm *sm);
 void eapol_sm_request_reauth(struct eapol_sm *sm);
 void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm);
 void eapol_sm_invalidate_cached_session(struct eapol_sm *sm);
+const char * eapol_sm_get_method_name(struct eapol_sm *sm);
 #else /* IEEE8021X_EAPOL */
 static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
 {
@@ -342,6 +359,10 @@ static inline void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm,
 static inline void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
 {
 }
+static inline const char * eapol_sm_get_method_name(struct eapol_sm *sm)
+{
+       return NULL;
+}
 #endif /* IEEE8021X_EAPOL */
 
 #endif /* EAPOL_SUPP_SM_H */
index 009e02c..e24277c 100644 (file)
 #include <pcap.h>
 
 #include <sys/ioctl.h>
+#ifdef __sun__
+#include <libdlpi.h>
+#else /* __sun__ */
 #include <sys/sysctl.h>
+#endif /* __sun__ */
 
 #include <net/if.h>
 #include <net/if_dl.h>
@@ -139,6 +143,7 @@ static int l2_packet_init_libpcap(struct l2_packet_data *l2,
        }
 
        pcap_freecode(&pcap_fp);
+#ifndef __sun__
        /*
         * When libpcap uses BPF we must enable "immediate mode" to
         * receive frames right away; otherwise the system may
@@ -153,6 +158,7 @@ static int l2_packet_init_libpcap(struct l2_packet_data *l2,
                        /* XXX should we fail? */
                }
        }
+#endif /* __sun__ */
 
        eloop_register_read_sock(pcap_get_selectable_fd(l2->pcap),
                                 l2_packet_receive, l2, l2->pcap);
@@ -163,6 +169,30 @@ static int l2_packet_init_libpcap(struct l2_packet_data *l2,
 
 static int eth_get(const char *device, u8 ea[ETH_ALEN])
 {
+#ifdef __sun__
+       dlpi_handle_t dh;
+       u32 physaddrlen = DLPI_PHYSADDR_MAX;
+       u8 physaddr[DLPI_PHYSADDR_MAX];
+       int retval;
+
+       retval = dlpi_open(device, &dh, 0);
+       if (retval != DLPI_SUCCESS) {
+               wpa_printf(MSG_ERROR, "dlpi_open error: %s",
+                          dlpi_strerror(retval));
+               return -1;
+       }
+
+       retval = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, physaddr,
+                                  &physaddrlen);
+       if (retval != DLPI_SUCCESS) {
+               wpa_printf(MSG_ERROR, "dlpi_get_physaddr error: %s",
+                          dlpi_strerror(retval));
+               dlpi_close(dh);
+               return -1;
+       }
+       os_memcpy(ea, physaddr, ETH_ALEN);
+       dlpi_close(dh);
+#else /* __sun__ */
        struct if_msghdr *ifm;
        struct sockaddr_dl *sdl;
        u_char *p, *buf;
@@ -195,6 +225,7 @@ static int eth_get(const char *device, u8 ea[ETH_ALEN])
                errno = ESRCH;
                return -1;
        }
+#endif /* __sun__ */
        return 0;
 }
 
index 48d1bde..93e15eb 100644 (file)
@@ -51,7 +51,8 @@ int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
        if (l2->l2_hdr) {
                ret = send(l2->fd, buf, len, 0);
                if (ret < 0)
-                       perror("l2_packet_send - send");
+                       wpa_printf(MSG_ERROR, "l2_packet_send - send: %s",
+                                  strerror(errno));
        } else {
                struct sockaddr_ll ll;
                os_memset(&ll, 0, sizeof(ll));
@@ -62,8 +63,10 @@ int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
                os_memcpy(ll.sll_addr, dst_addr, ETH_ALEN);
                ret = sendto(l2->fd, buf, len, 0, (struct sockaddr *) &ll,
                             sizeof(ll));
-               if (ret < 0)
-                       perror("l2_packet_send - sendto");
+               if (ret < 0) {
+                       wpa_printf(MSG_ERROR, "l2_packet_send - sendto: %s",
+                                  strerror(errno));
+               }
        }
        return ret;
 }
@@ -82,7 +85,8 @@ static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
        res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll,
                       &fromlen);
        if (res < 0) {
-               perror("l2_packet_receive - recvfrom");
+               wpa_printf(MSG_DEBUG, "l2_packet_receive - recvfrom: %s",
+                          strerror(errno));
                return;
        }
 
@@ -111,14 +115,16 @@ struct l2_packet_data * l2_packet_init(
        l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM,
                        htons(protocol));
        if (l2->fd < 0) {
-               perror("socket(PF_PACKET)");
+               wpa_printf(MSG_ERROR, "%s: socket(PF_PACKET): %s",
+                          __func__, strerror(errno));
                os_free(l2);
                return NULL;
        }
        os_memset(&ifr, 0, sizeof(ifr));
        os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name));
        if (ioctl(l2->fd, SIOCGIFINDEX, &ifr) < 0) {
-               perror("ioctl[SIOCGIFINDEX]");
+               wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFINDEX]: %s",
+                          __func__, strerror(errno));
                close(l2->fd);
                os_free(l2);
                return NULL;
@@ -130,14 +136,16 @@ struct l2_packet_data * l2_packet_init(
        ll.sll_ifindex = ifr.ifr_ifindex;
        ll.sll_protocol = htons(protocol);
        if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
-               perror("bind[PF_PACKET]");
+               wpa_printf(MSG_ERROR, "%s: bind[PF_PACKET]: %s",
+                          __func__, strerror(errno));
                close(l2->fd);
                os_free(l2);
                return NULL;
        }
 
        if (ioctl(l2->fd, SIOCGIFHWADDR, &ifr) < 0) {
-               perror("ioctl[SIOCGIFHWADDR]");
+               wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFHWADDR]: %s",
+                          __func__, strerror(errno));
                close(l2->fd);
                os_free(l2);
                return NULL;
@@ -173,14 +181,16 @@ int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
 
        s = socket(PF_INET, SOCK_DGRAM, 0);
        if (s < 0) {
-               perror("socket");
+               wpa_printf(MSG_ERROR, "%s: socket: %s",
+                          __func__, strerror(errno));
                return -1;
        }
        os_memset(&ifr, 0, sizeof(ifr));
        os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name));
        if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
                if (errno != EADDRNOTAVAIL)
-                       perror("ioctl[SIOCGIFADDR]");
+                       wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFADDR]: %s",
+                                  __func__, strerror(errno));
                close(s);
                return -1;
        }
diff --git a/src/p2p/Makefile b/src/p2p/Makefile
new file mode 100644 (file)
index 0000000..cffba62
--- /dev/null
@@ -0,0 +1,9 @@
+all:
+       @echo Nothing to be made.
+
+clean:
+       for d in $(SUBDIRS); do make -C $$d clean; done
+       rm -f *~ *.o *.d
+
+install:
+       @echo Nothing to be made.
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
new file mode 100644 (file)
index 0000000..c0009ce
--- /dev/null
@@ -0,0 +1,3780 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "wps/wps_i.h"
+#include "p2p_i.h"
+#include "p2p.h"
+
+
+static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx);
+static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev);
+static void p2p_process_presence_req(struct p2p_data *p2p, const u8 *da,
+                                    const u8 *sa, const u8 *data, size_t len,
+                                    int rx_freq);
+static void p2p_process_presence_resp(struct p2p_data *p2p, const u8 *da,
+                                     const u8 *sa, const u8 *data,
+                                     size_t len);
+static void p2p_ext_listen_timeout(void *eloop_ctx, void *timeout_ctx);
+static void p2p_scan_timeout(void *eloop_ctx, void *timeout_ctx);
+
+
+/*
+ * p2p_scan recovery timeout
+ *
+ * Many drivers are using 30 second timeout on scan results. Allow a bit larger
+ * timeout for this to avoid hitting P2P timeout unnecessarily.
+ */
+#define P2P_SCAN_TIMEOUT 35
+
+/**
+ * P2P_PEER_EXPIRATION_AGE - Number of seconds after which inactive peer
+ * entries will be removed
+ */
+#define P2P_PEER_EXPIRATION_AGE 300
+
+#define P2P_PEER_EXPIRATION_INTERVAL (P2P_PEER_EXPIRATION_AGE / 2)
+
+static void p2p_expire_peers(struct p2p_data *p2p)
+{
+       struct p2p_device *dev, *n;
+       struct os_time now;
+
+       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));
+               dl_list_del(&dev->list);
+               p2p_device_free(p2p, dev);
+       }
+}
+
+
+static void p2p_expiration_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct p2p_data *p2p = eloop_ctx;
+       p2p_expire_peers(p2p);
+       eloop_register_timeout(P2P_PEER_EXPIRATION_INTERVAL, 0,
+                              p2p_expiration_timeout, p2p, NULL);
+}
+
+
+static const char * p2p_state_txt(int state)
+{
+       switch (state) {
+       case P2P_IDLE:
+               return "IDLE";
+       case P2P_SEARCH:
+               return "SEARCH";
+       case P2P_CONNECT:
+               return "CONNECT";
+       case P2P_CONNECT_LISTEN:
+               return "CONNECT_LISTEN";
+       case P2P_GO_NEG:
+               return "GO_NEG";
+       case P2P_LISTEN_ONLY:
+               return "LISTEN_ONLY";
+       case P2P_WAIT_PEER_CONNECT:
+               return "WAIT_PEER_CONNECT";
+       case P2P_WAIT_PEER_IDLE:
+               return "WAIT_PEER_IDLE";
+       case P2P_SD_DURING_FIND:
+               return "SD_DURING_FIND";
+       case P2P_PROVISIONING:
+               return "PROVISIONING";
+       case P2P_PD_DURING_FIND:
+               return "PD_DURING_FIND";
+       case P2P_INVITE:
+               return "INVITE";
+       case P2P_INVITE_LISTEN:
+               return "INVITE_LISTEN";
+       case P2P_SEARCH_WHEN_READY:
+               return "SEARCH_WHEN_READY";
+       default:
+               return "?";
+       }
+}
+
+
+u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr)
+{
+       struct p2p_device *dev = NULL;
+
+       if (!addr || !p2p)
+               return 0;
+
+       dev = p2p_get_device(p2p, addr);
+       if (dev)
+               return dev->wps_prov_info;
+       else
+               return 0;
+}
+
+
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr)
+{
+       struct p2p_device *dev = NULL;
+
+       if (!iface_addr || !p2p)
+               return;
+
+       dev = p2p_get_device_interface(p2p, iface_addr);
+       if (dev)
+               dev->wps_prov_info = 0;
+}
+
+
+void p2p_set_state(struct p2p_data *p2p, int new_state)
+{
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: State %s -> %s",
+               p2p_state_txt(p2p->state), p2p_state_txt(new_state));
+       p2p->state = 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_state_txt(p2p->state), sec, usec);
+       eloop_cancel_timeout(p2p_state_timeout, p2p, NULL);
+       eloop_register_timeout(sec, usec, p2p_state_timeout, p2p, NULL);
+}
+
+
+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));
+       eloop_cancel_timeout(p2p_state_timeout, p2p, NULL);
+}
+
+
+void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer,
+                      int status)
+{
+       struct p2p_go_neg_results res;
+       p2p_clear_timeout(p2p);
+       p2p_set_state(p2p, P2P_IDLE);
+       if (p2p->go_neg_peer)
+               p2p->go_neg_peer->wps_method = WPS_NOT_READY;
+       p2p->go_neg_peer = NULL;
+
+       os_memset(&res, 0, sizeof(res));
+       res.status = status;
+       if (peer) {
+               os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr,
+                         ETH_ALEN);
+               os_memcpy(res.peer_interface_addr, peer->intended_addr,
+                         ETH_ALEN);
+       }
+       p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
+}
+
+
+static void p2p_listen_in_find(struct p2p_data *p2p)
+{
+       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_state_txt(p2p->state));
+
+       freq = p2p_channel_to_freq(p2p->cfg->country, p2p->cfg->reg_class,
+                                  p2p->cfg->channel);
+       if (freq < 0) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "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;
+
+       p2p->pending_listen_freq = freq;
+       p2p->pending_listen_sec = 0;
+       p2p->pending_listen_usec = 1024 * tu;
+
+       ies = p2p_build_probe_resp_ies(p2p);
+       if (ies == NULL)
+               return;
+
+       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->pending_listen_freq = 0;
+       }
+       wpabuf_free(ies);
+}
+
+
+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");
+
+       freq = p2p_channel_to_freq(p2p->cfg->country, p2p->cfg->reg_class,
+                                  p2p->cfg->channel);
+       if (freq < 0) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Unknown regulatory class/channel");
+               return -1;
+       }
+
+       p2p->pending_listen_freq = freq;
+       p2p->pending_listen_sec = timeout / 1000;
+       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");
+               p2p->start_after_scan = P2P_AFTER_SCAN_LISTEN;
+               return 0;
+       }
+
+       ies = p2p_build_probe_resp_ies(p2p);
+       if (ies == NULL)
+               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->pending_listen_freq = 0;
+               wpabuf_free(ies);
+               return -1;
+       }
+       wpabuf_free(ies);
+
+       p2p_set_state(p2p, P2P_LISTEN_ONLY);
+
+       return 0;
+}
+
+
+static void p2p_device_clear_reported(struct p2p_data *p2p)
+{
+       struct p2p_device *dev;
+       dl_list_for_each(dev, &p2p->devices, struct p2p_device, list)
+               dev->flags &= ~P2P_DEV_REPORTED;
+}
+
+
+/**
+ * p2p_get_device - Fetch a peer entry
+ * @p2p: P2P module context from p2p_init()
+ * @addr: P2P Device Address of the peer
+ * Returns: Pointer to the device entry or %NULL if not found
+ */
+struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr)
+{
+       struct p2p_device *dev;
+       dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+               if (os_memcmp(dev->info.p2p_device_addr, addr, ETH_ALEN) == 0)
+                       return dev;
+       }
+       return NULL;
+}
+
+
+/**
+ * p2p_get_device_interface - Fetch a peer entry based on P2P Interface Address
+ * @p2p: P2P module context from p2p_init()
+ * @addr: P2P Interface Address of the peer
+ * Returns: Pointer to the device entry or %NULL if not found
+ */
+struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p,
+                                            const u8 *addr)
+{
+       struct p2p_device *dev;
+       dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+               if (os_memcmp(dev->interface_addr, addr, ETH_ALEN) == 0)
+                       return dev;
+       }
+       return NULL;
+}
+
+
+/**
+ * p2p_create_device - Create a peer entry
+ * @p2p: P2P module context from p2p_init()
+ * @addr: P2P Device Address of the peer
+ * Returns: Pointer to the device entry or %NULL on failure
+ *
+ * If there is already an entry for the peer, it will be returned instead of
+ * creating a new one.
+ */
+static struct p2p_device * p2p_create_device(struct p2p_data *p2p,
+                                            const u8 *addr)
+{
+       struct p2p_device *dev, *oldest = NULL;
+       size_t count = 0;
+
+       dev = p2p_get_device(p2p, addr);
+       if (dev)
+               return dev;
+
+       dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+               count++;
+               if (oldest == NULL ||
+                   os_time_before(&dev->last_seen, &oldest->last_seen))
+                       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");
+               dl_list_del(&oldest->list);
+               p2p_device_free(p2p, oldest);
+       }
+
+       dev = os_zalloc(sizeof(*dev));
+       if (dev == NULL)
+               return NULL;
+       dl_list_add(&p2p->devices, &dev->list);
+       os_memcpy(dev->info.p2p_device_addr, addr, ETH_ALEN);
+
+       return dev;
+}
+
+
+static void p2p_copy_client_info(struct p2p_device *dev,
+                                struct p2p_client_info *cli)
+{
+       os_memcpy(dev->info.device_name, cli->dev_name, cli->dev_name_len);
+       dev->info.device_name[cli->dev_name_len] = '\0';
+       dev->info.dev_capab = cli->dev_capab;
+       dev->info.config_methods = cli->config_methods;
+       os_memcpy(dev->info.pri_dev_type, cli->pri_dev_type, 8);
+       dev->info.wps_sec_dev_type_list_len = 8 * cli->num_sec_dev_types;
+       os_memcpy(dev->info.wps_sec_dev_type_list, cli->sec_dev_types,
+                 dev->info.wps_sec_dev_type_list_len);
+}
+
+
+static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr,
+                                const u8 *go_interface_addr, int freq,
+                                const u8 *gi, size_t gi_len)
+{
+       struct p2p_group_info info;
+       size_t c;
+       struct p2p_device *dev;
+
+       if (gi == NULL)
+               return 0;
+
+       if (p2p_group_info_parse(gi, gi_len, &info) < 0)
+               return -1;
+
+       /*
+        * Clear old data for this group; if the devices are still in the
+        * group, the information will be restored in the loop following this.
+        */
+       dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+               if (os_memcmp(dev->member_in_go_iface, go_interface_addr,
+                             ETH_ALEN) == 0) {
+                       os_memset(dev->member_in_go_iface, 0, ETH_ALEN);
+                       os_memset(dev->member_in_go_dev, 0, ETH_ALEN);
+               }
+       }
+
+       for (c = 0; c < info.num_clients; c++) {
+               struct p2p_client_info *cli = &info.client[c];
+               if (os_memcmp(cli->p2p_device_addr, p2p->cfg->dev_addr,
+                             ETH_ALEN) == 0)
+                       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_copy_client_info(dev, cli);
+                       if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) {
+                               dev->flags &= ~P2P_DEV_PROBE_REQ_ONLY;
+                       }
+               } else {
+                       dev = p2p_create_device(p2p, cli->p2p_device_addr);
+                       if (dev == NULL)
+                               continue;
+                       dev->flags |= P2P_DEV_GROUP_CLIENT_ONLY;
+                       p2p_copy_client_info(dev, cli);
+                       dev->oper_freq = freq;
+                       p2p->cfg->dev_found(p2p->cfg->cb_ctx,
+                                           dev->info.p2p_device_addr,
+                                           &dev->info, 1);
+                       dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
+               }
+
+               os_memcpy(dev->interface_addr, cli->p2p_interface_addr,
+                         ETH_ALEN);
+               os_get_time(&dev->last_seen);
+               os_memcpy(dev->member_in_go_dev, go_dev_addr, ETH_ALEN);
+               os_memcpy(dev->member_in_go_iface, go_interface_addr,
+                         ETH_ALEN);
+       }
+
+       return 0;
+}
+
+
+static void p2p_copy_wps_info(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));
+
+       if (msg->manufacturer &&
+           msg->manufacturer_len < sizeof(dev->info.manufacturer)) {
+               os_memset(dev->info.manufacturer, 0,
+                         sizeof(dev->info.manufacturer));
+               os_memcpy(dev->info.manufacturer, msg->manufacturer,
+                         msg->manufacturer_len);
+       }
+
+       if (msg->model_name &&
+           msg->model_name_len < sizeof(dev->info.model_name)) {
+               os_memset(dev->info.model_name, 0,
+                         sizeof(dev->info.model_name));
+               os_memcpy(dev->info.model_name, msg->model_name,
+                         msg->model_name_len);
+       }
+
+       if (msg->model_number &&
+           msg->model_number_len < sizeof(dev->info.model_number)) {
+               os_memset(dev->info.model_number, 0,
+                         sizeof(dev->info.model_number));
+               os_memcpy(dev->info.model_number, msg->model_number,
+                         msg->model_number_len);
+       }
+
+       if (msg->serial_number &&
+           msg->serial_number_len < sizeof(dev->info.serial_number)) {
+               os_memset(dev->info.serial_number, 0,
+                         sizeof(dev->info.serial_number));
+               os_memcpy(dev->info.serial_number, msg->serial_number,
+                         msg->serial_number_len);
+       }
+
+       if (msg->pri_dev_type)
+               os_memcpy(dev->info.pri_dev_type, msg->pri_dev_type,
+                         sizeof(dev->info.pri_dev_type));
+       else if (msg->wps_pri_dev_type)
+               os_memcpy(dev->info.pri_dev_type, msg->wps_pri_dev_type,
+                         sizeof(dev->info.pri_dev_type));
+
+       if (msg->wps_sec_dev_type_list) {
+               os_memcpy(dev->info.wps_sec_dev_type_list,
+                         msg->wps_sec_dev_type_list,
+                         msg->wps_sec_dev_type_list_len);
+               dev->info.wps_sec_dev_type_list_len =
+                       msg->wps_sec_dev_type_list_len;
+       }
+
+       if (msg->capability) {
+               dev->info.dev_capab = msg->capability[0];
+               dev->info.group_capab = msg->capability[1];
+       }
+
+       if (msg->ext_listen_timing) {
+               dev->ext_listen_period = WPA_GET_LE16(msg->ext_listen_timing);
+               dev->ext_listen_interval =
+                       WPA_GET_LE16(msg->ext_listen_timing + 2);
+       }
+
+       if (!probe_req) {
+               dev->info.config_methods = msg->config_methods ?
+                       msg->config_methods : msg->wps_config_methods;
+       }
+}
+
+
+/**
+ * p2p_add_device - Add peer entries based on scan results
+ * @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
+ * @ies: IEs from the Beacon or Probe Response frame
+ * @ies_len: Length of ies buffer in octets
+ * Returns: 0 on success, -1 on failure
+ *
+ * If the scan result is for a GO, the clients in the group will also be added
+ * to the peer table. This function can also be used with some other frames
+ * 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)
+{
+       struct p2p_device *dev;
+       struct p2p_message msg;
+       const u8 *p2p_dev_addr;
+       int i;
+
+       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_parse_free(&msg);
+               return -1;
+       }
+
+       if (msg.p2p_device_addr)
+               p2p_dev_addr = msg.p2p_device_addr;
+       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_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));
+               return 0;
+       }
+
+       dev = p2p_create_device(p2p, p2p_dev_addr);
+       if (dev == NULL) {
+               p2p_parse_free(&msg);
+               return -1;
+       }
+       os_get_time(&dev->last_seen);
+       dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY);
+
+       if (os_memcmp(addr, p2p_dev_addr, ETH_ALEN) != 0)
+               os_memcpy(dev->interface_addr, addr, ETH_ALEN);
+       if (msg.ssid &&
+           (msg.ssid[1] != P2P_WILDCARD_SSID_LEN ||
+            os_memcmp(msg.ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN)
+            != 0)) {
+               os_memcpy(dev->oper_ssid, msg.ssid + 2, msg.ssid[1]);
+               dev->oper_ssid_len = msg.ssid[1];
+       }
+
+       if (freq >= 2412 && freq <= 2484 && msg.ds_params &&
+           *msg.ds_params >= 1 && *msg.ds_params <= 14) {
+               int ds_freq;
+               if (*msg.ds_params == 14)
+                       ds_freq = 2484;
+               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",
+                               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)",
+                       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;
+       dev->info.level = level;
+
+       p2p_copy_wps_info(dev, 0, &msg);
+
+       for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+               wpabuf_free(dev->info.wps_vendor_ext[i]);
+               dev->info.wps_vendor_ext[i] = NULL;
+       }
+
+       for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+               if (msg.wps_vendor_ext[i] == NULL)
+                       break;
+               dev->info.wps_vendor_ext[i] = wpabuf_alloc_copy(
+                       msg.wps_vendor_ext[i], msg.wps_vendor_ext_len[i]);
+               if (dev->info.wps_vendor_ext[i] == NULL)
+                       break;
+       }
+
+       p2p_add_group_clients(p2p, p2p_dev_addr, addr, freq, msg.group_info,
+                             msg.group_info_len);
+
+       p2p_parse_free(&msg);
+
+       if (p2p_pending_sd_req(p2p, dev))
+               dev->flags |= P2P_DEV_SD_SCHEDULE;
+
+       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);
+       if (dev->flags & P2P_DEV_USER_REJECTED) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Do not report rejected device");
+               return 0;
+       }
+
+       p2p->cfg->dev_found(p2p->cfg->cb_ctx, addr, &dev->info,
+                           !(dev->flags & P2P_DEV_REPORTED_ONCE));
+       dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
+
+       return 0;
+}
+
+
+static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev)
+{
+       int i;
+
+       if (p2p->go_neg_peer == dev) {
+               /*
+                * If GO Negotiation is in progress, report that it has failed.
+                */
+               p2p_go_neg_failed(p2p, dev, -1);
+               p2p->go_neg_peer = NULL;
+       }
+       if (p2p->invite_peer == dev)
+               p2p->invite_peer = NULL;
+       if (p2p->sd_peer == dev)
+               p2p->sd_peer = NULL;
+       if (p2p->pending_client_disc_go == dev)
+               p2p->pending_client_disc_go = NULL;
+
+       /* dev_lost() device, but only if it was previously dev_found() */
+       if (dev->flags & P2P_DEV_REPORTED_ONCE)
+               p2p->cfg->dev_lost(p2p->cfg->cb_ctx,
+                                  dev->info.p2p_device_addr);
+
+       for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+               wpabuf_free(dev->info.wps_vendor_ext[i]);
+               dev->info.wps_vendor_ext[i] = NULL;
+       }
+
+       os_free(dev);
+}
+
+
+static int p2p_get_next_prog_freq(struct p2p_data *p2p)
+{
+       struct p2p_channels *c;
+       struct p2p_reg_class *cla;
+       size_t cl, ch;
+       int found = 0;
+       u8 reg_class;
+       u8 channel;
+       int freq;
+
+       c = &p2p->cfg->channels;
+       for (cl = 0; cl < c->reg_classes; cl++) {
+               cla = &c->reg_class[cl];
+               if (cla->reg_class != p2p->last_prog_scan_class)
+                       continue;
+               for (ch = 0; ch < cla->channels; ch++) {
+                       if (cla->channel[ch] == p2p->last_prog_scan_chan) {
+                               found = 1;
+                               break;
+                       }
+               }
+               if (found)
+                       break;
+       }
+
+       if (!found) {
+               /* Start from beginning */
+               reg_class = c->reg_class[0].reg_class;
+               channel = c->reg_class[0].channel[0];
+       } else {
+               /* Pick the next channel */
+               ch++;
+               if (ch == cla->channels) {
+                       cl++;
+                       if (cl == c->reg_classes)
+                               cl = 0;
+                       ch = 0;
+               }
+               reg_class = c->reg_class[cl].reg_class;
+               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",
+               reg_class, channel, freq);
+       p2p->last_prog_scan_class = reg_class;
+       p2p->last_prog_scan_chan = channel;
+
+       if (freq == 2412 || freq == 2437 || freq == 2462)
+               return 0; /* No need to add social channels */
+       return freq;
+}
+
+
+static void p2p_search(struct p2p_data *p2p)
+{
+       int freq = 0;
+       enum p2p_scan_type type;
+
+       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");
+               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) {
+               type = P2P_SCAN_SOCIAL_PLUS_ONE;
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search "
+                       "(+ freq %u)", freq);
+       } else {
+               type = P2P_SCAN_SOCIAL;
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "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");
+               p2p_continue_find(p2p);
+       } else {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "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);
+       }
+}
+
+
+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_stop_find(p2p);
+}
+
+
+static int p2p_run_after_scan(struct p2p_data *p2p)
+{
+       struct p2p_device *dev;
+       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->cfg->send_action(p2p->cfg->cb_ctx,
+                                     p2p->after_scan_tx->freq,
+                                     p2p->after_scan_tx->dst,
+                                     p2p->after_scan_tx->src,
+                                     p2p->after_scan_tx->bssid,
+                                     (u8 *) (p2p->after_scan_tx + 1),
+                                     p2p->after_scan_tx->len,
+                                     p2p->after_scan_tx->wait_time);
+               os_free(p2p->after_scan_tx);
+               p2p->after_scan_tx = NULL;
+               return 1;
+       }
+
+       op = p2p->start_after_scan;
+       p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
+       switch (op) {
+       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_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,
+                       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");
+                       break;
+               }
+               p2p_connect_send(p2p, dev);
+               return 1;
+       }
+
+       return 0;
+}
+
+
+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);
+       running = p2p->p2p_scan_running;
+       /* Make sure we recover from missed scan results callback */
+       p2p->p2p_scan_running = 0;
+
+       if (running)
+               p2p_run_after_scan(p2p);
+}
+
+
+static void p2p_free_req_dev_types(struct p2p_data *p2p)
+{
+       p2p->num_req_dev_types = 0;
+       os_free(p2p->req_dev_types);
+       p2p->req_dev_types = NULL;
+}
+
+
+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)
+{
+       int res;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting find (type=%d)",
+               type);
+       if (p2p->p2p_scan_running) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan is "
+                       "already running");
+       }
+
+       p2p_free_req_dev_types(p2p);
+       if (req_dev_types && num_req_dev_types) {
+               p2p->req_dev_types = os_malloc(num_req_dev_types *
+                                              WPS_DEV_TYPE_LEN);
+               if (p2p->req_dev_types == NULL)
+                       return -1;
+               os_memcpy(p2p->req_dev_types, req_dev_types,
+                         num_req_dev_types * WPS_DEV_TYPE_LEN);
+               p2p->num_req_dev_types = num_req_dev_types;
+       }
+
+       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);
+       eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
+       p2p->last_p2p_find_timeout = timeout;
+       if (timeout)
+               eloop_register_timeout(timeout, 0, p2p_find_timeout,
+                                      p2p, NULL);
+       switch (type) {
+       case P2P_FIND_START_WITH_FULL:
+       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);
+               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);
+               break;
+       default:
+               return -1;
+       }
+
+       if (res == 0) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "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");
+               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_set_state(p2p, P2P_IDLE);
+               eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
+       }
+
+       return res;
+}
+
+
+int p2p_other_scan_completed(struct p2p_data *p2p)
+{
+       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");
+       if (p2p_find(p2p, p2p->last_p2p_find_timeout, p2p->find_type,
+                    p2p->num_req_dev_types, p2p->req_dev_types) < 0)
+               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");
+       eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
+       p2p_clear_timeout(p2p);
+       p2p_set_state(p2p, P2P_IDLE);
+       p2p_free_req_dev_types(p2p);
+       p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
+       p2p->go_neg_peer = NULL;
+       p2p->sd_peer = NULL;
+       p2p->invite_peer = NULL;
+       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");
+               return;
+       }
+       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->drv_in_listen = 0;
+       }
+       p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
+}
+
+
+void p2p_stop_find(struct p2p_data *p2p)
+{
+       p2p_stop_find_for_freq(p2p, 0);
+}
+
+
+static int p2p_prepare_channel(struct p2p_data *p2p, unsigned int force_freq)
+{
+       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",
+               p2p->op_reg_class, p2p->op_channel,
+               force_freq ? " (forced)" : "");
+
+       return 0;
+}
+
+
+static void p2p_set_dev_persistent(struct p2p_device *dev,
+                                  int persistent_group)
+{
+       switch (persistent_group) {
+       case 0:
+               dev->flags &= ~(P2P_DEV_PREFER_PERSISTENT_GROUP |
+                               P2P_DEV_PREFER_PERSISTENT_RECONN);
+               break;
+       case 1:
+               dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP;
+               dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_RECONN;
+               break;
+       case 2:
+               dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP |
+                       P2P_DEV_PREFER_PERSISTENT_RECONN;
+               break;
+       }
+}
+
+
+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)
+{
+       struct p2p_device *dev;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "P2P: Request to start 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;
+
+       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,
+                       MAC2STR(peer_addr));
+               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
+                               " 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
+                               " with incomplete information",
+                               MAC2STR(peer_addr));
+                       return -1;
+               }
+
+               /*
+                * First, try to connect directly. If the peer does not
+                * acknowledge frames, assume it is sleeping and use device
+                * discoverability via the GO at that point.
+                */
+       }
+
+       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;
+       dev->connect_reqs = 0;
+       dev->go_neg_req_sent = 0;
+       dev->go_state = UNKNOWN_GO;
+       p2p_set_dev_persistent(dev, persistent_group);
+       p2p->go_intent = go_intent;
+       os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
+
+       if (p2p->state != P2P_IDLE)
+               p2p_stop_find(p2p);
+
+       if (p2p->after_scan_tx) {
+               /*
+                * We need to drop the pending frame to avoid issues with the
+                * 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");
+               os_free(p2p->after_scan_tx);
+               p2p->after_scan_tx = NULL;
+       }
+
+       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->start_after_scan = P2P_AFTER_SCAN_CONNECT;
+               os_memcpy(p2p->after_scan_peer, peer_addr, ETH_ALEN);
+               return 0;
+       }
+       p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
+
+       return p2p_connect_send(p2p, dev);
+}
+
+
+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)
+{
+       struct p2p_device *dev;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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,
+                       MAC2STR(peer_addr));
+               return -1;
+       }
+
+       dev->flags &= ~P2P_DEV_NOT_YET_READY;
+       dev->flags &= ~P2P_DEV_USER_REJECTED;
+       dev->go_neg_req_sent = 0;
+       dev->go_state = UNKNOWN_GO;
+       p2p_set_dev_persistent(dev, persistent_group);
+       p2p->go_intent = go_intent;
+       os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
+
+       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;
+}
+
+
+void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
+                     struct p2p_device *dev, struct p2p_message *msg)
+{
+       os_get_time(&dev->last_seen);
+
+       p2p_copy_wps_info(dev, 0, msg);
+
+       if (msg->listen_channel) {
+               int freq;
+               freq = p2p_channel_to_freq((char *) msg->listen_channel,
+                                          msg->listen_channel[3],
+                                          msg->listen_channel[4]);
+               if (freq < 0) {
+                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                               "P2P: Unknown peer Listen channel: "
+                               "country=%c%c(0x%02x) reg_class=%u channel=%u",
+                               msg->listen_channel[0],
+                               msg->listen_channel[1],
+                               msg->listen_channel[2],
+                               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",
+                               MAC2STR(dev->info.p2p_device_addr),
+                               dev->listen_freq, freq);
+                       dev->listen_freq = freq;
+               }
+       }
+
+       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");
+       } else {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "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),
+                       dev->info.dev_capab, dev->info.group_capab,
+                       dev->info.device_name, dev->listen_freq);
+       }
+
+       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");
+               return;
+       }
+
+       p2p->cfg->dev_found(p2p->cfg->cb_ctx, addr, &dev->info,
+                           !(dev->flags & P2P_DEV_REPORTED_ONCE));
+       dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
+}
+
+
+void p2p_build_ssid(struct p2p_data *p2p, u8 *ssid, size_t *ssid_len)
+{
+       os_memcpy(ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
+       p2p_random((char *) &ssid[P2P_WILDCARD_SSID_LEN], 2);
+       os_memcpy(&ssid[P2P_WILDCARD_SSID_LEN + 2],
+                 p2p->cfg->ssid_postfix, p2p->cfg->ssid_postfix_len);
+       *ssid_len = P2P_WILDCARD_SSID_LEN + 2 + p2p->cfg->ssid_postfix_len;
+}
+
+
+int p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params)
+{
+       p2p_build_ssid(p2p, params->ssid, &params->ssid_len);
+       p2p_random(params->passphrase, 8);
+       return 0;
+}
+
+
+void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
+{
+       struct p2p_go_neg_results res;
+       int go = peer->go_state == LOCAL_GO;
+       struct p2p_channels intersection;
+       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");
+
+       os_memset(&res, 0, sizeof(res));
+       res.role_go = go;
+       os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
+       os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN);
+       res.wps_method = peer->wps_method;
+       if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
+               if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+                       res.persistent_group = 2;
+               else
+                       res.persistent_group = 1;
+       }
+
+       if (go) {
+               /* Setup AP mode for WPS provisioning */
+               res.freq = p2p_channel_to_freq(p2p->cfg->country,
+                                              p2p->op_reg_class,
+                                              p2p->op_channel);
+               os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len);
+               res.ssid_len = p2p->ssid_len;
+               p2p_random(res.passphrase, 8);
+       } else {
+               res.freq = peer->oper_freq;
+               if (p2p->ssid_len) {
+                       os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len);
+                       res.ssid_len = p2p->ssid_len;
+               }
+       }
+
+       p2p_channels_intersect(&p2p->channels, &peer->channels,
+                              &intersection);
+       freqs = 0;
+       for (i = 0; i < intersection.reg_classes; i++) {
+               struct p2p_reg_class *c = &intersection.reg_class[i];
+               if (freqs + 1 == P2P_MAX_CHANNELS)
+                       break;
+               for (j = 0; j < c->channels; j++) {
+                       int freq;
+                       if (freqs + 1 == P2P_MAX_CHANNELS)
+                               break;
+                       freq = p2p_channel_to_freq(peer->country, c->reg_class,
+                                                  c->channel[j]);
+                       if (freq < 0)
+                               continue;
+                       res.freq_list[freqs++] = freq;
+               }
+       }
+
+       res.peer_config_timeout = go ? peer->client_timeout : peer->go_timeout;
+
+       p2p_clear_timeout(p2p);
+       p2p->ssid_set = 0;
+       peer->go_neg_req_sent = 0;
+       peer->wps_method = WPS_NOT_READY;
+
+       p2p_set_state(p2p, P2P_PROVISIONING);
+       p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
+}
+
+
+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));
+       wpa_hexdump(MSG_MSGDUMP, "P2P: P2P Public Action contents", data, len);
+
+       if (len < 1)
+               return;
+
+       switch (data[0]) {
+       case P2P_GO_NEG_REQ:
+               p2p_process_go_neg_req(p2p, sa, data + 1, len - 1, rx_freq);
+               break;
+       case P2P_GO_NEG_RESP:
+               p2p_process_go_neg_resp(p2p, sa, data + 1, len - 1, rx_freq);
+               break;
+       case P2P_GO_NEG_CONF:
+               p2p_process_go_neg_conf(p2p, sa, data + 1, len - 1);
+               break;
+       case P2P_INVITATION_REQ:
+               p2p_process_invitation_req(p2p, sa, data + 1, len - 1,
+                                          rx_freq);
+               break;
+       case P2P_INVITATION_RESP:
+               p2p_process_invitation_resp(p2p, sa, data + 1, len - 1);
+               break;
+       case P2P_PROV_DISC_REQ:
+               p2p_process_prov_disc_req(p2p, sa, data + 1, len - 1, rx_freq);
+               break;
+       case P2P_PROV_DISC_RESP:
+               p2p_process_prov_disc_resp(p2p, sa, data + 1, len - 1);
+               break;
+       case P2P_DEV_DISC_REQ:
+               p2p_process_dev_disc_req(p2p, sa, data + 1, len - 1, rx_freq);
+               break;
+       case P2P_DEV_DISC_RESP:
+               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",
+                       data[0]);
+               break;
+       }
+}
+
+
+static void p2p_rx_action_public(struct p2p_data *p2p, const u8 *da,
+                                const u8 *sa, const u8 *bssid, const u8 *data,
+                                size_t len, int freq)
+{
+       if (len < 1)
+               return;
+
+       switch (data[0]) {
+       case WLAN_PA_VENDOR_SPECIFIC:
+               data++;
+               len--;
+               if (len < 3)
+                       return;
+               if (WPA_GET_BE24(data) != OUI_WFA)
+                       return;
+
+               data += 3;
+               len -= 3;
+               if (len < 1)
+                       return;
+
+               if (*data != P2P_OUI_TYPE)
+                       return;
+
+               p2p_rx_p2p_action(p2p, sa, data + 1, len - 1, freq);
+               break;
+       case WLAN_PA_GAS_INITIAL_REQ:
+               p2p_rx_gas_initial_req(p2p, sa, data + 1, len - 1, freq);
+               break;
+       case WLAN_PA_GAS_INITIAL_RESP:
+               p2p_rx_gas_initial_resp(p2p, sa, data + 1, len - 1, freq);
+               break;
+       case WLAN_PA_GAS_COMEBACK_REQ:
+               p2p_rx_gas_comeback_req(p2p, sa, data + 1, len - 1, freq);
+               break;
+       case WLAN_PA_GAS_COMEBACK_RESP:
+               p2p_rx_gas_comeback_resp(p2p, sa, data + 1, len - 1, freq);
+               break;
+       }
+}
+
+
+void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa,
+                  const u8 *bssid, u8 category,
+                  const u8 *data, size_t len, int freq)
+{
+       if (category == WLAN_ACTION_PUBLIC) {
+               p2p_rx_action_public(p2p, da, sa, bssid, data, len, freq);
+               return;
+       }
+
+       if (category != WLAN_ACTION_VENDOR_SPECIFIC)
+               return;
+
+       if (len < 4)
+               return;
+
+       if (WPA_GET_BE24(data) != OUI_WFA)
+               return;
+       data += 3;
+       len -= 3;
+
+       if (*data != P2P_OUI_TYPE)
+               return;
+       data++;
+       len--;
+
+       /* P2P action frame */
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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");
+               /* TODO */
+               break;
+       case P2P_PRESENCE_REQ:
+               p2p_process_presence_req(p2p, da, sa, data + 1, len - 1, freq);
+               break;
+       case P2P_PRESENCE_RESP:
+               p2p_process_presence_resp(p2p, da, sa, data + 1, len - 1);
+               break;
+       case P2P_GO_DISC_REQ:
+               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]);
+               break;
+       }
+}
+
+
+static void p2p_go_neg_start(void *eloop_ctx, void *timeout_ctx)
+{
+       struct p2p_data *p2p = eloop_ctx;
+       if (p2p->go_neg_peer == NULL)
+               return;
+       p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
+       p2p->go_neg_peer->status = P2P_SC_SUCCESS;
+       p2p_connect_send(p2p, p2p->go_neg_peer);
+}
+
+
+static void p2p_invite_start(void *eloop_ctx, void *timeout_ctx)
+{
+       struct p2p_data *p2p = eloop_ctx;
+       if (p2p->invite_peer == NULL)
+               return;
+       p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
+       p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr);
+}
+
+
+static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr,
+                                      const u8 *ie, size_t ie_len)
+{
+       struct p2p_message msg;
+       struct p2p_device *dev;
+
+       os_memset(&msg, 0, sizeof(msg));
+       if (p2p_parse_ies(ie, ie_len, &msg) < 0 || msg.p2p_attributes == NULL)
+       {
+               p2p_parse_free(&msg);
+               return; /* not a P2P probe */
+       }
+
+       if (msg.ssid == NULL || msg.ssid[1] != P2P_WILDCARD_SSID_LEN ||
+           os_memcmp(msg.ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN)
+           != 0) {
+               /* The Probe Request is not part of P2P Device Discovery. It is
+                * not known whether the source address of the frame is the P2P
+                * Device Address or P2P Interface Address. Do not add a new
+                * peer entry based on this frames.
+                */
+               p2p_parse_free(&msg);
+               return;
+       }
+
+       dev = p2p_get_device(p2p, addr);
+       if (dev) {
+               if (dev->country[0] == 0 && msg.listen_channel)
+                       os_memcpy(dev->country, msg.listen_channel, 3);
+               os_get_time(&dev->last_seen);
+               p2p_parse_free(&msg);
+               return; /* already known */
+       }
+
+       dev = p2p_create_device(p2p, addr);
+       if (dev == NULL) {
+               p2p_parse_free(&msg);
+               return;
+       }
+
+       os_get_time(&dev->last_seen);
+       dev->flags |= P2P_DEV_PROBE_REQ_ONLY;
+
+       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],
+                                                      msg.listen_channel[4]);
+       }
+
+       p2p_copy_wps_info(dev, 1, &msg);
+
+       p2p_parse_free(&msg);
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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,
+               dev->listen_freq);
+}
+
+
+struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p,
+                                               const u8 *addr,
+                                               struct p2p_message *msg)
+{
+       struct p2p_device *dev;
+
+       dev = p2p_get_device(p2p, addr);
+       if (dev) {
+               os_get_time(&dev->last_seen);
+               return dev; /* already known */
+       }
+
+       dev = p2p_create_device(p2p, addr);
+       if (dev == NULL)
+               return NULL;
+
+       p2p_add_dev_info(p2p, addr, dev, msg);
+
+       return dev;
+}
+
+
+static int dev_type_match(const u8 *dev_type, const u8 *req_dev_type)
+{
+       if (os_memcmp(dev_type, req_dev_type, WPS_DEV_TYPE_LEN) == 0)
+               return 1;
+       if (os_memcmp(dev_type, req_dev_type, 2) == 0 &&
+           WPA_GET_BE32(&req_dev_type[2]) == 0 &&
+           WPA_GET_BE16(&req_dev_type[6]) == 0)
+               return 1; /* Category match with wildcard OUI/sub-category */
+       return 0;
+}
+
+
+int dev_type_list_match(const u8 *dev_type, const u8 *req_dev_type[],
+                       size_t num_req_dev_type)
+{
+       size_t i;
+       for (i = 0; i < num_req_dev_type; i++) {
+               if (dev_type_match(dev_type, req_dev_type[i]))
+                       return 1;
+       }
+       return 0;
+}
+
+
+/**
+ * p2p_match_dev_type - Match local device type with requested type
+ * @p2p: P2P module context from p2p_init()
+ * @wps: WPS TLVs from Probe Request frame (concatenated WPS IEs)
+ * Returns: 1 on match, 0 on mismatch
+ *
+ * This function can be used to match the Requested Device Type attribute in
+ * WPS IE with the local device types for deciding whether to reply to a Probe
+ * Request frame.
+ */
+int p2p_match_dev_type(struct p2p_data *p2p, struct wpabuf *wps)
+{
+       struct wps_parse_attr attr;
+       size_t i;
+
+       if (wps_parse_msg(wps, &attr))
+               return 1; /* assume no Requested Device Type attributes */
+
+       if (attr.num_req_dev_type == 0)
+               return 1; /* no Requested Device Type attributes -> match */
+
+       if (dev_type_list_match(p2p->cfg->pri_dev_type, attr.req_dev_type,
+                               attr.num_req_dev_type))
+               return 1; /* Own Primary Device Type matches */
+
+       for (i = 0; i < p2p->cfg->num_sec_dev_types; i++)
+               if (dev_type_list_match(p2p->cfg->sec_dev_type[i],
+                                       attr.req_dev_type,
+                                       attr.num_req_dev_type))
+               return 1; /* Own Secondary Device Type matches */
+
+       /* No matching device type found */
+       return 0;
+}
+
+
+struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
+{
+       struct wpabuf *buf;
+       u8 *len;
+
+       buf = wpabuf_alloc(1000);
+       if (buf == NULL)
+               return NULL;
+
+       p2p_build_wps_ie(p2p, buf, DEV_PW_DEFAULT, 1);
+
+       /* P2P IE */
+       len = p2p_buf_add_ie_hdr(buf);
+       p2p_buf_add_capability(buf, p2p->dev_capab, 0);
+       if (p2p->ext_listen_interval)
+               p2p_buf_add_ext_listen_timing(buf, p2p->ext_listen_period,
+                                             p2p->ext_listen_interval);
+       p2p_buf_add_device_info(buf, p2p, NULL);
+       p2p_buf_update_ie_hdr(buf, len);
+
+       return buf;
+}
+
+
+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)
+{
+       struct ieee802_11_elems elems;
+       struct wpabuf *buf;
+       struct ieee80211_mgmt *resp;
+       struct p2p_message msg;
+       struct wpabuf *ies;
+
+       if (!p2p->in_listen || !p2p->drv_in_listen) {
+               /* not in Listen state - ignore Probe Request */
+               return;
+       }
+
+       if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
+           ParseFailed) {
+               /* Ignore invalid Probe Request frames */
+               return;
+       }
+
+       if (elems.p2p == NULL) {
+               /* not a P2P probe - ignore it */
+               return;
+       }
+
+       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;
+       }
+
+       if (bssid && !is_broadcast_ether_addr(bssid)) {
+               /* Not sent to the Wildcard BSSID */
+               return;
+       }
+
+       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;
+       }
+
+       if (supp_rates_11b_only(&elems)) {
+               /* Indicates support for 11b rates only */
+               return;
+       }
+
+       os_memset(&msg, 0, sizeof(msg));
+       if (p2p_parse_ies(ie, ie_len, &msg) < 0) {
+               /* Could not parse P2P attributes */
+               return;
+       }
+
+       if (msg.device_id &&
+           os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN != 0)) {
+               /* Device ID did not match */
+               p2p_parse_free(&msg);
+               return;
+       }
+
+       /* Check Requested Device Type match */
+       if (msg.wps_attributes &&
+           !p2p_match_dev_type(p2p, msg.wps_attributes)) {
+               /* No match with Requested Device Type */
+               p2p_parse_free(&msg);
+               return;
+       }
+       p2p_parse_free(&msg);
+
+       if (!p2p->cfg->send_probe_resp)
+               return; /* Response generated elsewhere */
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "P2P: Reply to P2P Probe Request in Listen state");
+
+       /*
+        * We do not really have a specific BSS that this frame is advertising,
+        * so build a frame that has some information in valid format. This is
+        * really only used for discovery purposes, not to learn exact BSS
+        * parameters.
+        */
+       ies = p2p_build_probe_resp_ies(p2p);
+       if (ies == NULL)
+               return;
+
+       buf = wpabuf_alloc(200 + wpabuf_len(ies));
+       if (buf == NULL) {
+               wpabuf_free(ies);
+               return;
+       }
+
+       resp = NULL;
+       resp = wpabuf_put(buf, resp->u.probe_resp.variable - (u8 *) resp);
+
+       resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
+                                          (WLAN_FC_STYPE_PROBE_RESP << 4));
+       os_memcpy(resp->da, addr, ETH_ALEN);
+       os_memcpy(resp->sa, p2p->cfg->dev_addr, ETH_ALEN);
+       os_memcpy(resp->bssid, p2p->cfg->dev_addr, ETH_ALEN);
+       resp->u.probe_resp.beacon_int = host_to_le16(100);
+       /* hardware or low-level driver will setup seq_ctrl and timestamp */
+       resp->u.probe_resp.capab_info =
+               host_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE |
+                            WLAN_CAPABILITY_PRIVACY |
+                            WLAN_CAPABILITY_SHORT_SLOT_TIME);
+
+       wpabuf_put_u8(buf, WLAN_EID_SSID);
+       wpabuf_put_u8(buf, P2P_WILDCARD_SSID_LEN);
+       wpabuf_put_data(buf, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
+
+       wpabuf_put_u8(buf, WLAN_EID_SUPP_RATES);
+       wpabuf_put_u8(buf, 8);
+       wpabuf_put_u8(buf, (60 / 5) | 0x80);
+       wpabuf_put_u8(buf, 90 / 5);
+       wpabuf_put_u8(buf, (120 / 5) | 0x80);
+       wpabuf_put_u8(buf, 180 / 5);
+       wpabuf_put_u8(buf, (240 / 5) | 0x80);
+       wpabuf_put_u8(buf, 360 / 5);
+       wpabuf_put_u8(buf, 480 / 5);
+       wpabuf_put_u8(buf, 540 / 5);
+
+       wpabuf_put_u8(buf, WLAN_EID_DS_PARAMS);
+       wpabuf_put_u8(buf, 1);
+       wpabuf_put_u8(buf, p2p->cfg->channel);
+
+       wpabuf_put_buf(buf, ies);
+       wpabuf_free(ies);
+
+       p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf);
+
+       wpabuf_free(buf);
+}
+
+
+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)
+{
+       p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
+
+       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) {
+               /* 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");
+               eloop_register_timeout(0, 0, p2p_go_neg_start, p2p, NULL);
+               return 1;
+       }
+
+       if ((p2p->state == P2P_INVITE || p2p->state == P2P_INVITE_LISTEN) &&
+           p2p->invite_peer &&
+           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");
+               eloop_register_timeout(0, 0, p2p_invite_start, p2p, NULL);
+               return 1;
+       }
+
+       return 0;
+}
+
+
+static int p2p_assoc_req_ie_wlan_ap(struct p2p_data *p2p, const u8 *bssid,
+                                   u8 *buf, size_t len, struct wpabuf *p2p_ie)
+{
+       struct wpabuf *tmp;
+       u8 *lpos;
+       size_t tmplen;
+       int res;
+       u8 group_capab;
+
+       if (p2p_ie == NULL)
+               return 0; /* WLAN AP is not a P2P manager */
+
+       /*
+        * (Re)Association Request - P2P IE
+        * P2P Capability attribute (shall be present)
+        * P2P Interface attribute (present if concurrent device and
+        *      P2P Management is enabled)
+        */
+       tmp = wpabuf_alloc(200);
+       if (tmp == NULL)
+               return -1;
+
+       lpos = p2p_buf_add_ie_hdr(tmp);
+       group_capab = 0;
+       if (p2p->num_groups > 0) {
+               group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER;
+               if ((p2p->dev_capab & P2P_DEV_CAPAB_CONCURRENT_OPER) &&
+                   (p2p->dev_capab & P2P_DEV_CAPAB_INFRA_MANAGED) &&
+                   p2p->cross_connect)
+                       group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
+       }
+       p2p_buf_add_capability(tmp, p2p->dev_capab, group_capab);
+       if ((p2p->dev_capab & P2P_DEV_CAPAB_CONCURRENT_OPER) &&
+           (p2p->dev_capab & P2P_DEV_CAPAB_INFRA_MANAGED))
+               p2p_buf_add_p2p_interface(tmp, p2p);
+       p2p_buf_update_ie_hdr(tmp, lpos);
+
+       tmplen = wpabuf_len(tmp);
+       if (tmplen > len)
+               res = -1;
+       else {
+               os_memcpy(buf, wpabuf_head(tmp), tmplen);
+               res = tmplen;
+       }
+       wpabuf_free(tmp);
+
+       return res;
+}
+
+
+int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf,
+                    size_t len, int p2p_group, struct wpabuf *p2p_ie)
+{
+       struct wpabuf *tmp;
+       u8 *lpos;
+       struct p2p_device *peer;
+       size_t tmplen;
+       int res;
+
+       if (!p2p_group)
+               return p2p_assoc_req_ie_wlan_ap(p2p, bssid, buf, len, p2p_ie);
+
+       /*
+        * (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);
+       if (tmp == NULL)
+               return -1;
+
+       peer = bssid ? p2p_get_device(p2p, bssid) : NULL;
+
+       lpos = p2p_buf_add_ie_hdr(tmp);
+       p2p_buf_add_capability(tmp, p2p->dev_capab, 0);
+       if (p2p->ext_listen_interval)
+               p2p_buf_add_ext_listen_timing(tmp, p2p->ext_listen_period,
+                                             p2p->ext_listen_interval);
+       p2p_buf_add_device_info(tmp, p2p, peer);
+       p2p_buf_update_ie_hdr(tmp, lpos);
+
+       tmplen = wpabuf_len(tmp);
+       if (tmplen > len)
+               res = -1;
+       else {
+               os_memcpy(buf, wpabuf_head(tmp), tmplen);
+               res = tmplen;
+       }
+       wpabuf_free(tmp);
+
+       return res;
+}
+
+
+int p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end)
+{
+       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 0;
+
+       ret = p2p_attr_text(p2p_ie, buf, end);
+       wpabuf_free(p2p_ie);
+       return ret;
+}
+
+
+static void p2p_clear_go_neg(struct p2p_data *p2p)
+{
+       p2p->go_neg_peer = NULL;
+       p2p_clear_timeout(p2p);
+       p2p_set_state(p2p, P2P_IDLE);
+}
+
+
+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");
+               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 ")",
+                       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,
+               MAC2STR(mac_addr));
+
+       p2p_clear_go_neg(p2p);
+}
+
+
+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");
+               return; /* No pending Group Formation */
+       }
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "P2P: Group Formation failed with " MACSTR,
+               MAC2STR(p2p->go_neg_peer->intended_addr));
+
+       p2p_clear_go_neg(p2p);
+}
+
+
+struct p2p_data * p2p_init(const struct p2p_config *cfg)
+{
+       struct p2p_data *p2p;
+
+       if (cfg->max_peers < 1)
+               return NULL;
+
+       p2p = os_zalloc(sizeof(*p2p) + sizeof(*cfg));
+       if (p2p == NULL)
+               return NULL;
+       p2p->cfg = (struct p2p_config *) (p2p + 1);
+       os_memcpy(p2p->cfg, cfg, sizeof(*cfg));
+       if (cfg->dev_name)
+               p2p->cfg->dev_name = os_strdup(cfg->dev_name);
+       if (cfg->manufacturer)
+               p2p->cfg->manufacturer = os_strdup(cfg->manufacturer);
+       if (cfg->model_name)
+               p2p->cfg->model_name = os_strdup(cfg->model_name);
+       if (cfg->model_number)
+               p2p->cfg->model_number = os_strdup(cfg->model_number);
+       if (cfg->serial_number)
+               p2p->cfg->serial_number = os_strdup(cfg->serial_number);
+
+       p2p->min_disc_int = 1;
+       p2p->max_disc_int = 3;
+
+       os_get_random(&p2p->next_tie_breaker, 1);
+       p2p->next_tie_breaker &= 0x01;
+       if (cfg->sd_request)
+               p2p->dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
+       p2p->dev_capab |= P2P_DEV_CAPAB_INVITATION_PROCEDURE;
+       if (cfg->concurrent_operations)
+               p2p->dev_capab |= P2P_DEV_CAPAB_CONCURRENT_OPER;
+       p2p->dev_capab |= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
+
+       dl_list_init(&p2p->devices);
+
+       eloop_register_timeout(P2P_PEER_EXPIRATION_INTERVAL, 0,
+                              p2p_expiration_timeout, p2p, NULL);
+
+       return p2p;
+}
+
+
+void p2p_deinit(struct p2p_data *p2p)
+{
+       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);
+       p2p_flush(p2p);
+       p2p_free_req_dev_types(p2p);
+       os_free(p2p->cfg->dev_name);
+       os_free(p2p->cfg->manufacturer);
+       os_free(p2p->cfg->model_name);
+       os_free(p2p->cfg->model_number);
+       os_free(p2p->cfg->serial_number);
+       os_free(p2p->groups);
+       wpabuf_free(p2p->sd_resp);
+       os_free(p2p->after_scan_tx);
+       p2p_remove_wps_vendor_extensions(p2p);
+       os_free(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);
+       dl_list_for_each_safe(dev, prev, &p2p->devices, struct p2p_device,
+                             list) {
+               dl_list_del(&dev->list);
+               p2p_device_free(p2p, dev);
+       }
+       p2p_free_sd_queries(p2p);
+       os_free(p2p->after_scan_tx);
+       p2p->after_scan_tx = NULL;
+}
+
+
+int p2p_unauthorize(struct p2p_data *p2p, const u8 *addr)
+{
+       struct p2p_device *dev;
+
+       dev = p2p_get_device(p2p, addr);
+       if (dev == NULL)
+               return -1;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unauthorizing " MACSTR,
+               MAC2STR(addr));
+
+       if (p2p->go_neg_peer == dev)
+               p2p->go_neg_peer = NULL;
+
+       dev->wps_method = WPS_NOT_READY;
+       dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
+       dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
+
+       /* Check if after_scan_tx is for this peer. If so free it */
+       if (p2p->after_scan_tx &&
+           os_memcmp(addr, p2p->after_scan_tx->dst, ETH_ALEN) == 0) {
+               os_free(p2p->after_scan_tx);
+               p2p->after_scan_tx = NULL;
+       }
+
+       return 0;
+}
+
+
+int p2p_set_dev_name(struct p2p_data *p2p, const char *dev_name)
+{
+       os_free(p2p->cfg->dev_name);
+       if (dev_name) {
+               p2p->cfg->dev_name = os_strdup(dev_name);
+               if (p2p->cfg->dev_name == NULL)
+                       return -1;
+       } else
+               p2p->cfg->dev_name = NULL;
+       return 0;
+}
+
+
+int p2p_set_manufacturer(struct p2p_data *p2p, const char *manufacturer)
+{
+       os_free(p2p->cfg->manufacturer);
+       p2p->cfg->manufacturer = NULL;
+       if (manufacturer) {
+               p2p->cfg->manufacturer = os_strdup(manufacturer);
+               if (p2p->cfg->manufacturer == NULL)
+                       return -1;
+       }
+
+       return 0;
+}
+
+
+int p2p_set_model_name(struct p2p_data *p2p, const char *model_name)
+{
+       os_free(p2p->cfg->model_name);
+       p2p->cfg->model_name = NULL;
+       if (model_name) {
+               p2p->cfg->model_name = os_strdup(model_name);
+               if (p2p->cfg->model_name == NULL)
+                       return -1;
+       }
+
+       return 0;
+}
+
+
+int p2p_set_model_number(struct p2p_data *p2p, const char *model_number)
+{
+       os_free(p2p->cfg->model_number);
+       p2p->cfg->model_number = NULL;
+       if (model_number) {
+               p2p->cfg->model_number = os_strdup(model_number);
+               if (p2p->cfg->model_number == NULL)
+                       return -1;
+       }
+
+       return 0;
+}
+
+
+int p2p_set_serial_number(struct p2p_data *p2p, const char *serial_number)
+{
+       os_free(p2p->cfg->serial_number);
+       p2p->cfg->serial_number = NULL;
+       if (serial_number) {
+               p2p->cfg->serial_number = os_strdup(serial_number);
+               if (p2p->cfg->serial_number == NULL)
+                       return -1;
+       }
+
+       return 0;
+}
+
+
+void p2p_set_config_methods(struct p2p_data *p2p, u16 config_methods)
+{
+       p2p->cfg->config_methods = config_methods;
+}
+
+
+void p2p_set_uuid(struct p2p_data *p2p, const u8 *uuid)
+{
+       os_memcpy(p2p->cfg->uuid, uuid, 16);
+}
+
+
+int p2p_set_pri_dev_type(struct p2p_data *p2p, const u8 *pri_dev_type)
+{
+       os_memcpy(p2p->cfg->pri_dev_type, pri_dev_type, 8);
+       return 0;
+}
+
+
+int p2p_set_sec_dev_types(struct p2p_data *p2p, const u8 dev_types[][8],
+                         size_t num_dev_types)
+{
+       if (num_dev_types > P2P_SEC_DEVICE_TYPES)
+               num_dev_types = P2P_SEC_DEVICE_TYPES;
+       p2p->cfg->num_sec_dev_types = num_dev_types;
+       os_memcpy(p2p->cfg->sec_dev_type, dev_types, num_dev_types * 8);
+       return 0;
+}
+
+
+void p2p_remove_wps_vendor_extensions(struct p2p_data *p2p)
+{
+       int i;
+
+       for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+               wpabuf_free(p2p->wps_vendor_ext[i]);
+               p2p->wps_vendor_ext[i] = NULL;
+       }
+}
+
+
+int p2p_add_wps_vendor_extension(struct p2p_data *p2p,
+                                const struct wpabuf *vendor_ext)
+{
+       int i;
+
+       if (vendor_ext == NULL)
+               return -1;
+
+       for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+               if (p2p->wps_vendor_ext[i] == NULL)
+                       break;
+       }
+       if (i >= P2P_MAX_WPS_VENDOR_EXT)
+               return -1;
+
+       p2p->wps_vendor_ext[i] = wpabuf_dup(vendor_ext);
+       if (p2p->wps_vendor_ext[i] == NULL)
+               return -1;
+
+       return 0;
+}
+
+
+int p2p_set_country(struct p2p_data *p2p, const char *country)
+{
+       os_memcpy(p2p->cfg->country, country, 3);
+       return 0;
+}
+
+
+void p2p_continue_find(struct p2p_data *p2p)
+{
+       struct p2p_device *dev;
+       p2p_set_state(p2p, P2P_SEARCH);
+       dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+               if (dev->flags & P2P_DEV_SD_SCHEDULE) {
+                       if (p2p_start_sd(p2p, dev) == 0)
+                               return;
+                       else
+                               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 "
+                               MACSTR " (config methods 0x%x)",
+                               MAC2STR(dev->info.p2p_device_addr),
+                               dev->req_config_methods);
+                       if (p2p_send_prov_disc_req(p2p, dev, 0, 0) == 0)
+                               return;
+               }
+       }
+
+       p2p_listen_in_find(p2p);
+}
+
+
+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",
+               success);
+       p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
+       if (!success) {
+               if (p2p->sd_peer) {
+                       p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE;
+                       p2p->sd_peer = NULL;
+               }
+               p2p_continue_find(p2p);
+               return;
+       }
+
+       if (p2p->sd_peer == NULL) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: No SD peer entry known");
+               p2p_continue_find(p2p);
+               return;
+       }
+
+       /* Wait for response from the peer */
+       p2p_set_state(p2p, P2P_SD_DURING_FIND);
+       p2p_set_timeout(p2p, 0, 200000);
+}
+
+
+/**
+ * p2p_retry_pd - Retry any pending provision disc requests in IDLE state
+ * @p2p: P2P module context from p2p_init()
+ */
+static void p2p_retry_pd(struct p2p_data *p2p)
+{
+       struct p2p_device *dev;
+
+       if (p2p->state != P2P_IDLE)
+               return;
+
+       /*
+        * 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.
+        */
+
+       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)
+                       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 "
+                       MACSTR " (config methods 0x%x)",
+                       MAC2STR(dev->info.p2p_device_addr),
+                       dev->req_config_methods);
+               p2p_send_prov_disc_req(p2p, dev, 0, 0);
+               return;
+       }
+}
+
+
+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",
+               success);
+
+       /*
+        * Postpone resetting the pending action state till after we actually
+        * time out. This allows us to take some action like notifying any
+        * interested parties about no response to the request.
+        *
+        * When the timer (below) goes off we check in IDLE, SEARCH, or
+        * LISTEN_ONLY state, which are the only allowed states to issue a PD
+        * requests in, if this was still pending and then raise notification.
+        */
+
+       if (!success) {
+               p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
+               if (p2p->state != P2P_IDLE)
+                       p2p_continue_find(p2p);
+               else if (p2p->user_initiated_pd) {
+                       p2p->pending_action_state = P2P_PENDING_PD;
+                       p2p_set_timeout(p2p, 0, 300000);
+               }
+               return;
+       }
+
+       /*
+        * This postponing, of resetting pending_action_state, needs to be
+        * done only for user initiated PD requests and not internal ones.
+        */
+       if (p2p->user_initiated_pd)
+               p2p->pending_action_state = P2P_PENDING_PD;
+       else
+               p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
+       /* Wait for response from the peer */
+       if (p2p->state == P2P_SEARCH)
+               p2p_set_state(p2p, P2P_PD_DURING_FIND);
+       p2p_set_timeout(p2p, 0, 200000);
+}
+
+
+int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
+                        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;
+       }
+
+       return 0;
+}
+
+
+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->p2p_scan_running = 0;
+       eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
+
+       if (p2p_run_after_scan(p2p))
+               return;
+       if (p2p->state == P2P_SEARCH)
+               p2p_continue_find(p2p);
+}
+
+
+void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies)
+{
+       u8 *len = p2p_buf_add_ie_hdr(ies);
+       p2p_buf_add_capability(ies, p2p->dev_capab, 0);
+       if (p2p->cfg->reg_class && p2p->cfg->channel)
+               p2p_buf_add_listen_channel(ies, p2p->cfg->country,
+                                          p2p->cfg->reg_class,
+                                          p2p->cfg->channel);
+       if (p2p->ext_listen_interval)
+               p2p_buf_add_ext_listen_timing(ies, p2p->ext_listen_period,
+                                             p2p->ext_listen_interval);
+       /* TODO: p2p_buf_add_operating_channel() if GO */
+       p2p_buf_update_ie_hdr(ies, len);
+}
+
+
+size_t p2p_scan_ie_buf_len(struct p2p_data *p2p)
+{
+       return 100;
+}
+
+
+int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end)
+{
+       return p2p_attr_text(p2p_ie, buf, end);
+}
+
+
+static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success)
+{
+       struct p2p_device *dev = p2p->go_neg_peer;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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");
+               return;
+       }
+
+       if (success) {
+               dev->go_neg_req_sent++;
+               if (dev->flags & P2P_DEV_USER_REJECTED) {
+                       p2p_set_state(p2p, P2P_IDLE);
+                       return;
+               }
+       }
+
+       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",
+                       MAC2STR(dev->info.p2p_device_addr));
+               p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+               p2p_send_dev_disc_req(p2p, dev);
+               return;
+       }
+
+       /*
+        * Use P2P find, if needed, to find the other device from its listen
+        * channel.
+        */
+       p2p_set_state(p2p, P2P_CONNECT);
+       p2p_set_timeout(p2p, 0, 100000);
+}
+
+
+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",
+               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");
+               return;
+       }
+       p2p_set_state(p2p, P2P_CONNECT);
+       p2p_set_timeout(p2p, 0, 100000);
+}
+
+
+static void p2p_go_neg_resp_failure_cb(struct p2p_data *p2p, int success)
+{
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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);
+       }
+}
+
+
+static void p2p_go_neg_conf_cb(struct p2p_data *p2p,
+                              enum p2p_send_action_result result)
+{
+       struct p2p_device *dev;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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);
+               return;
+       }
+       if (result == P2P_SEND_ACTION_NO_ACK) {
+               /*
+                * It looks like the TX status for GO Negotiation Confirm is
+                * often showing failure even when the peer has actually
+                * received the frame. Since the peer may change channels
+                * immediately after having received the frame, we may not see
+                * an Ack for retries, so just dropping a single frame may
+                * trigger this. To allow the group formation to succeed if the
+                * 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");
+       }
+
+       dev = p2p->go_neg_peer;
+       if (dev == NULL)
+               return;
+
+       p2p_go_complete(p2p, dev);
+}
+
+
+void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
+                       const u8 *src, const u8 *bssid,
+                       enum p2p_send_action_result result)
+{
+       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
+               " src=" MACSTR " bssid=" MACSTR " result=%d",
+               p2p->pending_action_state, freq, MAC2STR(dst), MAC2STR(src),
+               MAC2STR(bssid), result);
+       success = result == P2P_SEND_ACTION_SUCCESS;
+       state = p2p->pending_action_state;
+       p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+       switch (state) {
+       case P2P_NO_PENDING_ACTION:
+               break;
+       case P2P_PENDING_GO_NEG_REQUEST:
+               p2p_go_neg_req_cb(p2p, success);
+               break;
+       case P2P_PENDING_GO_NEG_RESPONSE:
+               p2p_go_neg_resp_cb(p2p, success);
+               break;
+       case P2P_PENDING_GO_NEG_RESPONSE_FAILURE:
+               p2p_go_neg_resp_failure_cb(p2p, success);
+               break;
+       case P2P_PENDING_GO_NEG_CONFIRM:
+               p2p_go_neg_conf_cb(p2p, result);
+               break;
+       case P2P_PENDING_SD:
+               p2p_sd_cb(p2p, success);
+               break;
+       case P2P_PENDING_PD:
+               p2p_prov_disc_cb(p2p, success);
+               break;
+       case P2P_PENDING_INVITATION_REQUEST:
+               p2p_invitation_req_cb(p2p, success);
+               break;
+       case P2P_PENDING_INVITATION_RESPONSE:
+               p2p_invitation_resp_cb(p2p, success);
+               break;
+       case P2P_PENDING_DEV_DISC_REQUEST:
+               p2p_dev_disc_req_cb(p2p, success);
+               break;
+       case P2P_PENDING_DEV_DISC_RESPONSE:
+               p2p_dev_disc_resp_cb(p2p, success);
+               break;
+       case P2P_PENDING_GO_DISC_REQ:
+               p2p_go_disc_req_cb(p2p, success);
+               break;
+       }
+}
+
+
+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->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)",
+                       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->pending_listen_sec, p2p->pending_listen_usec,
+               p2p->pending_listen_freq);
+       p2p->in_listen = 1;
+       p2p->drv_in_listen = freq;
+       if (p2p->pending_listen_sec || p2p->pending_listen_usec) {
+               /*
+                * Add 20 msec extra wait to avoid race condition with driver
+                * remain-on-channel end event, i.e., give driver more time to
+                * complete the operation before our timeout expires.
+                */
+               p2p_set_timeout(p2p, p2p->pending_listen_sec,
+                               p2p->pending_listen_usec + 20000);
+       }
+
+       p2p->pending_listen_freq = 0;
+}
+
+
+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->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_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+                       return 0;
+               }
+
+               p2p_set_state(p2p, P2P_CONNECT);
+               p2p_connect_send(p2p, p2p->go_neg_peer);
+               return 1;
+       } else if (p2p->state == P2P_SEARCH) {
+               p2p_search(p2p);
+               return 1;
+       }
+
+       return 0;
+}
+
+
+static void p2p_timeout_connect(struct p2p_data *p2p)
+{
+       p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+       p2p_set_state(p2p, P2P_CONNECT_LISTEN);
+       p2p_listen_in_find(p2p);
+}
+
+
+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");
+                       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_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+                       return;
+               }
+
+               p2p_set_state(p2p, P2P_CONNECT);
+               p2p_connect_send(p2p, p2p->go_neg_peer);
+       } else
+               p2p_set_state(p2p, P2P_IDLE);
+}
+
+
+static void p2p_timeout_wait_peer_connect(struct p2p_data *p2p)
+{
+       /*
+        * TODO: could remain constantly in Listen state for some time if there
+        * are no other concurrent uses for the radio. For now, go to listen
+        * state once per second to give other uses a chance to use the radio.
+        */
+       p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
+       p2p_set_timeout(p2p, 0, 500000);
+}
+
+
+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");
+               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_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_set_state(p2p, P2P_WAIT_PEER_CONNECT);
+       p2p_listen_in_find(p2p);
+}
+
+
+static void p2p_timeout_sd_during_find(struct p2p_data *p2p)
+{
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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;
+               p2p->sd_peer = NULL;
+       }
+       p2p_continue_find(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->cfg->send_action_done(p2p->cfg->cb_ctx);
+       p2p_continue_find(p2p);
+}
+
+
+static void p2p_timeout_prov_disc_req(struct p2p_data *p2p)
+{
+       p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
+       /*
+        * For user initiated PD requests that we have not gotten any responses
+        * for while in IDLE state, we retry them a couple of times before
+        * giving up.
+        */
+       if (!p2p->user_initiated_pd)
+               return;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "P2P: User initiated Provision Discovery Request timeout");
+
+       if (p2p->pd_retries) {
+               p2p->pd_retries--;
+               p2p_retry_pd(p2p);
+       } else {
+               if (p2p->cfg->prov_disc_fail)
+                       p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx,
+                                                p2p->pending_pd_devaddr,
+                                                P2P_PROV_DISC_TIMEOUT);
+               p2p_reset_pending_pd(p2p);
+       }
+}
+
+
+static void p2p_timeout_invite(struct p2p_data *p2p)
+{
+       p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+       p2p_set_state(p2p, P2P_INVITE_LISTEN);
+       if (p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO) {
+               /*
+                * 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_set_timeout(p2p, 0, 100000);
+               return;
+       }
+       p2p_listen_in_find(p2p);
+}
+
+
+static void p2p_timeout_invite_listen(struct p2p_data *p2p)
+{
+       if (p2p->invite_peer && p2p->invite_peer->invitation_reqs < 100) {
+               p2p_set_state(p2p, P2P_INVITE);
+               p2p_invite_send(p2p, p2p->invite_peer,
+                               p2p->invite_go_dev_addr);
+       } else {
+               if (p2p->invite_peer) {
+                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                               "P2P: Invitation Request retry limit reached");
+                       if (p2p->cfg->invitation_result)
+                               p2p->cfg->invitation_result(
+                                       p2p->cfg->cb_ctx, -1, NULL);
+               }
+               p2p_set_state(p2p, P2P_IDLE);
+       }
+}
+
+
+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->in_listen = 0;
+
+       switch (p2p->state) {
+       case P2P_IDLE:
+               /* Check if we timed out waiting for PD req */
+               if (p2p->pending_action_state == P2P_PENDING_PD)
+                       p2p_timeout_prov_disc_req(p2p);
+               break;
+       case P2P_SEARCH:
+               /* Check if we timed out waiting for PD req */
+               if (p2p->pending_action_state == P2P_PENDING_PD)
+                       p2p_timeout_prov_disc_req(p2p);
+               p2p_search(p2p);
+               break;
+       case P2P_CONNECT:
+               p2p_timeout_connect(p2p);
+               break;
+       case P2P_CONNECT_LISTEN:
+               p2p_timeout_connect_listen(p2p);
+               break;
+       case P2P_GO_NEG:
+               break;
+       case P2P_LISTEN_ONLY:
+               /* 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->ext_listen_only) {
+                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                               "P2P: Extended Listen Timing - Listen State "
+                               "completed");
+                       p2p->ext_listen_only = 0;
+                       p2p_set_state(p2p, P2P_IDLE);
+               }
+               break;
+       case P2P_WAIT_PEER_CONNECT:
+               p2p_timeout_wait_peer_connect(p2p);
+               break;
+       case P2P_WAIT_PEER_IDLE:
+               p2p_timeout_wait_peer_idle(p2p);
+               break;
+       case P2P_SD_DURING_FIND:
+               p2p_timeout_sd_during_find(p2p);
+               break;
+       case P2P_PROVISIONING:
+               break;
+       case P2P_PD_DURING_FIND:
+               p2p_timeout_prov_disc_during_find(p2p);
+               break;
+       case P2P_INVITE:
+               p2p_timeout_invite(p2p);
+               break;
+       case P2P_INVITE_LISTEN:
+               p2p_timeout_invite_listen(p2p);
+               break;
+       case P2P_SEARCH_WHEN_READY:
+               break;
+       }
+}
+
+
+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));
+       if (dev == NULL) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
+                       " unknown", MAC2STR(peer_addr));
+               return -1;
+       }
+       dev->status = P2P_SC_FAIL_REJECTED_BY_USER;
+       dev->flags |= P2P_DEV_USER_REJECTED;
+       return 0;
+}
+
+
+const char * p2p_wps_method_text(enum p2p_wps_method method)
+{
+       switch (method) {
+       case WPS_NOT_READY:
+               return "not-ready";
+       case WPS_PIN_DISPLAY:
+               return "Display";
+       case WPS_PIN_KEYPAD:
+               return "Keypad";
+       case WPS_PBC:
+               return "PBC";
+       }
+
+       return "??";
+}
+
+
+static const char * p2p_go_state_text(enum p2p_go_state go_state)
+{
+       switch (go_state) {
+       case UNKNOWN_GO:
+               return "unknown";
+       case LOCAL_GO:
+               return "local";
+       case  REMOTE_GO:
+               return "remote";
+       }
+
+       return "??";
+}
+
+
+int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
+                     char *buf, size_t buflen)
+{
+       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);
+       else
+               dev = dl_list_first(&p2p->devices, struct p2p_device, list);
+
+       if (dev && next) {
+               dev = dl_list_first(&dev->list, struct p2p_device, list);
+               if (&dev->list == &p2p->devices)
+                       dev = NULL;
+       }
+
+       if (dev == NULL)
+               return -1;
+
+       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"
+                         "intended_addr=" MACSTR "\n"
+                         "country=%c%c\n"
+                         "oper_freq=%d\n"
+                         "req_config_methods=0x%x\n"
+                         "flags=%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n"
+                         "status=%d\n"
+                         "wait_count=%u\n"
+                         "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,
+                         MAC2STR(dev->intended_addr),
+                         dev->country[0] ? dev->country[0] : '_',
+                         dev->country[1] ? dev->country[1] : '_',
+                         dev->oper_freq,
+                         dev->req_config_methods,
+                         dev->flags & P2P_DEV_PROBE_REQ_ONLY ?
+                         "[PROBE_REQ_ONLY]" : "",
+                         dev->flags & P2P_DEV_REPORTED ? "[REPORTED]" : "",
+                         dev->flags & P2P_DEV_NOT_YET_READY ?
+                         "[NOT_YET_READY]" : "",
+                         dev->flags & P2P_DEV_SD_INFO ? "[SD_INFO]" : "",
+                         dev->flags & P2P_DEV_SD_SCHEDULE ? "[SD_SCHEDULE]" :
+                         "",
+                         dev->flags & P2P_DEV_PD_PEER_DISPLAY ?
+                         "[PD_PEER_DISPLAY]" : "",
+                         dev->flags & P2P_DEV_PD_PEER_KEYPAD ?
+                         "[PD_PEER_KEYPAD]" : "",
+                         dev->flags & P2P_DEV_USER_REJECTED ?
+                         "[USER_REJECTED]" : "",
+                         dev->flags & P2P_DEV_PEER_WAITING_RESPONSE ?
+                         "[PEER_WAITING_RESPONSE]" : "",
+                         dev->flags & P2P_DEV_PREFER_PERSISTENT_GROUP ?
+                         "[PREFER_PERSISTENT_GROUP]" : "",
+                         dev->flags & P2P_DEV_WAIT_GO_NEG_RESPONSE ?
+                         "[WAIT_GO_NEG_RESPONSE]" : "",
+                         dev->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM ?
+                         "[WAIT_GO_NEG_CONFIRM]" : "",
+                         dev->flags & P2P_DEV_GROUP_CLIENT_ONLY ?
+                         "[GROUP_CLIENT_ONLY]" : "",
+                         dev->flags & P2P_DEV_FORCE_FREQ ?
+                         "[FORCE_FREQ]" : "",
+                         dev->flags & P2P_DEV_PD_FOR_JOIN ?
+                         "[PD_FOR_JOIN]" : "",
+                         dev->status,
+                         dev->wait_count,
+                         dev->invitation_reqs);
+       if (res < 0 || res >= end - pos)
+               return pos - buf;
+       pos += res;
+
+       if (dev->ext_listen_period) {
+               res = os_snprintf(pos, end - pos,
+                                 "ext_listen_period=%u\n"
+                                 "ext_listen_interval=%u\n",
+                                 dev->ext_listen_period,
+                                 dev->ext_listen_interval);
+               if (res < 0 || res >= end - pos)
+                       return pos - buf;
+               pos += res;
+       }
+
+       if (dev->oper_ssid_len) {
+               res = os_snprintf(pos, end - pos,
+                                 "oper_ssid=%s\n",
+                                 wpa_ssid_txt(dev->oper_ssid,
+                                              dev->oper_ssid_len));
+               if (res < 0 || res >= end - pos)
+                       return pos - buf;
+               pos += res;
+       }
+
+       return pos - buf;
+}
+
+
+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->dev_capab |= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
+       } else {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Client "
+                       "discoverability disabled");
+               p2p->dev_capab &= ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
+       }
+}
+
+
+static struct wpabuf * p2p_build_presence_req(u32 duration1, u32 interval1,
+                                             u32 duration2, u32 interval2)
+{
+       struct wpabuf *req;
+       struct p2p_noa_desc desc1, desc2, *ptr1 = NULL, *ptr2 = NULL;
+       u8 *len;
+
+       req = wpabuf_alloc(100);
+       if (req == NULL)
+               return NULL;
+
+       if (duration1 || interval1) {
+               os_memset(&desc1, 0, sizeof(desc1));
+               desc1.count_type = 1;
+               desc1.duration = duration1;
+               desc1.interval = interval1;
+               ptr1 = &desc1;
+
+               if (duration2 || interval2) {
+                       os_memset(&desc2, 0, sizeof(desc2));
+                       desc2.count_type = 2;
+                       desc2.duration = duration2;
+                       desc2.interval = interval2;
+                       ptr2 = &desc2;
+               }
+       }
+
+       p2p_buf_add_action_hdr(req, P2P_PRESENCE_REQ, 1);
+       len = p2p_buf_add_ie_hdr(req);
+       p2p_buf_add_noa(req, 0, 0, 0, ptr1, ptr2);
+       p2p_buf_update_ie_hdr(req, len);
+
+       return req;
+}
+
+
+int p2p_presence_req(struct p2p_data *p2p, const u8 *go_interface_addr,
+                    const u8 *own_interface_addr, unsigned int freq,
+                    u32 duration1, u32 interval1, u32 duration2,
+                    u32 interval2)
+{
+       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",
+               MAC2STR(go_interface_addr), MAC2STR(own_interface_addr),
+               freq, duration1, interval1, duration2, interval2);
+
+       req = p2p_build_presence_req(duration1, interval1, duration2,
+                                    interval2);
+       if (req == NULL)
+               return -1;
+
+       p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+       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");
+       }
+       wpabuf_free(req);
+
+       return 0;
+}
+
+
+static struct wpabuf * p2p_build_presence_resp(u8 status, const u8 *noa,
+                                              size_t noa_len, u8 dialog_token)
+{
+       struct wpabuf *resp;
+       u8 *len;
+
+       resp = wpabuf_alloc(100 + noa_len);
+       if (resp == NULL)
+               return NULL;
+
+       p2p_buf_add_action_hdr(resp, P2P_PRESENCE_RESP, dialog_token);
+       len = p2p_buf_add_ie_hdr(resp);
+       p2p_buf_add_status(resp, status);
+       if (noa) {
+               wpabuf_put_u8(resp, P2P_ATTR_NOTICE_OF_ABSENCE);
+               wpabuf_put_le16(resp, noa_len);
+               wpabuf_put_data(resp, noa, noa_len);
+       } else
+               p2p_buf_add_noa(resp, 0, 0, 0, NULL, NULL);
+       p2p_buf_update_ie_hdr(resp, len);
+
+       return resp;
+}
+
+
+static void p2p_process_presence_req(struct p2p_data *p2p, const u8 *da,
+                                    const u8 *sa, const u8 *data, size_t len,
+                                    int rx_freq)
+{
+       struct p2p_message msg;
+       u8 status;
+       struct wpabuf *resp;
+       size_t g;
+       struct p2p_group *group = NULL;
+       int parsed = 0;
+       u8 noa[50];
+       int noa_len;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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]),
+                             ETH_ALEN) == 0) {
+                       group = p2p->groups[g];
+                       break;
+               }
+       }
+       if (group == NULL) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "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");
+               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");
+               status = P2P_SC_FAIL_INVALID_PARAMS;
+               goto fail;
+       }
+
+       status = p2p_group_presence_req(group, sa, msg.noa, msg.noa_len);
+
+fail:
+       if (p2p->cfg->get_noa)
+               noa_len = p2p->cfg->get_noa(p2p->cfg->cb_ctx, da, noa,
+                                           sizeof(noa));
+       else
+               noa_len = -1;
+       resp = p2p_build_presence_resp(status, noa_len > 0 ? noa : NULL,
+                                      noa_len > 0 ? noa_len : 0,
+                                      msg.dialog_token);
+       if (parsed)
+               p2p_parse_free(&msg);
+       if (resp == NULL)
+               return;
+
+       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");
+       }
+       wpabuf_free(resp);
+}
+
+
+static void p2p_process_presence_resp(struct p2p_data *p2p, const u8 *da,
+                                     const u8 *sa, const u8 *data, size_t len)
+{
+       struct p2p_message msg;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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");
+               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_parse_free(&msg);
+               return;
+       }
+
+       if (*msg.status) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "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");
+       wpa_hexdump(MSG_DEBUG, "P2P: P2P Presence Response - NoA",
+                   msg.noa, msg.noa_len);
+       /* TODO: process NoA */
+       p2p_parse_free(&msg);
+}
+
+
+static void p2p_ext_listen_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct p2p_data *p2p = eloop_ctx;
+
+       if (p2p->ext_listen_interval) {
+               /* Schedule next extended listen timeout */
+               eloop_register_timeout(p2p->ext_listen_interval_sec,
+                                      p2p->ext_listen_interval_usec,
+                                      p2p_ext_listen_timeout, p2p, NULL);
+       }
+
+       if (p2p->state == P2P_LISTEN_ONLY && p2p->ext_listen_only) {
+               /*
+                * This should not really happen, but it looks like the Listen
+                * command may fail is something else (e.g., a scan) was
+                * 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->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));
+               return;
+       }
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "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->ext_listen_only = 0;
+       }
+}
+
+
+int p2p_ext_listen(struct p2p_data *p2p, unsigned int period,
+                  unsigned int interval)
+{
+       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);
+               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->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->ext_listen_period = period;
+       p2p->ext_listen_interval = interval;
+       p2p->ext_listen_interval_sec = interval / 1000;
+       p2p->ext_listen_interval_usec = (interval % 1000) * 1000;
+
+       eloop_register_timeout(p2p->ext_listen_interval_sec,
+                              p2p->ext_listen_interval_usec,
+                              p2p_ext_listen_timeout, p2p, NULL);
+
+       return 0;
+}
+
+
+void p2p_deauth_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code,
+                     const u8 *ie, size_t ie_len)
+{
+       struct p2p_message msg;
+
+       if (bssid == NULL || ie == NULL)
+               return;
+
+       os_memset(&msg, 0, sizeof(msg));
+       if (p2p_parse_ies(ie, ie_len, &msg))
+               return;
+       if (msg.minor_reason_code == NULL)
+               return;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
+               "P2P: Deauthentication notification BSSID " MACSTR
+               " reason_code=%u minor_reason_code=%u",
+               MAC2STR(bssid), reason_code, *msg.minor_reason_code);
+
+       p2p_parse_free(&msg);
+}
+
+
+void p2p_disassoc_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code,
+                       const u8 *ie, size_t ie_len)
+{
+       struct p2p_message msg;
+
+       if (bssid == NULL || ie == NULL)
+               return;
+
+       os_memset(&msg, 0, sizeof(msg));
+       if (p2p_parse_ies(ie, ie_len, &msg))
+               return;
+       if (msg.minor_reason_code == NULL)
+               return;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
+               "P2P: Disassociation notification BSSID " MACSTR
+               " reason_code=%u minor_reason_code=%u",
+               MAC2STR(bssid), reason_code, *msg.minor_reason_code);
+
+       p2p_parse_free(&msg);
+}
+
+
+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->dev_capab |= P2P_DEV_CAPAB_INFRA_MANAGED;
+       } else {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Managed P2P "
+                       "Device operations disabled");
+               p2p->dev_capab &= ~P2P_DEV_CAPAB_INFRA_MANAGED;
+       }
+}
+
+
+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)
+               return -1;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Set Listen channel: "
+               "reg_class %u channel %u", reg_class, channel);
+       p2p->cfg->reg_class = reg_class;
+       p2p->cfg->channel = channel;
+
+       return 0;
+}
+
+
+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);
+       if (postfix == NULL) {
+               p2p->cfg->ssid_postfix_len = 0;
+               return 0;
+       }
+       if (len > sizeof(p2p->cfg->ssid_postfix))
+               return -1;
+       os_memcpy(p2p->cfg->ssid_postfix, postfix, len);
+       p2p->cfg->ssid_postfix_len = len;
+       return 0;
+}
+
+
+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)
+               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->cfg->op_reg_class = op_reg_class;
+       p2p->cfg->op_channel = op_channel;
+       p2p->cfg->cfg_op_channel = cfg_op_channel;
+       return 0;
+}
+
+
+int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
+                          u8 *iface_addr)
+{
+       struct p2p_device *dev = p2p_get_device(p2p, dev_addr);
+       if (dev == NULL || is_zero_ether_addr(dev->interface_addr))
+               return -1;
+       os_memcpy(iface_addr, dev->interface_addr, ETH_ALEN);
+       return 0;
+}
+
+
+int p2p_get_dev_addr(struct p2p_data *p2p, const u8 *iface_addr,
+                          u8 *dev_addr)
+{
+       struct p2p_device *dev = p2p_get_device_interface(p2p, iface_addr);
+       if (dev == NULL)
+               return -1;
+       os_memcpy(dev_addr, dev->info.p2p_device_addr, ETH_ALEN);
+       return 0;
+}
+
+
+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");
+       else
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "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");
+       if (p2p->cross_connect == enabled)
+               return;
+       p2p->cross_connect = enabled;
+       /* TODO: may need to tear down any action group where we are GO(?) */
+}
+
+
+int p2p_get_oper_freq(struct p2p_data *p2p, const u8 *iface_addr)
+{
+       struct p2p_device *dev = p2p_get_device_interface(p2p, iface_addr);
+       if (dev == NULL)
+               return -1;
+       if (dev->oper_freq <= 0)
+               return -1;
+       return dev->oper_freq;
+}
+
+
+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",
+               enabled ? "enabled" : "disabled");
+       p2p->cfg->p2p_intra_bss = 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");
+       os_memcpy(&p2p->cfg->channels, chan, sizeof(struct p2p_channels));
+}
+
+
+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)
+{
+       if (p2p->p2p_scan_running) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "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");
+                       os_free(p2p->after_scan_tx);
+               }
+               p2p->after_scan_tx = os_malloc(sizeof(*p2p->after_scan_tx) +
+                                              len);
+               if (p2p->after_scan_tx == NULL)
+                       return -1;
+               p2p->after_scan_tx->freq = freq;
+               os_memcpy(p2p->after_scan_tx->dst, dst, ETH_ALEN);
+               os_memcpy(p2p->after_scan_tx->src, src, ETH_ALEN);
+               os_memcpy(p2p->after_scan_tx->bssid, bssid, ETH_ALEN);
+               p2p->after_scan_tx->len = len;
+               p2p->after_scan_tx->wait_time = wait_time;
+               os_memcpy(p2p->after_scan_tx + 1, buf, len);
+               return 0;
+       }
+
+       return p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, dst, src, bssid,
+                                    buf, len, wait_time);
+}
+
+
+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->best_freq_24 = freq_24;
+       p2p->best_freq_5 = freq_5;
+       p2p->best_freq_overall = freq_overall;
+}
+
+
+const u8 * p2p_get_go_neg_peer(struct p2p_data *p2p)
+{
+       if (p2p == NULL || p2p->go_neg_peer == NULL)
+               return NULL;
+       return p2p->go_neg_peer->info.p2p_device_addr;
+}
+
+
+const struct p2p_peer_info *
+p2p_get_peer_found(struct p2p_data *p2p, const u8 *addr, int next)
+{
+       struct p2p_device *dev;
+
+       if (addr) {
+               dev = p2p_get_device(p2p, addr);
+               if (!dev)
+                       return NULL;
+
+               if (!next) {
+                       if (dev->flags & P2P_DEV_PROBE_REQ_ONLY)
+                               return NULL;
+
+                       return &dev->info;
+               } else {
+                       do {
+                               dev = dl_list_first(&dev->list,
+                                                   struct p2p_device,
+                                                   list);
+                               if (&dev->list == &p2p->devices)
+                                       return NULL;
+                       } while (dev->flags & P2P_DEV_PROBE_REQ_ONLY);
+               }
+       } else {
+               dev = dl_list_first(&p2p->devices, struct p2p_device, list);
+               if (!dev)
+                       return NULL;
+               while (dev->flags & P2P_DEV_PROBE_REQ_ONLY) {
+                       dev = dl_list_first(&dev->list,
+                                           struct p2p_device,
+                                           list);
+                       if (&dev->list == &p2p->devices)
+                               return NULL;
+               }
+       }
+
+       return &dev->info;
+}
+
+
+int p2p_in_progress(struct p2p_data *p2p)
+{
+       if (p2p == NULL)
+               return 0;
+       return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING;
+}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
new file mode 100644 (file)
index 0000000..6a640ab
--- /dev/null
@@ -0,0 +1,1580 @@
+/*
+ * 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.
+ */
+
+#ifndef P2P_H
+#define P2P_H
+
+/**
+ * P2P_MAX_REG_CLASSES - Maximum number of regulatory classes
+ */
+#define P2P_MAX_REG_CLASSES 10
+
+/**
+ * P2P_MAX_REG_CLASS_CHANNELS - Maximum number of channels per regulatory class
+ */
+#define P2P_MAX_REG_CLASS_CHANNELS 20
+
+/**
+ * struct p2p_channels - List of supported channels
+ */
+struct p2p_channels {
+       /**
+        * struct p2p_reg_class - Supported regulatory class
+        */
+       struct p2p_reg_class {
+               /**
+                * reg_class - Regulatory class (IEEE 802.11-2007, Annex J)
+                */
+               u8 reg_class;
+
+               /**
+                * channel - Supported channels
+                */
+               u8 channel[P2P_MAX_REG_CLASS_CHANNELS];
+
+               /**
+                * channels - Number of channel entries in use
+                */
+               size_t channels;
+       } reg_class[P2P_MAX_REG_CLASSES];
+
+       /**
+        * reg_classes - Number of reg_class entries in use
+        */
+       size_t reg_classes;
+};
+
+enum p2p_wps_method {
+       WPS_NOT_READY, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC
+};
+
+/**
+ * struct p2p_go_neg_results - P2P Group Owner Negotiation results
+ */
+struct p2p_go_neg_results {
+       /**
+        * status - Negotiation result (Status Code)
+        *
+        * 0 (P2P_SC_SUCCESS) indicates success. Non-zero values indicate
+        * failed negotiation.
+        */
+       int status;
+
+       /**
+        * role_go - Whether local end is Group Owner
+        */
+       int role_go;
+
+       /**
+        * freq - Frequency of the group operational channel in MHz
+        */
+       int freq;
+
+       /**
+        * ssid - SSID of the group
+        */
+       u8 ssid[32];
+
+       /**
+        * ssid_len - Length of SSID in octets
+        */
+       size_t ssid_len;
+
+       /**
+        * passphrase - WPA2-Personal passphrase for the group (GO only)
+        */
+       char passphrase[64];
+
+       /**
+        * peer_device_addr - P2P Device Address of the peer
+        */
+       u8 peer_device_addr[ETH_ALEN];
+
+       /**
+        * peer_interface_addr - P2P Interface Address of the peer
+        */
+       u8 peer_interface_addr[ETH_ALEN];
+
+       /**
+        * wps_method - WPS method to be used during provisioning
+        */
+       enum p2p_wps_method wps_method;
+
+#define P2P_MAX_CHANNELS 50
+
+       /**
+        * freq_list - Zero-terminated list of possible operational channels
+        */
+       int freq_list[P2P_MAX_CHANNELS];
+
+       /**
+        * persistent_group - Whether the group should be made persistent
+        * 0 = not persistent
+        * 1 = persistent group without persistent reconnect
+        * 2 = persistent group with persistent reconnect
+        */
+       int persistent_group;
+
+       /**
+        * peer_config_timeout - Peer configuration timeout (in 10 msec units)
+        */
+       unsigned int peer_config_timeout;
+};
+
+struct p2p_data;
+
+enum p2p_scan_type {
+       P2P_SCAN_SOCIAL,
+       P2P_SCAN_FULL,
+       P2P_SCAN_SPECIFIC,
+       P2P_SCAN_SOCIAL_PLUS_ONE
+};
+
+#define P2P_MAX_WPS_VENDOR_EXT 10
+
+/**
+ * struct p2p_peer_info - P2P peer information
+ */
+struct p2p_peer_info {
+       /**
+        * p2p_device_addr - P2P Device Address of the peer
+        */
+       u8 p2p_device_addr[ETH_ALEN];
+
+       /**
+        * pri_dev_type - Primary Device Type
+        */
+       u8 pri_dev_type[8];
+
+       /**
+        * device_name - Device Name (0..32 octets encoded in UTF-8)
+        */
+       char device_name[33];
+
+       /**
+        * manufacturer - Manufacturer (0..64 octets encoded in UTF-8)
+        */
+       char manufacturer[65];
+
+       /**
+        * model_name - Model Name (0..32 octets encoded in UTF-8)
+        */
+       char model_name[33];
+
+       /**
+        * model_number - Model Number (0..32 octets encoded in UTF-8)
+        */
+       char model_number[33];
+
+       /**
+        * serial_number - Serial Number (0..32 octets encoded in UTF-8)
+        */
+       char serial_number[33];
+
+       /**
+        * level - Signal level
+        */
+       int level;
+
+       /**
+        * config_methods - WPS Configuration Methods
+        */
+       u16 config_methods;
+
+       /**
+        * dev_capab - Device Capabilities
+        */
+       u8 dev_capab;
+
+       /**
+        * group_capab - Group Capabilities
+        */
+       u8 group_capab;
+
+       /**
+        * wps_sec_dev_type_list - WPS secondary device type list
+        *
+        * This list includes from 0 to 16 Secondary Device Types as indicated
+        * by wps_sec_dev_type_list_len (8 * number of types).
+        */
+       u8 wps_sec_dev_type_list[128];
+
+       /**
+        * wps_sec_dev_type_list_len - Length of secondary device type list
+        */
+       size_t wps_sec_dev_type_list_len;
+
+       struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
+};
+
+enum p2p_prov_disc_status {
+       P2P_PROV_DISC_SUCCESS,
+       P2P_PROV_DISC_TIMEOUT,
+       P2P_PROV_DISC_REJECTED,
+};
+
+/**
+ * struct p2p_config - P2P configuration
+ *
+ * This configuration is provided to the P2P module during initialization with
+ * p2p_init().
+ */
+struct p2p_config {
+       /**
+        * country - Country code to use in P2P operations
+        */
+       char country[3];
+
+       /**
+        * reg_class - Regulatory class for own listen channel
+        */
+       u8 reg_class;
+
+       /**
+        * channel - Own listen channel
+        */
+       u8 channel;
+
+       /**
+        * Regulatory class for own operational channel
+        */
+       u8 op_reg_class;
+
+       /**
+        * op_channel - Own operational channel
+        */
+       u8 op_channel;
+
+       /**
+        * cfg_op_channel - Whether op_channel is hardcoded in configuration
+        */
+       u8 cfg_op_channel;
+
+       /**
+        * channels - Own supported regulatory classes and channels
+        *
+        * List of supposerted channels per regulatory class. The regulatory
+        * classes are defined in IEEE Std 802.11-2007 Annex J and the
+        * numbering of the clases depends on the configured country code.
+        */
+       struct p2p_channels channels;
+
+       /**
+        * pri_dev_type - Primary Device Type (see WPS)
+        */
+       u8 pri_dev_type[8];
+
+       /**
+        * P2P_SEC_DEVICE_TYPES - Maximum number of secondary device types
+        */
+#define P2P_SEC_DEVICE_TYPES 5
+
+       /**
+        * sec_dev_type - Optional secondary device types
+        */
+       u8 sec_dev_type[P2P_SEC_DEVICE_TYPES][8];
+
+       /**
+        * num_sec_dev_types - Number of sec_dev_type entries
+        */
+       size_t num_sec_dev_types;
+
+       /**
+        * dev_addr - P2P Device Address
+        */
+       u8 dev_addr[ETH_ALEN];
+
+       /**
+        * dev_name - Device Name
+        */
+       char *dev_name;
+
+       char *manufacturer;
+       char *model_name;
+       char *model_number;
+       char *serial_number;
+
+       u8 uuid[16];
+       u16 config_methods;
+
+       /**
+        * concurrent_operations - Whether concurrent operations are supported
+        */
+       int concurrent_operations;
+
+       /**
+        * max_peers - Maximum number of discovered peers to remember
+        *
+        * If more peers are discovered, older entries will be removed to make
+        * room for the new ones.
+        */
+       size_t max_peers;
+
+       /**
+        * p2p_intra_bss - Intra BSS communication is supported
+        */
+       int p2p_intra_bss;
+
+       /**
+        * ssid_postfix - Postfix data to add to the SSID
+        *
+        * This data will be added to the end of the SSID after the
+        * DIRECT-<random two octets> prefix.
+        */
+       u8 ssid_postfix[32 - 9];
+
+       /**
+        * ssid_postfix_len - Length of the ssid_postfix data
+        */
+       size_t ssid_postfix_len;
+
+       /**
+        * msg_ctx - Context to use with wpa_msg() calls
+        */
+       void *msg_ctx;
+
+       /**
+        * cb_ctx - Context to use with callback functions
+        */
+       void *cb_ctx;
+
+
+       /* Callbacks to request lower layer driver operations */
+
+       /**
+        * p2p_scan - Request a P2P scan/search
+        * @ctx: Callback context from cb_ctx
+        * @type: Scan type
+        * @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
+        * 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.
+        * @P2P_SCAN_SOCIAL_PLUS_ONE request scan of all the social channels
+        * plus one extra channel specified by freq.
+        *
+        * The full scan is used for the initial scan to find group owners from
+        * all. The other types are used during search phase scan of the social
+        * channels (with potential variation if the Listen channel of the
+        * target peer is known or if other channels are scanned in steps).
+        *
+        * The scan results are returned after this call by calling
+        * p2p_scan_res_handler() for each scan result that has a P2P IE and
+        * then calling p2p_scan_res_handled() to indicate that all scan
+        * results have been indicated.
+        */
+       int (*p2p_scan)(void *ctx, enum p2p_scan_type type, int freq,
+                       unsigned int num_req_dev_types,
+                       const u8 *req_dev_types);
+
+       /**
+        * send_probe_resp - Transmit a Probe Response frame
+        * @ctx: Callback context from cb_ctx
+        * @buf: Probe Response frame (including the header and body)
+        * Returns: 0 on success, -1 on failure
+        *
+        * This function is used to reply to Probe Request frames that were
+        * indicated with a call to p2p_probe_req_rx(). The response is to be
+        * sent on the same channel or to be dropped if the driver is not
+        * anymore listening to Probe Request frames.
+        *
+        * Alternatively, the responsibility for building the Probe Response
+        * frames in Listen state may be in another system component in which
+        * case this function need to be implemented (i.e., the function
+        * pointer can be %NULL). The WPS and P2P IEs to be added for Probe
+        * Response frames in such a case are available from the
+        * start_listen() callback. It should be noted that the received Probe
+        * Request frames must be indicated by calling p2p_probe_req_rx() even
+        * if this send_probe_resp() is not used.
+        */
+       int (*send_probe_resp)(void *ctx, const struct wpabuf *buf);
+
+       /**
+        * send_action - Transmit an Action frame
+        * @ctx: Callback context from cb_ctx
+        * @freq: Frequency in MHz for the channel on which to transmit
+        * @dst: Destination MAC address (Address 1)
+        * @src: Source MAC address (Address 2)
+        * @bssid: BSSID (Address 3)
+        * @buf: Frame body (starting from Category field)
+        * @len: Length of buf in octets
+        * @wait_time: How many msec to wait for a response frame
+        * Returns: 0 on success, -1 on failure
+        *
+        * The Action frame may not be transmitted immediately and the status
+        * of the transmission must be reported by calling
+        * p2p_send_action_cb() once the frame has either been transmitted or
+        * it has been dropped due to excessive retries or other failure to
+        * transmit.
+        */
+       int (*send_action)(void *ctx, unsigned int freq, const u8 *dst,
+                          const u8 *src, const u8 *bssid, const u8 *buf,
+                          size_t len, unsigned int wait_time);
+
+       /**
+        * send_action_done - Notify that Action frame sequence was completed
+        * @ctx: Callback context from cb_ctx
+        *
+        * This function is called when the Action frame sequence that was
+        * started with send_action() has been completed, i.e., when there is
+        * no need to wait for a response from the destination peer anymore.
+        */
+       void (*send_action_done)(void *ctx);
+
+       /**
+        * start_listen - Start Listen state
+        * @ctx: Callback context from cb_ctx
+        * @freq: Frequency of the listen channel in MHz
+        * @duration: Duration for the Listen state in milliseconds
+        * @probe_resp_ie: IE(s) to be added to Probe Response frames
+        * Returns: 0 on success, -1 on failure
+        *
+        * This Listen state may not start immediately since the driver may
+        * have other pending operations to complete first. Once the Listen
+        * state has started, p2p_listen_cb() must be called to notify the P2P
+        * module. Once the Listen state is stopped, p2p_listen_end() must be
+        * called to notify the P2P module that the driver is not in the Listen
+        * state anymore.
+        *
+        * If the send_probe_resp() is not used for generating the response,
+        * the IEs from probe_resp_ie need to be added to the end of the Probe
+        * Response frame body. If send_probe_resp() is used, the probe_resp_ie
+        * information can be ignored.
+        */
+       int (*start_listen)(void *ctx, unsigned int freq,
+                           unsigned int duration,
+                           const struct wpabuf *probe_resp_ie);
+       /**
+        * stop_listen - Stop Listen state
+        * @ctx: Callback context from cb_ctx
+        *
+        * This callback can be used to stop a Listen state operation that was
+        * previously requested with start_listen().
+        */
+       void (*stop_listen)(void *ctx);
+
+       /**
+        * get_noa - Get current Notice of Absence attribute payload
+        * @ctx: Callback context from cb_ctx
+        * @interface_addr: P2P Interface Address of the GO
+        * @buf: Buffer for returning NoA
+        * @buf_len: Buffer length in octets
+        * Returns: Number of octets used in buf, 0 to indicate no NoA is being
+        * advertized, or -1 on failure
+        *
+        * This function is used to fetch the current Notice of Absence
+        * attribute value from GO.
+        */
+       int (*get_noa)(void *ctx, const u8 *interface_addr, u8 *buf,
+                      size_t buf_len);
+
+       /* Callbacks to notify events to upper layer management entity */
+
+       /**
+        * dev_found - Notification of a found P2P Device
+        * @ctx: Callback context from cb_ctx
+        * @addr: Source address of the message triggering this notification
+        * @info: P2P peer information
+        * @new_device: Inform if the peer is newly found
+        *
+        * This callback is used to notify that a new P2P Device has been
+        * found. This may happen, e.g., during Search state based on scan
+        * results or during Listen state based on receive Probe Request and
+        * Group Owner Negotiation Request.
+        */
+       void (*dev_found)(void *ctx, const u8 *addr,
+                         const struct p2p_peer_info *info,
+                         int new_device);
+
+       /**
+        * dev_lost - Notification of a lost P2P Device
+        * @ctx: Callback context from cb_ctx
+        * @dev_addr: P2P Device Address of the lost P2P Device
+        *
+        * This callback is used to notify that a P2P Device has been deleted.
+        */
+       void (*dev_lost)(void *ctx, const u8 *dev_addr);
+
+       /**
+        * 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
+        * @dev_passwd_id: WPS Device Password ID
+        *
+        * This callback is used to notify that a P2P Device is requesting
+        * group owner negotiation with us, but we do not have all the
+        * necessary information to start GO Negotiation. This indicates that
+        * the local user has not authorized the connection yet by providing a
+        * PIN or PBC button press. This information can be provided with a
+        * call to p2p_connect().
+        */
+       void (*go_neg_req_rx)(void *ctx, const u8 *src, u16 dev_passwd_id);
+
+       /**
+        * go_neg_completed - Notification of GO Negotiation results
+        * @ctx: Callback context from cb_ctx
+        * @res: GO Negotiation results
+        *
+        * This callback is used to notify that Group Owner Negotiation has
+        * been completed. Non-zero struct p2p_go_neg_results::status indicates
+        * failed negotiation. In case of success, this function is responsible
+        * for creating a new group interface (or using the existing interface
+        * depending on driver features), setting up the group interface in
+        * proper mode based on struct p2p_go_neg_results::role_go and
+        * initializing WPS provisioning either as a Registrar (if GO) or as an
+        * Enrollee. Successful WPS provisioning must be indicated by calling
+        * p2p_wps_success_cb(). The callee is responsible for timing out group
+        * formation if WPS provisioning cannot be completed successfully
+        * within 15 seconds.
+        */
+       void (*go_neg_completed)(void *ctx, struct p2p_go_neg_results *res);
+
+       /**
+        * sd_request - Callback on Service Discovery Request
+        * @ctx: Callback context from cb_ctx
+        * @freq: Frequency (in MHz) of the channel
+        * @sa: Source address of the request
+        * @dialog_token: Dialog token
+        * @update_indic: Service Update Indicator from the source of request
+        * @tlvs: P2P Service Request TLV(s)
+        * @tlvs_len: Length of tlvs buffer in octets
+        *
+        * This callback is used to indicate reception of a service discovery
+        * request. Response to the query must be indicated by calling
+        * p2p_sd_response() with the context information from the arguments to
+        * this callback function.
+        *
+        * This callback handler can be set to %NULL to indicate that service
+        * discovery is not supported.
+        */
+       void (*sd_request)(void *ctx, int freq, const u8 *sa, u8 dialog_token,
+                          u16 update_indic, const u8 *tlvs, size_t tlvs_len);
+
+       /**
+        * sd_response - Callback on Service Discovery Response
+        * @ctx: Callback context from cb_ctx
+        * @sa: Source address of the request
+        * @update_indic: Service Update Indicator from the source of response
+        * @tlvs: P2P Service Response TLV(s)
+        * @tlvs_len: Length of tlvs buffer in octets
+        *
+        * This callback is used to indicate reception of a service discovery
+        * response. This callback handler can be set to %NULL if no service
+        * discovery requests are used. The information provided with this call
+        * is replies to the queries scheduled with p2p_sd_request().
+        */
+       void (*sd_response)(void *ctx, const u8 *sa, u16 update_indic,
+                           const u8 *tlvs, size_t tlvs_len);
+
+       /**
+        * prov_disc_req - Callback on Provisiong Discovery Request
+        * @ctx: Callback context from cb_ctx
+        * @peer: Source address of the request
+        * @config_methods: Requested WPS Config Method
+        * @dev_addr: P2P Device Address of the found P2P Device
+        * @pri_dev_type: Primary Device Type
+        * @dev_name: Device Name
+        * @supp_config_methods: Supported configuration Methods
+        * @dev_capab: Device Capabilities
+        * @group_capab: Group Capabilities
+        * @group_id: P2P Group ID (or %NULL if not included)
+        * @group_id_len: Length of P2P Group ID
+        *
+        * This callback is used to indicate reception of a Provision Discovery
+        * Request frame that the P2P module accepted.
+        */
+       void (*prov_disc_req)(void *ctx, const u8 *peer, u16 config_methods,
+                             const u8 *dev_addr, const u8 *pri_dev_type,
+                             const char *dev_name, u16 supp_config_methods,
+                             u8 dev_capab, u8 group_capab,
+                             const u8 *group_id, size_t group_id_len);
+
+       /**
+        * prov_disc_resp - Callback on Provisiong Discovery Response
+        * @ctx: Callback context from cb_ctx
+        * @peer: Source address of the response
+        * @config_methods: Value from p2p_prov_disc_req() or 0 on failure
+        *
+        * This callback is used to indicate reception of a Provision Discovery
+        * Response frame for a pending request scheduled with
+        * p2p_prov_disc_req(). This callback handler can be set to %NULL if
+        * provision discovery is not used.
+        */
+       void (*prov_disc_resp)(void *ctx, const u8 *peer, u16 config_methods);
+
+       /**
+        * prov_disc_fail - Callback on Provision Discovery failure
+        * @ctx: Callback context from cb_ctx
+        * @peer: Source address of the response
+        * @status: Cause of failure, will not be %P2P_PROV_DISC_SUCCESS
+        *
+        * This callback is used to indicate either a failure or no response
+        * to an earlier provision discovery request.
+        *
+        * This callback handler can be set to %NULL if provision discovery
+        * is not used or failures do not need to be indicated.
+        */
+       void (*prov_disc_fail)(void *ctx, const u8 *peer,
+                              enum p2p_prov_disc_status status);
+
+       /**
+        * invitation_process - Optional callback for processing Invitations
+        * @ctx: Callback context from cb_ctx
+        * @sa: Source address of the Invitation Request
+        * @bssid: P2P Group BSSID from the request or %NULL if not included
+        * @go_dev_addr: GO Device Address from P2P Group ID
+        * @ssid: SSID from P2P Group ID
+        * @ssid_len: Length of ssid buffer in octets
+        * @go: Variable for returning whether the local end is GO in the group
+        * @group_bssid: Buffer for returning P2P Group BSSID (if local end GO)
+        * @force_freq: Variable for returning forced frequency for the group
+        * @persistent_group: Whether this is an invitation to reinvoke a
+        *      persistent group (instead of invitation to join an active
+        *      group)
+        * Returns: Status code (P2P_SC_*)
+        *
+        * This optional callback can be used to implement persistent reconnect
+        * by allowing automatic restarting of persistent groups without user
+        * interaction. If this callback is not implemented (i.e., is %NULL),
+        * the received Invitation Request frames are replied with
+        * %P2P_SC_REQ_RECEIVED status and indicated to upper layer with the
+        * invitation_result() callback.
+        *
+        * If the requested parameters are acceptable and the group is known,
+        * %P2P_SC_SUCCESS may be returned. If the requested group is unknown,
+        * %P2P_SC_FAIL_UNKNOWN_GROUP should be returned. %P2P_SC_REQ_RECEIVED
+        * can be returned if there is not enough data to provide immediate
+        * response, i.e., if some sort of user interaction is needed. The
+        * invitation_received() callback will be called in that case
+        * immediately after this call.
+        */
+       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);
+
+       /**
+        * invitation_received - Callback on Invitation Request RX
+        * @ctx: Callback context from cb_ctx
+        * @sa: Source address of the Invitation Request
+        * @bssid: P2P Group BSSID or %NULL if not received
+        * @ssid: SSID of the group
+        * @ssid_len: Length of ssid in octets
+        * @go_dev_addr: GO Device Address
+        * @status: Response Status
+        * @op_freq: Operational frequency for the group
+        *
+        * This callback is used to indicate sending of an Invitation Response
+        * for a received Invitation Request. If status == 0 (success), the
+        * upper layer code is responsible for starting the group. status == 1
+        * indicates need to get user authorization for the group. Other status
+        * values indicate that the invitation request was rejected.
+        */
+       void (*invitation_received)(void *ctx, const u8 *sa, const u8 *bssid,
+                                   const u8 *ssid, size_t ssid_len,
+                                   const u8 *go_dev_addr, u8 status,
+                                   int op_freq);
+
+       /**
+        * invitation_result - Callback on Invitation result
+        * @ctx: Callback context from cb_ctx
+        * @status: Negotiation result (Status Code)
+        * @bssid: P2P Group BSSID or %NULL if not received
+        *
+        * This callback is used to indicate result of an Invitation procedure
+        * started with a call to p2p_invite(). The indicated status code is
+        * the value received from the peer in Invitation Response with 0
+        * (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);
+};
+
+
+/* P2P module initialization/deinitialization */
+
+/**
+ * p2p_init - Initialize P2P module
+ * @cfg: P2P module configuration
+ * Returns: Pointer to private data or %NULL on failure
+ *
+ * This function is used to initialize global P2P module context (one per
+ * device). The P2P module will keep a copy of the configuration data, so the
+ * caller does not need to maintain this structure. However, the callback
+ * functions and the context parameters to them must be kept available until
+ * the P2P module is deinitialized with p2p_deinit().
+ */
+struct p2p_data * p2p_init(const struct p2p_config *cfg);
+
+/**
+ * p2p_deinit - Deinitialize P2P module
+ * @p2p: P2P module context from p2p_init()
+ */
+void p2p_deinit(struct p2p_data *p2p);
+
+/**
+ * p2p_flush - Flush P2P module state
+ * @p2p: P2P module context from p2p_init()
+ *
+ * This command removes the P2P module state like peer device entries.
+ */
+void p2p_flush(struct p2p_data *p2p);
+
+/**
+ * p2p_unauthorize - Unauthorize the specified peer device
+ * @p2p: P2P module context from p2p_init()
+ * @addr: P2P peer entry to be unauthorized
+ * Returns: 0 on success, -1 on failure
+ *
+ * This command removes any connection authorization from the specified P2P
+ * peer device address. This can be used, e.g., to cancel effect of a previous
+ * p2p_authorize() or p2p_connect() call that has not yet resulted in completed
+ * GO Negotiation.
+ */
+int p2p_unauthorize(struct p2p_data *p2p, const u8 *addr);
+
+/**
+ * p2p_set_dev_name - Set device name
+ * @p2p: P2P module context from p2p_init()
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to update the P2P module configuration with
+ * information that was not available at the time of the p2p_init() call.
+ */
+int p2p_set_dev_name(struct p2p_data *p2p, const char *dev_name);
+
+int p2p_set_manufacturer(struct p2p_data *p2p, const char *manufacturer);
+int p2p_set_model_name(struct p2p_data *p2p, const char *model_name);
+int p2p_set_model_number(struct p2p_data *p2p, const char *model_number);
+int p2p_set_serial_number(struct p2p_data *p2p, const char *serial_number);
+
+void p2p_set_config_methods(struct p2p_data *p2p, u16 config_methods);
+void p2p_set_uuid(struct p2p_data *p2p, const u8 *uuid);
+
+/**
+ * p2p_set_pri_dev_type - Set primary device type
+ * @p2p: P2P module context from p2p_init()
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to update the P2P module configuration with
+ * information that was not available at the time of the p2p_init() call.
+ */
+int p2p_set_pri_dev_type(struct p2p_data *p2p, const u8 *pri_dev_type);
+
+/**
+ * p2p_set_sec_dev_types - Set secondary device types
+ * @p2p: P2P module context from p2p_init()
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to update the P2P module configuration with
+ * information that was not available at the time of the p2p_init() call.
+ */
+int p2p_set_sec_dev_types(struct p2p_data *p2p, const u8 dev_types[][8],
+                         size_t num_dev_types);
+
+int p2p_set_country(struct p2p_data *p2p, const char *country);
+
+
+/* Commands from upper layer management entity */
+
+enum p2p_discovery_type {
+       P2P_FIND_START_WITH_FULL,
+       P2P_FIND_ONLY_SOCIAL,
+       P2P_FIND_PROGRESSIVE
+};
+
+/**
+ * p2p_find - Start P2P Find (Device Discovery)
+ * @p2p: P2P module context from p2p_init()
+ * @timeout: Timeout for find operation in seconds or 0 for no timeout
+ * @type: Device Discovery type
+ * @num_req_dev_types: Number of requested device types
+ * @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.
+ * 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);
+
+/**
+ * p2p_stop_find - Stop P2P Find (Device Discovery)
+ * @p2p: P2P module context from p2p_init()
+ */
+void p2p_stop_find(struct p2p_data *p2p);
+
+/**
+ * p2p_stop_find_for_freq - Stop P2P Find for next oper on specific freq
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Frequency in MHz for next operation
+ *
+ * This is like p2p_stop_find(), but Listen state is not stopped if we are
+ * already on the same frequency.
+ */
+void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq);
+
+/**
+ * p2p_listen - Start P2P Listen state for specified duration
+ * @p2p: P2P module context from p2p_init()
+ * @timeout: Listen state duration in milliseconds
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to request the P2P module to keep the device
+ * discoverable on the listen channel for an extended set of time. At least in
+ * its current form, this is mainly used for testing purposes and may not be of
+ * much use for normal P2P operations.
+ */
+int p2p_listen(struct p2p_data *p2p, unsigned int timeout);
+
+/**
+ * p2p_connect - Start P2P group formation (GO negotiation)
+ * @p2p: P2P module context from p2p_init()
+ * @peer_addr: MAC address of the peer P2P client
+ * @wps_method: WPS method to be used in provisioning
+ * @go_intent: Local GO intent value (1..15)
+ * @own_interface_addr: Intended interface address to use with the group
+ * @force_freq: The only allowed channel frequency in MHz or 0
+ * @persistent_group: Whether to create a persistent group (0 = no, 1 =
+ * persistent group without persistent reconnect, 2 = persistent group with
+ * persistent reconnect)
+ * 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);
+
+/**
+ * p2p_authorize - Authorize P2P group formation (GO negotiation)
+ * @p2p: P2P module context from p2p_init()
+ * @peer_addr: MAC address of the peer P2P client
+ * @wps_method: WPS method to be used in provisioning
+ * @go_intent: Local GO intent value (1..15)
+ * @own_interface_addr: Intended interface address to use with the group
+ * @force_freq: The only allowed channel frequency in MHz or 0
+ * @persistent_group: Whether to create a persistent group (0 = no, 1 =
+ * persistent group without persistent reconnect, 2 = persistent group with
+ * persistent reconnect)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is like p2p_connect(), but the actual group negotiation is not
+ * initiated automatically, i.e., the other end is expected to do that.
+ */
+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);
+
+/**
+ * p2p_reject - Reject peer device (explicitly block connection attempts)
+ * @p2p: P2P module context from p2p_init()
+ * @peer_addr: MAC address of the peer P2P client
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr);
+
+/**
+ * p2p_prov_disc_req - Send Provision Discovery Request
+ * @p2p: P2P module context from p2p_init()
+ * @peer_addr: MAC address of the peer P2P client
+ * @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)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to request a discovered P2P peer to display a PIN
+ * (config_methods = WPS_CONFIG_DISPLAY) or be prepared to enter a PIN from us
+ * (config_methods = WPS_CONFIG_KEYPAD). The Provision Discovery Request frame
+ * is transmitted once immediately and if no response is received, the frame
+ * will be sent again whenever the target device is discovered during device
+ * dsicovery (start with a p2p_find() call). Response from the peer is
+ * indicated with the 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);
+
+/**
+ * p2p_sd_request - Schedule a service discovery query
+ * @p2p: P2P module context from p2p_init()
+ * @dst: Destination peer or %NULL to apply for all peers
+ * @tlvs: P2P Service Query TLV(s)
+ * Returns: Reference to the query or %NULL on failure
+ *
+ * Response to the query is indicated with the p2p_config::sd_response()
+ * callback.
+ */
+void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst,
+                     const struct wpabuf *tlvs);
+
+/**
+ * p2p_sd_cancel_request - Cancel a pending service discovery query
+ * @p2p: P2P module context from p2p_init()
+ * @req: Query reference from p2p_sd_request()
+ * Returns: 0 if request for cancelled; -1 if not found
+ */
+int p2p_sd_cancel_request(struct p2p_data *p2p, void *req);
+
+/**
+ * p2p_sd_response - Send response to a service discovery query
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Frequency from p2p_config::sd_request() callback
+ * @dst: Destination address from p2p_config::sd_request() callback
+ * @dialog_token: Dialog token from p2p_config::sd_request() callback
+ * @resp_tlvs: P2P Service Response TLV(s)
+ *
+ * This function is called as a response to the request indicated with
+ * p2p_config::sd_request() callback.
+ */
+void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
+                    u8 dialog_token, const struct wpabuf *resp_tlvs);
+
+/**
+ * p2p_sd_service_update - Indicate a change in local services
+ * @p2p: P2P module context from p2p_init()
+ *
+ * This function needs to be called whenever there is a change in availability
+ * of the local services. This will increment the Service Update Indicator
+ * value which will be used in SD Request and Response frames.
+ */
+void p2p_sd_service_update(struct p2p_data *p2p);
+
+
+enum p2p_invite_role {
+       P2P_INVITE_ROLE_GO,
+       P2P_INVITE_ROLE_ACTIVE_GO,
+       P2P_INVITE_ROLE_CLIENT
+};
+
+/**
+ * p2p_invite - Invite a P2P Device into a group
+ * @p2p: P2P module context from p2p_init()
+ * @peer: Device Address of the peer P2P Device
+ * @role: Local role in the group
+ * @bssid: Group BSSID or %NULL if not known
+ * @ssid: Group SSID
+ * @ssid_len: Length of ssid in octets
+ * @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
+ * 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);
+
+/**
+ * p2p_presence_req - Request GO presence
+ * @p2p: P2P module context from p2p_init()
+ * @go_interface_addr: GO P2P Interface Address
+ * @own_interface_addr: Own P2P Interface Address for this group
+ * @freq: Group operating frequence (in MHz)
+ * @duration1: Preferred presence duration in microseconds
+ * @interval1: Preferred presence interval in microseconds
+ * @duration2: Acceptable presence duration in microseconds
+ * @interval2: Acceptable presence interval in microseconds
+ * Returns: 0 on success, -1 on failure
+ *
+ * If both duration and interval values are zero, the parameter pair is not
+ * specified (i.e., to remove Presence Request, use duration1 = interval1 = 0).
+ */
+int p2p_presence_req(struct p2p_data *p2p, const u8 *go_interface_addr,
+                    const u8 *own_interface_addr, unsigned int freq,
+                    u32 duration1, u32 interval1, u32 duration2,
+                    u32 interval2);
+
+/**
+ * p2p_ext_listen - Set Extended Listen Timing
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Group operating frequence (in MHz)
+ * @period: Availability period in milliseconds (1-65535; 0 to disable)
+ * @interval: Availability interval in milliseconds (1-65535; 0 to disable)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to enable or disable (period = interval = 0)
+ * Extended Listen Timing. When enabled, the P2P Device will become
+ * discoverable (go into Listen State) every @interval milliseconds for at
+ * least @period milliseconds.
+ */
+int p2p_ext_listen(struct p2p_data *p2p, unsigned int period,
+                  unsigned int interval);
+
+/* Event notifications from upper layer management operations */
+
+/**
+ * p2p_wps_success_cb - Report successfully completed WPS provisioning
+ * @p2p: P2P module context from p2p_init()
+ * @mac_addr: Peer address
+ *
+ * This function is used to report successfully completed WPS provisioning
+ * during group formation in both GO/Registrar and client/Enrollee roles.
+ */
+void p2p_wps_success_cb(struct p2p_data *p2p, const u8 *mac_addr);
+
+/**
+ * p2p_group_formation_failed - Report failed WPS provisioning
+ * @p2p: P2P module context from p2p_init()
+ *
+ * This function is used to report failed group formation. This can happen
+ * either due to failed WPS provisioning or due to 15 second timeout during
+ * the provisioning phase.
+ */
+void p2p_group_formation_failed(struct p2p_data *p2p);
+
+/**
+ * p2p_get_provisioning_info - Get any stored provisioning info
+ * @p2p: P2P module context from p2p_init()
+ * @addr: Peer P2P Device Address
+ * Returns: WPS provisioning information (WPS config method) or 0 if no
+ * information is available
+ *
+ * This function is used to retrieve stored WPS provisioning info for the given
+ * peer.
+ */
+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
+ *
+ * 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);
+
+
+/* Event notifications from lower layer driver operations */
+
+/**
+ * p2p_probe_req_rx - Report reception of a Probe Request frame
+ * @p2p: P2P module context from p2p_init()
+ * @addr: Source MAC address
+ * @dst: Destination MAC address if available or %NULL
+ * @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
+ */
+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);
+
+/**
+ * p2p_rx_action - Report received Action frame
+ * @p2p: P2P module context from p2p_init()
+ * @da: Destination address of the received Action frame
+ * @sa: Source address of the received Action frame
+ * @bssid: Address 3 of the received Action frame
+ * @category: Category of the received Action frame
+ * @data: Action frame body after the Category field
+ * @len: Length of the data buffer in octets
+ * @freq: Frequency (in MHz) on which the frame was received
+ */
+void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa,
+                  const u8 *bssid, u8 category,
+                  const u8 *data, size_t len, int freq);
+
+/**
+ * p2p_scan_res_handler - Indicate a P2P scan results
+ * @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
+ * @level: Signal level (signal strength of the received Beacon/Probe Response
+ *     frame)
+ * @ies: Pointer to IEs from the scan result
+ * @ies_len: Length of the ies buffer
+ * Returns: 0 to continue or 1 to stop scan result indication
+ *
+ * This function is called to indicate a scan result entry with P2P IE from a
+ * scan requested with struct p2p_config::p2p_scan(). This can be called during
+ * the actual scan process (i.e., whenever a new device is found) or as a
+ * sequence of calls after the full scan has been completed. The former option
+ * can result in optimized operations, but may not be supported by all
+ * driver/firmware designs. The ies buffer need to include at least the P2P IE,
+ * but it is recommended to include all IEs received from the device. The
+ * caller does not need to check that the IEs contain a P2P IE before calling
+ * this function since frames will be filtered internally if needed.
+ *
+ * This function will return 1 if it wants to stop scan result iteration (and
+ * scan in general if it is still in progress). This is used to allow faster
+ * 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);
+
+/**
+ * p2p_scan_res_handled - Indicate end of scan results
+ * @p2p: P2P module context from p2p_init()
+ *
+ * This function is called to indicate that all P2P scan results from a scan
+ * have been reported with zero or more calls to p2p_scan_res_handler(). This
+ * function must be called as a response to successful
+ * struct p2p_config::p2p_scan() call if none of the p2p_scan_res_handler()
+ * calls stopped iteration.
+ */
+void p2p_scan_res_handled(struct p2p_data *p2p);
+
+enum p2p_send_action_result {
+       P2P_SEND_ACTION_SUCCESS /* Frame was send and acknowledged */,
+       P2P_SEND_ACTION_NO_ACK /* Frame was sent, but not acknowledged */,
+       P2P_SEND_ACTION_FAILED /* Frame was not sent due to a failure */
+};
+
+/**
+ * p2p_send_action_cb - Notify TX status of an Action frame
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Channel frequency in MHz
+ * @dst: Destination MAC address (Address 1)
+ * @src: Source MAC address (Address 2)
+ * @bssid: BSSID (Address 3)
+ * @result: Result of the transmission attempt
+ *
+ * This function is used to indicate the result of an Action frame transmission
+ * that was requested with struct p2p_config::send_action() callback.
+ */
+void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
+                       const u8 *src, const u8 *bssid,
+                       enum p2p_send_action_result result);
+
+/**
+ * p2p_listen_cb - Indicate the start of a requested Listen state
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Listen channel frequency in MHz
+ * @duration: Duration for the Listen state in milliseconds
+ *
+ * This function is used to indicate that a Listen state requested with
+ * struct p2p_config::start_listen() callback has started.
+ */
+void p2p_listen_cb(struct p2p_data *p2p, unsigned int freq,
+                  unsigned int duration);
+
+/**
+ * p2p_listen_end - Indicate the end of a requested Listen state
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Listen channel frequency in MHz
+ * Returns: 0 if no operations were started, 1 if an operation was started
+ *
+ * This function is used to indicate that a Listen state requested with
+ * struct p2p_config::start_listen() callback has ended.
+ */
+int p2p_listen_end(struct p2p_data *p2p, unsigned int freq);
+
+void p2p_deauth_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code,
+                     const u8 *ie, size_t ie_len);
+
+void p2p_disassoc_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code,
+                       const u8 *ie, size_t ie_len);
+
+
+/* Per-group P2P state for GO */
+
+struct p2p_group;
+
+/**
+ * struct p2p_group_config - P2P group configuration
+ *
+ * This configuration is provided to the P2P module during initialization of
+ * the per-group information with p2p_group_init().
+ */
+struct p2p_group_config {
+       /**
+        * persistent_group - Whether the group is persistent
+        * 0 = not a persistent group
+        * 1 = persistent group without persistent reconnect
+        * 2 = persistent group with persistent reconnect
+        */
+       int persistent_group;
+
+       /**
+        * interface_addr - P2P Interface Address of the group
+        */
+       u8 interface_addr[ETH_ALEN];
+
+       /**
+        * max_clients - Maximum number of clients in the group
+        */
+       unsigned int max_clients;
+
+       /**
+        * cb_ctx - Context to use with callback functions
+        */
+       void *cb_ctx;
+
+       /**
+        * ie_update - Notification of IE update
+        * @ctx: Callback context from cb_ctx
+        * @beacon_ies: P2P IE for Beacon frames or %NULL if no change
+        * @proberesp_ies: P2P Ie for Probe Response frames
+        *
+        * P2P module uses this callback function to notify whenever the P2P IE
+        * in Beacon or Probe Response frames should be updated based on group
+        * events.
+        *
+        * The callee is responsible for freeing the returned buffer(s) with
+        * wpabuf_free().
+        */
+       void (*ie_update)(void *ctx, struct wpabuf *beacon_ies,
+                         struct wpabuf *proberesp_ies);
+
+       /**
+        * idle_update - Notification of changes in group idle state
+        * @ctx: Callback context from cb_ctx
+        * @idle: Whether the group is idle (no associated stations)
+        */
+       void (*idle_update)(void *ctx, int idle);
+};
+
+/**
+ * p2p_group_init - Initialize P2P group
+ * @p2p: P2P module context from p2p_init()
+ * @config: P2P group configuration (will be freed by p2p_group_deinit())
+ * Returns: Pointer to private data or %NULL on failure
+ *
+ * This function is used to initialize per-group P2P module context. Currently,
+ * this is only used to manage GO functionality and P2P clients do not need to
+ * create an instance of this per-group information.
+ */
+struct p2p_group * p2p_group_init(struct p2p_data *p2p,
+                                 struct p2p_group_config *config);
+
+/**
+ * p2p_group_deinit - Deinitialize P2P group
+ * @group: P2P group context from p2p_group_init()
+ */
+void p2p_group_deinit(struct p2p_group *group);
+
+/**
+ * p2p_group_notif_assoc - Notification of P2P client association with GO
+ * @group: P2P group context from p2p_group_init()
+ * @addr: Interface address of the P2P client
+ * @ie: IEs from the (Re)association Request frame
+ * @len: Length of the ie buffer in octets
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
+                         const u8 *ie, size_t len);
+
+/**
+ * p2p_group_assoc_resp_ie - Build P2P IE for (re)association response
+ * @group: P2P group context from p2p_group_init()
+ * @status: Status value (P2P_SC_SUCCESS if association succeeded)
+ * Returns: P2P IE for (Re)association Response or %NULL on failure
+ *
+ * The caller is responsible for freeing the returned buffer with
+ * wpabuf_free().
+ */
+struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status);
+
+/**
+ * p2p_group_notif_disassoc - Notification of P2P client disassociation from GO
+ * @group: P2P group context from p2p_group_init()
+ * @addr: Interface address of the P2P client
+ */
+void p2p_group_notif_disassoc(struct p2p_group *group, const u8 *addr);
+
+/**
+ * p2p_group_notif_formation_done - Notification of completed group formation
+ * @group: P2P group context from p2p_group_init()
+ */
+void p2p_group_notif_formation_done(struct p2p_group *group);
+
+/**
+ * p2p_group_notif_noa - Notification of NoA change
+ * @group: P2P group context from p2p_group_init()
+ * @noa: Notice of Absence attribute payload, %NULL if none
+ * @noa_len: Length of noa buffer in octets
+ * Returns: 0 on success, -1 on failure
+ *
+ * Notify the P2P group management about a new NoA contents. This will be
+ * inserted into the P2P IEs in Beacon and Probe Response frames with rest of
+ * the group information.
+ */
+int p2p_group_notif_noa(struct p2p_group *group, const u8 *noa,
+                       size_t noa_len);
+
+/**
+ * p2p_group_match_dev_type - Match device types in group with requested type
+ * @group: P2P group context from p2p_group_init()
+ * @wps: WPS TLVs from Probe Request frame (concatenated WPS IEs)
+ * Returns: 1 on match, 0 on mismatch
+ *
+ * This function can be used to match the Requested Device Type attribute in
+ * WPS IE with the device types of a group member for deciding whether a GO
+ * should reply to a Probe Request frame. Match will be reported if the WPS IE
+ * is not requested any specific device type.
+ */
+int p2p_group_match_dev_type(struct p2p_group *group, struct wpabuf *wps);
+
+/**
+ * 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
+ */
+int p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id,
+                         const u8 *searching_dev, int rx_freq);
+
+
+/* Generic helper functions */
+
+/**
+ * p2p_ie_text - Build text format description of P2P IE
+ * @p2p_ie: P2P IE
+ * @buf: Buffer for returning text
+ * @end: Pointer to the end of the buf area
+ * Returns: Number of octets written to the buffer or -1 on failure
+ *
+ * This function can be used to parse P2P IE contents into text format
+ * field=value lines.
+ */
+int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end);
+
+/**
+ * p2p_scan_result_text - Build text format description of P2P IE
+ * @ies: Information elements from scan results
+ * @ies_len: ies buffer length in octets
+ * @buf: Buffer for returning text
+ * @end: Pointer to the end of the buf area
+ * Returns: Number of octets written to the buffer or -1 on failure
+ *
+ * This function can be used to parse P2P IE contents into text format
+ * field=value lines.
+ */
+int p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end);
+
+/**
+ * p2p_assoc_req_ie - Build P2P IE for (Re)Association Request frame
+ * @p2p: P2P module context from p2p_init()
+ * @bssid: BSSID
+ * @buf: Buffer for writing the P2P IE
+ * @len: Maximum buf length in octets
+ * @p2p_group: Whether this is for association with a P2P GO
+ * @p2p_ie: Reassembled P2P IE data from scan results or %NULL if none
+ * Returns: Number of octets written into buf or -1 on failure
+ */
+int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf,
+                    size_t len, int p2p_group, struct wpabuf *p2p_ie);
+
+/**
+ * p2p_scan_ie - Build P2P IE for Probe Request
+ * @p2p: P2P module context from p2p_init()
+ * @ies: Buffer for writing P2P IE
+ */
+void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies);
+
+/**
+ * p2p_scan_ie_buf_len - Get maximum buffer length needed for p2p_scan_ie
+ * @p2p: P2P module context from p2p_init()
+ * Returns: Number of octets that p2p_scan_ie() may add to the buffer
+ */
+size_t p2p_scan_ie_buf_len(struct p2p_data *p2p);
+
+/**
+ * p2p_go_params - Generate random P2P group parameters
+ * @p2p: P2P module context from p2p_init()
+ * @params: Buffer for parameters
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params);
+
+/**
+ * p2p_get_group_capab - Get Group Capability from P2P IE data
+ * @p2p_ie: P2P IE(s) contents
+ * Returns: Group Capability
+ */
+u8 p2p_get_group_capab(const struct wpabuf *p2p_ie);
+
+/**
+ * p2p_get_cross_connect_disallowed - Does WLAN AP disallows cross connection
+ * @p2p_ie: P2P IE(s) contents
+ * Returns: 0 if cross connection is allow, 1 if not
+ */
+int p2p_get_cross_connect_disallowed(const struct wpabuf *p2p_ie);
+
+/**
+ * p2p_get_go_dev_addr - Get P2P Device Address from P2P IE data
+ * @p2p_ie: P2P IE(s) contents
+ * Returns: Pointer to P2P Device Address or %NULL if not included
+ */
+const u8 * p2p_get_go_dev_addr(const struct wpabuf *p2p_ie);
+
+/**
+ * p2p_get_peer_info - Get P2P peer information in text format
+ * @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
+ * @buf: Buffer for returning text
+ * @buflen: Maximum buffer length
+ * Returns: Number of octets written to the buffer or -1 on failure
+ */
+int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
+                     char *buf, size_t buflen);
+
+/**
+ * p2p_set_client_discoverability - Set client discoverability capability
+ * @p2p: P2P module context from p2p_init()
+ * @enabled: Whether client discoverability will be enabled
+ *
+ * This function can be used to disable (and re-enable) client discoverability.
+ * This capability is enabled by default and should not be disabled in normal
+ * use cases, i.e., this is mainly for testing purposes.
+ */
+void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled);
+
+/**
+ * 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
+ */
+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);
+
+int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len);
+
+int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
+                          u8 *iface_addr);
+int p2p_get_dev_addr(struct p2p_data *p2p, const u8 *iface_addr,
+                          u8 *dev_addr);
+
+void p2p_set_peer_filter(struct p2p_data *p2p, const u8 *addr);
+
+/**
+ * p2p_set_cross_connect - Set cross connection capability
+ * @p2p: P2P module context from p2p_init()
+ * @enabled: Whether cross connection will be enabled
+ */
+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()
+ * @enabled: Whether intra BSS distribution will be enabled
+ */
+void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled);
+
+/**
+ * p2p_supported_freq - Check whether channel is supported for P2P
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Channel frequency in MHz
+ * Returns: 0 if channel not usable for P2P, 1 if usable for P2P
+ */
+int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq);
+
+void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan);
+
+/**
+ * p2p_set_best_channels - Update best channel information
+ * @p2p: P2P module context from p2p_init()
+ * @freq_24: Frequency (MHz) of best channel in 2.4 GHz band
+ * @freq_5: Frequency (MHz) of best channel in 5 GHz band
+ * @freq_overall: Frequency (MHz) of best channel overall
+ */
+void p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5,
+                          int freq_overall);
+
+const u8 * p2p_get_go_neg_peer(struct p2p_data *p2p);
+
+/**
+ * p2p_get_group_num_members - Get number of members in group
+ * @group: P2P group context from p2p_group_init()
+ * Returns: Number of members in the group
+ */
+unsigned int p2p_get_group_num_members(struct p2p_group *group);
+
+/**
+ * p2p_iterate_group_members - Iterate group members
+ * @group: P2P group context from p2p_group_init()
+ * @next: iteration pointer, must be a pointer to a void * that is set to %NULL
+ *     on the first call and not modified later
+ * Returns: A P2P Interface Address for each call and %NULL for no more members
+ */
+const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next);
+
+/**
+ * p2p_group_get_dev_addr - Get a P2P Device Address of a client in a group
+ * @group: P2P group context from p2p_group_init()
+ * @addr: P2P Interface Address of the client
+ * Returns: P2P Device Address of the client if found or %NULL if no match
+ * found
+ */
+const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *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
+ * @next: Whether to select the peer entry following the one indicated by addr
+ * Returns: The first P2P peer info available or %NULL if no such peer exists
+ */
+const struct p2p_peer_info *
+p2p_get_peer_found(struct p2p_data *p2p, const u8 *addr, int next);
+
+/**
+ * p2p_remove_wps_vendor_extensions - Remove WPS vendor extensions
+ * @p2p: P2P module context from p2p_init()
+ */
+void p2p_remove_wps_vendor_extensions(struct p2p_data *p2p);
+
+/**
+ * p2p_add_wps_vendor_extension - Add a WPS vendor extension
+ * @p2p: P2P module context from p2p_init()
+ * @vendor_ext: The vendor extensions to add
+ * Returns: 0 on success, -1 on failure
+ *
+ * The wpabuf structures in the array are owned by the P2P
+ * module after this call.
+ */
+int p2p_add_wps_vendor_extension(struct p2p_data *p2p,
+                                const struct wpabuf *vendor_ext);
+
+/**
+ * p2p_set_oper_channel - Set the P2P operating channel
+ * @p2p: P2P module context from p2p_init()
+ * @op_reg_class: Operating regulatory class to set
+ * @op_channel: operating channel to set
+ * @cfg_op_channel : Whether op_channel is hardcoded in configuration
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
+                        int cfg_op_channel);
+
+/**
+ * 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
+ */
+int p2p_in_progress(struct p2p_data *p2p);
+
+/**
+ * p2p_other_scan_completed - Notify completion of non-P2P scan
+ * @p2p: P2P module context from p2p_init()
+ * Returns: 0 if P2P module is idle or 1 if an operation was started
+ */
+int p2p_other_scan_completed(struct p2p_data *p2p);
+
+const char * p2p_wps_method_text(enum p2p_wps_method method);
+
+#endif /* P2P_H */
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
new file mode 100644 (file)
index 0000000..a82e16d
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "common/ieee802_11_defs.h"
+#include "wps/wps_i.h"
+#include "p2p_i.h"
+
+
+void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token)
+{
+       wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC);
+       wpabuf_put_be24(buf, OUI_WFA);
+       wpabuf_put_u8(buf, P2P_OUI_TYPE);
+
+       wpabuf_put_u8(buf, subtype); /* OUI Subtype */
+       wpabuf_put_u8(buf, dialog_token);
+       wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", dialog_token);
+}
+
+
+void p2p_buf_add_public_action_hdr(struct wpabuf *buf, u8 subtype,
+                                  u8 dialog_token)
+{
+       wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+       wpabuf_put_u8(buf, WLAN_PA_VENDOR_SPECIFIC);
+       wpabuf_put_be24(buf, OUI_WFA);
+       wpabuf_put_u8(buf, P2P_OUI_TYPE);
+
+       wpabuf_put_u8(buf, subtype); /* OUI Subtype */
+       wpabuf_put_u8(buf, dialog_token);
+       wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", dialog_token);
+}
+
+
+u8 * p2p_buf_add_ie_hdr(struct wpabuf *buf)
+{
+       u8 *len;
+
+       /* P2P IE header */
+       wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+       len = wpabuf_put(buf, 1); /* IE length to be filled */
+       wpabuf_put_be24(buf, OUI_WFA);
+       wpabuf_put_u8(buf, P2P_OUI_TYPE);
+       wpa_printf(MSG_DEBUG, "P2P: * P2P IE header");
+       return len;
+}
+
+
+void p2p_buf_update_ie_hdr(struct wpabuf *buf, u8 *len)
+{
+       /* Update P2P IE Length */
+       *len = (u8 *) wpabuf_put(buf, 0) - len - 1;
+}
+
+
+void p2p_buf_add_capability(struct wpabuf *buf, u8 dev_capab, u8 group_capab)
+{
+       /* P2P Capability */
+       wpabuf_put_u8(buf, P2P_ATTR_CAPABILITY);
+       wpabuf_put_le16(buf, 2);
+       wpabuf_put_u8(buf, dev_capab); /* Device Capabilities */
+       wpabuf_put_u8(buf, group_capab); /* Group Capabilities */
+       wpa_printf(MSG_DEBUG, "P2P: * Capability dev=%02x group=%02x",
+                  dev_capab, group_capab);
+}
+
+
+void p2p_buf_add_go_intent(struct wpabuf *buf, u8 go_intent)
+{
+       /* Group Owner Intent */
+       wpabuf_put_u8(buf, P2P_ATTR_GROUP_OWNER_INTENT);
+       wpabuf_put_le16(buf, 1);
+       wpabuf_put_u8(buf, go_intent);
+       wpa_printf(MSG_DEBUG, "P2P: * GO Intent: Intent %u Tie breaker %u",
+                  go_intent >> 1, go_intent & 0x01);
+}
+
+
+void p2p_buf_add_listen_channel(struct wpabuf *buf, const char *country,
+                               u8 reg_class, u8 channel)
+{
+       /* Listen Channel */
+       wpabuf_put_u8(buf, P2P_ATTR_LISTEN_CHANNEL);
+       wpabuf_put_le16(buf, 5);
+       wpabuf_put_data(buf, country, 3);
+       wpabuf_put_u8(buf, reg_class); /* Regulatory Class */
+       wpabuf_put_u8(buf, channel); /* Channel Number */
+       wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: Regulatory Class %u "
+                  "Channel %u", reg_class, channel);
+}
+
+
+void p2p_buf_add_operating_channel(struct wpabuf *buf, const char *country,
+                                  u8 reg_class, u8 channel)
+{
+       /* Operating Channel */
+       wpabuf_put_u8(buf, P2P_ATTR_OPERATING_CHANNEL);
+       wpabuf_put_le16(buf, 5);
+       wpabuf_put_data(buf, country, 3);
+       wpabuf_put_u8(buf, reg_class); /* Regulatory Class */
+       wpabuf_put_u8(buf, channel); /* Channel Number */
+       wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: Regulatory Class %u "
+                  "Channel %u", reg_class, channel);
+}
+
+
+void p2p_buf_add_channel_list(struct wpabuf *buf, const char *country,
+                             struct p2p_channels *chan)
+{
+       u8 *len;
+       size_t i;
+
+       /* Channel List */
+       wpabuf_put_u8(buf, P2P_ATTR_CHANNEL_LIST);
+       len = wpabuf_put(buf, 2); /* IE length to be filled */
+       wpabuf_put_data(buf, country, 3); /* Country String */
+
+       for (i = 0; i < chan->reg_classes; i++) {
+               struct p2p_reg_class *c = &chan->reg_class[i];
+               wpabuf_put_u8(buf, c->reg_class);
+               wpabuf_put_u8(buf, c->channels);
+               wpabuf_put_data(buf, c->channel, c->channels);
+       }
+
+       /* Update attribute length */
+       WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
+       wpa_printf(MSG_DEBUG, "P2P: * Channel List");
+}
+
+
+void p2p_buf_add_status(struct wpabuf *buf, u8 status)
+{
+       /* Status */
+       wpabuf_put_u8(buf, P2P_ATTR_STATUS);
+       wpabuf_put_le16(buf, 1);
+       wpabuf_put_u8(buf, status);
+       wpa_printf(MSG_DEBUG, "P2P: * Status: %d", status);
+}
+
+
+void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p,
+                            struct p2p_device *peer)
+{
+       u8 *len;
+       u16 methods;
+       size_t nlen, i;
+
+       /* P2P Device Info */
+       wpabuf_put_u8(buf, P2P_ATTR_DEVICE_INFO);
+       len = wpabuf_put(buf, 2); /* IE length to be filled */
+
+       /* P2P Device address */
+       wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN);
+
+       /* Config Methods */
+       methods = 0;
+       if (peer && peer->wps_method != WPS_NOT_READY) {
+               if (peer->wps_method == WPS_PBC)
+                       methods |= WPS_CONFIG_PUSHBUTTON;
+               else if (peer->wps_method == WPS_PIN_DISPLAY ||
+                        peer->wps_method == WPS_PIN_KEYPAD)
+                       methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
+       } else if (p2p->cfg->config_methods) {
+               methods |= p2p->cfg->config_methods &
+                       (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY |
+                        WPS_CONFIG_KEYPAD);
+       } else {
+               methods |= WPS_CONFIG_PUSHBUTTON;
+               methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
+       }
+       wpabuf_put_be16(buf, methods);
+
+       /* Primary Device Type */
+       wpabuf_put_data(buf, p2p->cfg->pri_dev_type,
+                       sizeof(p2p->cfg->pri_dev_type));
+
+       /* Number of Secondary Device Types */
+       wpabuf_put_u8(buf, p2p->cfg->num_sec_dev_types);
+
+       /* Secondary Device Type List */
+       for (i = 0; i < p2p->cfg->num_sec_dev_types; i++)
+               wpabuf_put_data(buf, p2p->cfg->sec_dev_type[i],
+                               WPS_DEV_TYPE_LEN);
+
+       /* Device Name */
+       nlen = p2p->cfg->dev_name ? os_strlen(p2p->cfg->dev_name) : 0;
+       wpabuf_put_be16(buf, ATTR_DEV_NAME);
+       wpabuf_put_be16(buf, nlen);
+       wpabuf_put_data(buf, p2p->cfg->dev_name, nlen);
+
+       /* Update attribute length */
+       WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
+       wpa_printf(MSG_DEBUG, "P2P: * Device Info");
+}
+
+
+void p2p_buf_add_device_id(struct wpabuf *buf, const u8 *dev_addr)
+{
+       /* P2P Device ID */
+       wpabuf_put_u8(buf, P2P_ATTR_DEVICE_ID);
+       wpabuf_put_le16(buf, ETH_ALEN);
+       wpabuf_put_data(buf, dev_addr, ETH_ALEN);
+       wpa_printf(MSG_DEBUG, "P2P: * Device ID: " MACSTR, MAC2STR(dev_addr));
+}
+
+
+void p2p_buf_add_config_timeout(struct wpabuf *buf, u8 go_timeout,
+                               u8 client_timeout)
+{
+       /* Configuration Timeout */
+       wpabuf_put_u8(buf, P2P_ATTR_CONFIGURATION_TIMEOUT);
+       wpabuf_put_le16(buf, 2);
+       wpabuf_put_u8(buf, go_timeout);
+       wpabuf_put_u8(buf, client_timeout);
+       wpa_printf(MSG_DEBUG, "P2P: * Configuration Timeout: GO %d (*10ms)  "
+                  "client %d (*10ms)", go_timeout, client_timeout);
+}
+
+
+void p2p_buf_add_intended_addr(struct wpabuf *buf, const u8 *interface_addr)
+{
+       /* Intended P2P Interface Address */
+       wpabuf_put_u8(buf, P2P_ATTR_INTENDED_INTERFACE_ADDR);
+       wpabuf_put_le16(buf, ETH_ALEN);
+       wpabuf_put_data(buf, interface_addr, ETH_ALEN);
+       wpa_printf(MSG_DEBUG, "P2P: * Intended P2P Interface Address " MACSTR,
+                  MAC2STR(interface_addr));
+}
+
+
+void p2p_buf_add_group_bssid(struct wpabuf *buf, const u8 *bssid)
+{
+       /* P2P Group BSSID */
+       wpabuf_put_u8(buf, P2P_ATTR_GROUP_BSSID);
+       wpabuf_put_le16(buf, ETH_ALEN);
+       wpabuf_put_data(buf, bssid, ETH_ALEN);
+       wpa_printf(MSG_DEBUG, "P2P: * P2P Group BSSID " MACSTR,
+                  MAC2STR(bssid));
+}
+
+
+void p2p_buf_add_group_id(struct wpabuf *buf, const u8 *dev_addr,
+                         const u8 *ssid, size_t ssid_len)
+{
+       /* P2P Group ID */
+       wpabuf_put_u8(buf, P2P_ATTR_GROUP_ID);
+       wpabuf_put_le16(buf, ETH_ALEN + ssid_len);
+       wpabuf_put_data(buf, dev_addr, ETH_ALEN);
+       wpabuf_put_data(buf, ssid, ssid_len);
+       wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR,
+                  MAC2STR(dev_addr));
+}
+
+
+void p2p_buf_add_invitation_flags(struct wpabuf *buf, u8 flags)
+{
+       /* Invitation Flags */
+       wpabuf_put_u8(buf, P2P_ATTR_INVITATION_FLAGS);
+       wpabuf_put_le16(buf, 1);
+       wpabuf_put_u8(buf, flags);
+       wpa_printf(MSG_DEBUG, "P2P: * Invitation Flags: bitmap 0x%x", flags);
+}
+
+
+static void p2p_buf_add_noa_desc(struct wpabuf *buf, struct p2p_noa_desc *desc)
+{
+       if (desc == NULL)
+               return;
+
+       wpabuf_put_u8(buf, desc->count_type);
+       wpabuf_put_le32(buf, desc->duration);
+       wpabuf_put_le32(buf, desc->interval);
+       wpabuf_put_le32(buf, desc->start_time);
+}
+
+
+void p2p_buf_add_noa(struct wpabuf *buf, u8 noa_index, u8 opp_ps, u8 ctwindow,
+                    struct p2p_noa_desc *desc1, struct p2p_noa_desc *desc2)
+{
+       /* Notice of Absence */
+       wpabuf_put_u8(buf, P2P_ATTR_NOTICE_OF_ABSENCE);
+       wpabuf_put_le16(buf, 2 + (desc1 ? 13 : 0) + (desc2 ? 13 : 0));
+       wpabuf_put_u8(buf, noa_index);
+       wpabuf_put_u8(buf, (opp_ps ? 0x80 : 0) | (ctwindow & 0x7f));
+       p2p_buf_add_noa_desc(buf, desc1);
+       p2p_buf_add_noa_desc(buf, desc2);
+       wpa_printf(MSG_DEBUG, "P2P: * Notice of Absence");
+}
+
+
+void p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period,
+                                  u16 interval)
+{
+       /* Extended Listen Timing */
+       wpabuf_put_u8(buf, P2P_ATTR_EXT_LISTEN_TIMING);
+       wpabuf_put_le16(buf, 4);
+       wpabuf_put_le16(buf, period);
+       wpabuf_put_le16(buf, interval);
+       wpa_printf(MSG_DEBUG, "P2P: * Extended Listen Timing (period %u msec  "
+                  "interval %u msec)", period, interval);
+}
+
+
+void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p)
+{
+       /* P2P Interface */
+       wpabuf_put_u8(buf, P2P_ATTR_INTERFACE);
+       wpabuf_put_le16(buf, ETH_ALEN + 1 + ETH_ALEN);
+       /* P2P Device address */
+       wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN);
+       /*
+        * FIX: Fetch interface address list from driver. Do not include
+        * the P2P Device address if it is never used as interface address.
+        */
+       /* P2P Interface Address Count */
+       wpabuf_put_u8(buf, 1);
+       wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN);
+}
+
+
+static void p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
+                              const char *val)
+{
+       size_t len;
+
+       wpabuf_put_be16(buf, attr);
+       len = val ? os_strlen(val) : 0;
+#ifndef CONFIG_WPS_STRICT
+       if (len == 0) {
+               /*
+                * Some deployed WPS implementations fail to parse zeor-length
+                * attributes. As a workaround, send a space character if the
+                * device attribute string is empty.
+                */
+               wpabuf_put_be16(buf, 1);
+               wpabuf_put_u8(buf, ' ');
+               return;
+       }
+#endif /* CONFIG_WPS_STRICT */
+       wpabuf_put_be16(buf, len);
+       if (val)
+               wpabuf_put_data(buf, val, len);
+}
+
+
+void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, u16 pw_id,
+                     int all_attr)
+{
+       u8 *len;
+       int i;
+
+       wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+       len = wpabuf_put(buf, 1);
+       wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
+
+       wps_build_version(buf);
+
+       if (all_attr) {
+               wpabuf_put_be16(buf, ATTR_WPS_STATE);
+               wpabuf_put_be16(buf, 1);
+               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 (all_attr) {
+               wpabuf_put_be16(buf, ATTR_RESPONSE_TYPE);
+               wpabuf_put_be16(buf, 1);
+               wpabuf_put_u8(buf, WPS_RESP_ENROLLEE_INFO);
+
+               wps_build_uuid_e(buf, p2p->cfg->uuid);
+               p2p_add_wps_string(buf, ATTR_MANUFACTURER,
+                                  p2p->cfg->manufacturer);
+               p2p_add_wps_string(buf, ATTR_MODEL_NAME, p2p->cfg->model_name);
+               p2p_add_wps_string(buf, ATTR_MODEL_NUMBER,
+                                  p2p->cfg->model_number);
+               p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER,
+                                  p2p->cfg->serial_number);
+
+               wpabuf_put_be16(buf, ATTR_PRIMARY_DEV_TYPE);
+               wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN);
+               wpabuf_put_data(buf, p2p->cfg->pri_dev_type, WPS_DEV_TYPE_LEN);
+
+               p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name);
+
+               wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
+               wpabuf_put_be16(buf, 2);
+               wpabuf_put_be16(buf, p2p->cfg->config_methods);
+       }
+
+       wps_build_wfa_ext(buf, 0, NULL, 0);
+
+       if (all_attr && p2p->cfg->num_sec_dev_types) {
+               wpabuf_put_be16(buf, ATTR_SECONDARY_DEV_TYPE_LIST);
+               wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN *
+                               p2p->cfg->num_sec_dev_types);
+               wpabuf_put_data(buf, p2p->cfg->sec_dev_type,
+                               WPS_DEV_TYPE_LEN *
+                               p2p->cfg->num_sec_dev_types);
+       }
+
+       /* Add the WPS vendor extensions */
+       for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+               if (p2p->wps_vendor_ext[i] == NULL)
+                       break;
+               if (wpabuf_tailroom(buf) <
+                   4 + wpabuf_len(p2p->wps_vendor_ext[i]))
+                       continue;
+               wpabuf_put_be16(buf, ATTR_VENDOR_EXT);
+               wpabuf_put_be16(buf, wpabuf_len(p2p->wps_vendor_ext[i]));
+               wpabuf_put_buf(buf, p2p->wps_vendor_ext[i]);
+       }
+
+       p2p_buf_update_ie_hdr(buf, len);
+}
diff --git a/src/p2p/p2p_dev_disc.c b/src/p2p/p2p_dev_disc.c
new file mode 100644 (file)
index 0000000..47cc0fd
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "common/ieee802_11_defs.h"
+#include "p2p_i.h"
+#include "p2p.h"
+
+
+static struct wpabuf * p2p_build_dev_disc_req(struct p2p_data *p2p,
+                                             struct p2p_device *go,
+                                             const u8 *dev_id)
+{
+       struct wpabuf *buf;
+       u8 *len;
+
+       buf = wpabuf_alloc(100);
+       if (buf == NULL)
+               return NULL;
+
+       go->dialog_token++;
+       if (go->dialog_token == 0)
+               go->dialog_token = 1;
+       p2p_buf_add_public_action_hdr(buf, P2P_DEV_DISC_REQ, go->dialog_token);
+
+       len = p2p_buf_add_ie_hdr(buf);
+       p2p_buf_add_device_id(buf, dev_id);
+       p2p_buf_add_group_id(buf, go->info.p2p_device_addr, go->oper_ssid,
+                            go->oper_ssid_len);
+       p2p_buf_update_ie_hdr(buf, len);
+
+       return buf;
+}
+
+
+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",
+               success);
+
+       if (!success) {
+               /*
+                * Use P2P find, if needed, to find the other device or to
+                * retry device discoverability.
+                */
+               p2p_set_state(p2p, P2P_CONNECT);
+               p2p_set_timeout(p2p, 0, 100000);
+               return;
+       }
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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
+        * another remain-on-channel if needed once the previous one expires?
+        */
+}
+
+
+int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev)
+{
+       struct p2p_device *go;
+       struct wpabuf *req;
+
+       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");
+               return -1;
+       }
+
+       req = p2p_build_dev_disc_req(p2p, go, dev->info.p2p_device_addr);
+       if (req == NULL)
+               return -1;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "P2P: Sending Device Discoverability Request to GO " MACSTR
+               " for client " MACSTR,
+               MAC2STR(go->info.p2p_device_addr),
+               MAC2STR(dev->info.p2p_device_addr));
+
+       p2p->pending_client_disc_go = go;
+       os_memcpy(p2p->pending_client_disc_addr, dev->info.p2p_device_addr,
+                 ETH_ALEN);
+       p2p->pending_action_state = P2P_PENDING_DEV_DISC_REQUEST;
+       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");
+               wpabuf_free(req);
+               /* TODO: how to recover from failure? */
+               return -1;
+       }
+
+       wpabuf_free(req);
+
+       return 0;
+}
+
+
+static struct wpabuf * p2p_build_dev_disc_resp(u8 dialog_token, u8 status)
+{
+       struct wpabuf *buf;
+       u8 *len;
+
+       buf = wpabuf_alloc(100);
+       if (buf == NULL)
+               return NULL;
+
+       p2p_buf_add_public_action_hdr(buf, P2P_DEV_DISC_RESP, dialog_token);
+
+       len = p2p_buf_add_ie_hdr(buf);
+       p2p_buf_add_status(buf, status);
+       p2p_buf_update_ie_hdr(buf, len);
+
+       return buf;
+}
+
+
+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",
+               success);
+       p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+}
+
+
+static void p2p_send_dev_disc_resp(struct p2p_data *p2p, u8 dialog_token,
+                                  const u8 *addr, int freq, u8 status)
+{
+       struct wpabuf *resp;
+
+       resp = p2p_build_dev_disc_resp(dialog_token, status);
+       if (resp == NULL)
+               return;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "P2P: Sending Device Discoverability Response to " MACSTR
+               " (status %u freq %d)",
+               MAC2STR(addr), status, freq);
+
+       p2p->pending_action_state = P2P_PENDING_DEV_DISC_RESPONSE;
+       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");
+       }
+
+       wpabuf_free(resp);
+}
+
+
+void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa,
+                             const u8 *data, size_t len, int rx_freq)
+{
+       struct p2p_message msg;
+       size_t g;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq,
+                                      P2P_SC_FAIL_INVALID_PARAMS);
+               p2p_parse_free(&msg);
+               return;
+       }
+
+       if (msg.device_id == NULL) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "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);
+               return;
+       }
+
+       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 group code will use a callback to indicate TX
+                        * status, so that we can reply to the request once the
+                        * target client has acknowledged the request or it has
+                        * timed out.
+                        */
+                       p2p->pending_dev_disc_dialog_token = msg.dialog_token;
+                       os_memcpy(p2p->pending_dev_disc_addr, sa, ETH_ALEN);
+                       p2p->pending_dev_disc_freq = rx_freq;
+                       p2p_parse_free(&msg);
+                       return;
+               }
+       }
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "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);
+}
+
+
+void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
+                              const u8 *data, size_t len)
+{
+       struct p2p_message msg;
+       struct p2p_device *go;
+       u8 status;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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");
+               return;
+       }
+
+       if (p2p_parse(data, len, &msg))
+               return;
+
+       if (msg.status == NULL) {
+               p2p_parse_free(&msg);
+               return;
+       }
+
+       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)",
+                       msg.dialog_token, go->dialog_token);
+               p2p_parse_free(&msg);
+               return;
+       }
+
+       status = *msg.status;
+       p2p_parse_free(&msg);
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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");
+               return;
+       }
+
+       if (status == 0) {
+               /*
+                * 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");
+               if (p2p->state == P2P_CONNECT) {
+                       /*
+                        * Change state to force the timeout to start in
+                        * P2P_CONNECT again without going through the short
+                        * Listen state.
+                        */
+                       p2p_set_state(p2p, P2P_CONNECT_LISTEN);
+                       p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+               }
+               p2p_set_timeout(p2p, 0, 0);
+       } else {
+               /*
+                * Client discoverability request failed; try to connect from
+                * timeout.
+                */
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Client discoverability request failed");
+               p2p_set_timeout(p2p, 0, 500000);
+       }
+
+}
+
+
+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",
+               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");
+               return;
+       }
+
+       p2p_send_dev_disc_resp(p2p, p2p->pending_dev_disc_dialog_token,
+                              p2p->pending_dev_disc_addr,
+                              p2p->pending_dev_disc_freq,
+                              success ? P2P_SC_SUCCESS :
+                              P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE);
+
+       p2p->pending_dev_disc_dialog_token = 0;
+}
+
+
+void p2p_process_go_disc_req(struct p2p_data *p2p, const u8 *da, const u8 *sa,
+                            const u8 *data, size_t len, int rx_freq)
+{
+       unsigned int tu;
+       struct wpabuf *ies;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "P2P: Received GO Discoverability Request - remain awake for "
+               "100 TU");
+
+       ies = p2p_build_probe_resp_ies(p2p);
+       if (ies == NULL)
+               return;
+
+       /* Remain awake 100 TU on operating channel */
+       p2p->pending_client_disc_freq = rx_freq;
+       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");
+       }
+       wpabuf_free(ies);
+}
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
new file mode 100644 (file)
index 0000000..eb85f51
--- /dev/null
@@ -0,0 +1,1114 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "common/ieee802_11_defs.h"
+#include "wps/wps_defs.h"
+#include "p2p_i.h"
+#include "p2p.h"
+
+
+static int p2p_go_det(u8 own_intent, u8 peer_value)
+{
+       u8 peer_intent = peer_value >> 1;
+       if (own_intent == peer_intent) {
+               if (own_intent == P2P_MAX_GO_INTENT)
+                       return -1; /* both devices want to become GO */
+
+               /* Use tie breaker bit to determine GO */
+               return (peer_value & 0x01) ? 0 : 1;
+       }
+
+       return own_intent > peer_intent;
+}
+
+
+int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
+                           struct p2p_device *dev,
+                           const u8 *channel_list, size_t channel_list_len)
+{
+       const u8 *pos, *end;
+       struct p2p_channels *ch;
+       size_t channels;
+       struct p2p_channels intersection;
+
+       ch = &dev->channels;
+       os_memset(ch, 0, sizeof(*ch));
+       pos = channel_list;
+       end = channel_list + channel_list_len;
+
+       if (end - pos < 3)
+               return -1;
+       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->cfg->country[0], p2p->cfg->country[1],
+                       pos[0], pos[1]);
+               return -1;
+       }
+       pos += 3;
+
+       while (pos + 2 < end) {
+               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");
+                       return -1;
+               }
+               channels = *pos++;
+               cl->channels = channels > P2P_MAX_REG_CLASS_CHANNELS ?
+                       P2P_MAX_REG_CLASS_CHANNELS : channels;
+               os_memcpy(cl->channel, pos, cl->channels);
+               pos += channels;
+               ch->reg_classes++;
+               if (ch->reg_classes == P2P_MAX_REG_CLASSES)
+                       break;
+       }
+
+       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",
+               (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");
+               return -1;
+       }
+       return 0;
+}
+
+
+static int p2p_peer_channels(struct p2p_data *p2p, struct p2p_device *dev,
+                            const u8 *channel_list, size_t channel_list_len)
+{
+       return p2p_peer_channels_check(p2p, &p2p->channels, dev,
+                                      channel_list, channel_list_len);
+}
+
+
+static u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method)
+{
+       switch (wps_method) {
+       case WPS_PIN_DISPLAY:
+               return DEV_PW_REGISTRAR_SPECIFIED;
+       case WPS_PIN_KEYPAD:
+               return DEV_PW_USER_SPECIFIED;
+       case WPS_PBC:
+               return DEV_PW_PUSHBUTTON;
+       default:
+               return DEV_PW_DEFAULT;
+       }
+}
+
+
+static const char * p2p_wps_method_str(enum p2p_wps_method wps_method)
+{
+       switch (wps_method) {
+       case WPS_PIN_DISPLAY:
+               return "Display";
+       case WPS_PIN_KEYPAD:
+               return "Keypad";
+       case WPS_PBC:
+               return "PBC";
+       default:
+               return "??";
+       }
+}
+
+
+static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
+                                           struct p2p_device *peer)
+{
+       struct wpabuf *buf;
+       u8 *len;
+       u8 group_capab;
+
+       buf = wpabuf_alloc(1000);
+       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);
+       group_capab = 0;
+       if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
+               group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+               if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+                       group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+       }
+       if (p2p->cross_connect)
+               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_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class,
+                                  p2p->cfg->channel);
+       if (p2p->ext_listen_interval)
+               p2p_buf_add_ext_listen_timing(buf, p2p->ext_listen_period,
+                                             p2p->ext_listen_interval);
+       p2p_buf_add_intended_addr(buf, p2p->intended_addr);
+       p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels);
+       p2p_buf_add_device_info(buf, p2p, peer);
+       p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+                                     p2p->op_reg_class, p2p->op_channel);
+       p2p_buf_update_ie_hdr(buf, len);
+
+       /* WPS IE with Device Password ID attribute */
+       p2p_build_wps_ie(p2p, buf, p2p_wps_method_pw_id(peer->wps_method), 0);
+
+       return buf;
+}
+
+
+int p2p_connect_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) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: No Listen/Operating frequency known for the "
+                       "peer " MACSTR " to send GO Negotiation Request",
+                       MAC2STR(dev->info.p2p_device_addr));
+               return -1;
+       }
+
+       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_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,
+                           p2p->cfg->dev_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");
+               /* Use P2P find to recover and retry */
+               p2p_set_timeout(p2p, 0, 0);
+       }
+
+       wpabuf_free(req);
+
+       return 0;
+}
+
+
+static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
+                                            struct p2p_device *peer,
+                                            u8 dialog_token, u8 status,
+                                            u8 tie_breaker)
+{
+       struct wpabuf *buf;
+       u8 *len;
+       u8 group_capab;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "P2P: Building GO Negotiation Response");
+       buf = wpabuf_alloc(1000);
+       if (buf == NULL)
+               return NULL;
+
+       p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_RESP, dialog_token);
+
+       len = p2p_buf_add_ie_hdr(buf);
+       p2p_buf_add_status(buf, status);
+       group_capab = 0;
+       if (peer && peer->go_state == LOCAL_GO) {
+               if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
+                       group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+                       if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+                               group_capab |=
+                                       P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+               }
+               if (p2p->cross_connect)
+                       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) | tie_breaker);
+       p2p_buf_add_config_timeout(buf, 100, 20);
+       if (peer && peer->go_state == REMOTE_GO) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Omit Operating "
+                       "Channel attribute");
+       } else {
+               p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+                                             p2p->op_reg_class,
+                                             p2p->op_channel);
+       }
+       p2p_buf_add_intended_addr(buf, p2p->intended_addr);
+       if (status || peer == NULL) {
+               p2p_buf_add_channel_list(buf, p2p->cfg->country,
+                                        &p2p->channels);
+       } else if (peer->go_state == REMOTE_GO) {
+               p2p_buf_add_channel_list(buf, p2p->cfg->country,
+                                        &p2p->channels);
+       } else {
+               struct p2p_channels res;
+               p2p_channels_intersect(&p2p->channels, &peer->channels,
+                                      &res);
+               p2p_buf_add_channel_list(buf, p2p->cfg->country, &res);
+       }
+       p2p_buf_add_device_info(buf, p2p, peer);
+       if (peer && peer->go_state == LOCAL_GO) {
+               p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid,
+                                    p2p->ssid_len);
+       }
+       p2p_buf_update_ie_hdr(buf, len);
+
+       /* WPS IE with Device Password ID attribute */
+       p2p_build_wps_ie(p2p, buf,
+                        p2p_wps_method_pw_id(peer ? peer->wps_method :
+                                             WPS_NOT_READY), 0);
+
+       return buf;
+}
+
+
+static 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;
+
+       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);
+
+       /* 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);
+       if (freq >= 2400 && freq < 2500 && p2p->best_freq_5 > 0 &&
+           p2p_freq_to_channel(p2p->cfg->country, 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",
+                       op_reg_class, op_channel);
+               p2p->op_reg_class = op_reg_class;
+               p2p->op_channel = op_channel;
+               return;
+       }
+
+       if (freq >= 4900 && freq < 6000 && p2p->best_freq_24 > 0 &&
+           p2p_freq_to_channel(p2p->cfg->country, 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",
+                       op_reg_class, op_channel);
+               p2p->op_reg_class = op_reg_class;
+               p2p->op_channel = 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",
+               cl->reg_class, cl->channel[0]);
+       p2p->op_reg_class = cl->reg_class;
+       p2p->op_channel = cl->channel[0];
+}
+
+
+void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
+                           const u8 *data, size_t len, int rx_freq)
+{
+       struct p2p_device *dev = NULL;
+       struct wpabuf *resp;
+       struct p2p_message msg;
+       u8 status = P2P_SC_FAIL_INVALID_PARAMS;
+       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);
+
+       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");
+#ifdef CONFIG_P2P_STRICT
+               goto fail;
+#endif /* CONFIG_P2P_STRICT */
+       }
+
+       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");
+#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");
+#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");
+               goto fail;
+       }
+       if (!msg.operating_channel) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "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");
+               goto fail;
+       }
+       if (!msg.intended_addr) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "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");
+               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
+                       " != dev_addr=" MACSTR,
+                       MAC2STR(sa), MAC2STR(msg.p2p_device_addr));
+               goto fail;
+       }
+
+       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);
+               goto fail;
+       }
+
+       if (dev == NULL)
+               dev = p2p_add_dev_from_go_neg_req(p2p, sa, &msg);
+       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");
+               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,
+                       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");
+               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");
+                       if (!(dev->flags & P2P_DEV_FORCE_FREQ)) {
+                               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                                       "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");
+                       }
+               }
+
+               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");
+                       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",
+                               *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_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");
+                       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");
+                       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");
+                       if (dev->wps_method != WPS_PIN_KEYPAD) {
+                               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                                       "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");
+                       if (dev->wps_method != WPS_PIN_DISPLAY) {
+                               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                                       "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");
+                       if (dev->wps_method != WPS_PBC) {
+                               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                                       "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",
+                               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;
+                       }
+               }
+
+               dev->go_state = go ? LOCAL_GO : REMOTE_GO;
+               dev->oper_freq = p2p_channel_to_freq((const char *)
+                                                    msg.operating_channel,
+                                                    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);
+
+               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));
+               if (p2p->state != P2P_IDLE)
+                       p2p_stop_find_for_freq(p2p, rx_freq);
+               p2p_set_state(p2p, P2P_GO_NEG);
+               p2p_clear_timeout(p2p);
+               dev->dialog_token = msg.dialog_token;
+               os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN);
+               p2p->go_neg_peer = dev;
+               status = P2P_SC_SUCCESS;
+       }
+
+fail:
+       if (dev)
+               dev->status = status;
+       resp = p2p_build_go_neg_resp(p2p, dev, msg.dialog_token, status,
+                                    !tie_breaker);
+       p2p_parse_free(&msg);
+       if (resp == NULL)
+               return;
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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,
+                                          p2p->cfg->channel);
+       if (freq < 0) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "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;
+       } 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");
+       }
+
+       wpabuf_free(resp);
+}
+
+
+static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
+                                            struct p2p_device *peer,
+                                            u8 dialog_token, u8 status,
+                                            const u8 *resp_chan, int go)
+{
+       struct wpabuf *buf;
+       u8 *len;
+       struct p2p_channels res;
+       u8 group_capab;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "P2P: Building GO Negotiation Confirm");
+       buf = wpabuf_alloc(1000);
+       if (buf == NULL)
+               return NULL;
+
+       p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_CONF, dialog_token);
+
+       len = p2p_buf_add_ie_hdr(buf);
+       p2p_buf_add_status(buf, status);
+       group_capab = 0;
+       if (peer->go_state == LOCAL_GO) {
+               if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
+                       group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+                       if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+                               group_capab |=
+                                       P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+               }
+               if (p2p->cross_connect)
+                       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);
+       if (go || resp_chan == NULL)
+               p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+                                             p2p->op_reg_class,
+                                             p2p->op_channel);
+       else
+               p2p_buf_add_operating_channel(buf, (const char *) resp_chan,
+                                             resp_chan[3], resp_chan[4]);
+       p2p_channels_intersect(&p2p->channels, &peer->channels, &res);
+       p2p_buf_add_channel_list(buf, p2p->cfg->country, &res);
+       if (go) {
+               p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid,
+                                    p2p->ssid_len);
+       }
+       p2p_buf_update_ie_hdr(buf, len);
+
+       return buf;
+}
+
+
+void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
+                            const u8 *data, size_t len, int rx_freq)
+{
+       struct p2p_device *dev;
+       struct wpabuf *conf;
+       int go = -1;
+       struct p2p_message msg;
+       u8 status = P2P_SC_SUCCESS;
+       int freq;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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,
+                       MAC2STR(sa));
+               return;
+       }
+
+       if (p2p_parse(data, len, &msg))
+               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_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)",
+                       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");
+               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);
+               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");
+                       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_go_neg_failed(p2p, dev, *msg.status);
+               }
+               p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+               p2p_parse_free(&msg);
+               return;
+       }
+
+       if (!msg.capability) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Mandatory Capability attribute missing from GO "
+                       "Negotiation Response");
+#ifdef CONFIG_P2P_STRICT
+               status = P2P_SC_FAIL_INVALID_PARAMS;
+               goto fail;
+#endif /* CONFIG_P2P_STRICT */
+       }
+
+       if (!msg.p2p_device_info) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Mandatory P2P Device Info attribute missing "
+                       "from GO Negotiation Response");
+#ifdef CONFIG_P2P_STRICT
+               status = P2P_SC_FAIL_INVALID_PARAMS;
+               goto fail;
+#endif /* CONFIG_P2P_STRICT */
+       }
+
+       if (!msg.intended_addr) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "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");
+               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",
+                       *msg.go_intent >> 1);
+               status = P2P_SC_FAIL_INVALID_PARAMS;
+               goto fail;
+       }
+
+       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");
+               status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+               goto fail;
+       }
+
+       if (!go && msg.group_id) {
+               /* Store SSID for Provisioning step */
+               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->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");
+#ifdef CONFIG_P2P_STRICT
+               status = P2P_SC_FAIL_INVALID_PARAMS;
+               goto fail;
+#endif /* CONFIG_P2P_STRICT */
+       } else {
+               dev->go_timeout = msg.config_timeout[0];
+               dev->client_timeout = msg.config_timeout[1];
+       }
+
+       if (!msg.operating_channel && !go) {
+               /*
+                * 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");
+               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");
+               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");
+               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],
+                                                    msg.operating_channel[4]);
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "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");
+               if (dev->wps_method != WPS_PIN_KEYPAD) {
+                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                               "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");
+               if (dev->wps_method != WPS_PIN_DISPLAY) {
+                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                               "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");
+               if (dev->wps_method != WPS_PBC) {
+                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                               "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",
+                       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;
+               }
+       }
+
+       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));
+       os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN);
+
+fail:
+       conf = p2p_build_go_neg_conf(p2p, dev, msg.dialog_token, status,
+                                    msg.operating_channel, go);
+       p2p_parse_free(&msg);
+       if (conf == NULL)
+               return;
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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;
+       } else
+               p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+       if (rx_freq > 0)
+               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");
+               p2p_go_neg_failed(p2p, dev, -1);
+       }
+       wpabuf_free(conf);
+}
+
+
+void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
+                            const u8 *data, size_t len)
+{
+       struct p2p_device *dev;
+       struct p2p_message msg;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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,
+                       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->pending_action_state = P2P_NO_PENDING_ACTION;
+       }
+
+       if (p2p_parse(data, len, &msg))
+               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");
+               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)",
+                       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_parse_free(&msg);
+               return;
+       }
+       if (*msg.status) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: GO Negotiation rejected: status %d",
+                       *msg.status);
+               p2p_parse_free(&msg);
+               return;
+       }
+
+       if (dev->go_state == REMOTE_GO && msg.group_id) {
+               /* Store SSID for Provisioning step */
+               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->ssid_len = 0;
+#ifdef CONFIG_P2P_STRICT
+               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");
+#ifdef CONFIG_P2P_STRICT
+               p2p_parse_free(&msg);
+               return;
+#endif /* CONFIG_P2P_STRICT */
+       }
+
+       if (!msg.channel_list) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Mandatory Operating Channel attribute missing "
+                       "from GO Negotiation Confirmation");
+#ifdef CONFIG_P2P_STRICT
+               p2p_parse_free(&msg);
+               return;
+#endif /* CONFIG_P2P_STRICT */
+       }
+
+       p2p_parse_free(&msg);
+
+       if (dev->go_state == UNKNOWN_GO) {
+               /*
+                * 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");
+               return;
+       }
+
+       p2p_go_complete(p2p, dev);
+}
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
new file mode 100644 (file)
index 0000000..59d1507
--- /dev/null
@@ -0,0 +1,701 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "wps/wps_defs.h"
+#include "wps/wps_i.h"
+#include "p2p_i.h"
+#include "p2p.h"
+
+
+struct p2p_group_member {
+       struct p2p_group_member *next;
+       u8 addr[ETH_ALEN]; /* P2P Interface Address */
+       u8 dev_addr[ETH_ALEN]; /* P2P Device Address */
+       struct wpabuf *p2p_ie;
+       struct wpabuf *client_info;
+       u8 dev_capab;
+};
+
+/**
+ * struct p2p_group - Internal P2P module per-group data
+ */
+struct p2p_group {
+       struct p2p_data *p2p;
+       struct p2p_group_config *cfg;
+       struct p2p_group_member *members;
+       unsigned int num_members;
+       int group_formation;
+       int beacon_update;
+       struct wpabuf *noa;
+};
+
+
+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)
+{
+       struct p2p_group *group, **groups;
+
+       group = os_zalloc(sizeof(*group));
+       if (group == NULL)
+               return NULL;
+
+       groups = os_realloc(p2p->groups, (p2p->num_groups + 1) *
+                           sizeof(struct p2p_group *));
+       if (groups == NULL) {
+               os_free(group);
+               return NULL;
+       }
+       groups[p2p->num_groups++] = group;
+       p2p->groups = groups;
+
+       group->p2p = p2p;
+       group->cfg = config;
+       group->group_formation = 1;
+       group->beacon_update = 1;
+       p2p_group_update_ies(group);
+       group->cfg->idle_update(group->cfg->cb_ctx, 1);
+
+       return group;
+}
+
+
+static void p2p_group_free_member(struct p2p_group_member *m)
+{
+       wpabuf_free(m->p2p_ie);
+       wpabuf_free(m->client_info);
+       os_free(m);
+}
+
+
+static void p2p_group_free_members(struct p2p_group *group)
+{
+       struct p2p_group_member *m, *prev;
+       m = group->members;
+       group->members = NULL;
+       group->num_members = 0;
+       while (m) {
+               prev = m;
+               m = m->next;
+               p2p_group_free_member(prev);
+       }
+}
+
+
+void p2p_group_deinit(struct p2p_group *group)
+{
+       size_t g;
+       struct p2p_data *p2p;
+
+       if (group == NULL)
+               return;
+
+       p2p = group->p2p;
+
+       for (g = 0; g < p2p->num_groups; g++) {
+               if (p2p->groups[g] == group) {
+                       while (g + 1 < p2p->num_groups) {
+                               p2p->groups[g] = p2p->groups[g + 1];
+                               g++;
+                       }
+                       p2p->num_groups--;
+                       break;
+               }
+       }
+
+       p2p_group_free_members(group);
+       os_free(group->cfg);
+       wpabuf_free(group->noa);
+       os_free(group);
+}
+
+
+static void p2p_client_info(struct wpabuf *ie, struct p2p_group_member *m)
+{
+       if (m->client_info == NULL)
+               return;
+       if (wpabuf_tailroom(ie) < wpabuf_len(m->client_info) + 1)
+               return;
+       wpabuf_put_buf(ie, m->client_info);
+}
+
+
+static void p2p_group_add_common_ies(struct p2p_group *group,
+                                    struct wpabuf *ie)
+{
+       u8 dev_capab = 0, group_capab = 0;
+
+       /* P2P Capability */
+       dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
+       dev_capab |= P2P_DEV_CAPAB_INVITATION_PROCEDURE;
+       group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER;
+       if (group->cfg->persistent_group) {
+               group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+               if (group->cfg->persistent_group == 2)
+                       group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+       }
+       if (group->p2p->cfg->p2p_intra_bss)
+               group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
+       if (group->group_formation)
+               group_capab |= P2P_GROUP_CAPAB_GROUP_FORMATION;
+       if (group->p2p->cross_connect)
+               group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
+       if (group->num_members >= group->cfg->max_clients)
+               group_capab |= P2P_GROUP_CAPAB_GROUP_LIMIT;
+       p2p_buf_add_capability(ie, dev_capab, group_capab);
+}
+
+
+static void p2p_group_add_noa(struct wpabuf *ie, struct wpabuf *noa)
+{
+       if (noa == NULL)
+               return;
+       /* Notice of Absence */
+       wpabuf_put_u8(ie, P2P_ATTR_NOTICE_OF_ABSENCE);
+       wpabuf_put_le16(ie, wpabuf_len(noa));
+       wpabuf_put_buf(ie, noa);
+}
+
+
+static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
+{
+       struct wpabuf *ie;
+       u8 *len;
+
+       ie = wpabuf_alloc(257);
+       if (ie == NULL)
+               return NULL;
+
+       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);
+       p2p_group_add_noa(ie, group->noa);
+       p2p_buf_update_ie_hdr(ie, len);
+
+       return ie;
+}
+
+
+static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
+{
+       u8 *group_info;
+       struct wpabuf *ie;
+       struct p2p_group_member *m;
+       u8 *len;
+
+       ie = wpabuf_alloc(257);
+       if (ie == NULL)
+               return NULL;
+
+       len = p2p_buf_add_ie_hdr(ie);
+
+       p2p_group_add_common_ies(group, ie);
+       p2p_group_add_noa(ie, group->noa);
+
+       /* P2P Device Info */
+       p2p_buf_add_device_info(ie, group->p2p, NULL);
+
+       /* 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);
+
+       p2p_buf_update_ie_hdr(ie, len);
+       return ie;
+}
+
+
+static void p2p_group_update_ies(struct p2p_group *group)
+{
+       struct wpabuf *beacon_ie;
+       struct wpabuf *probe_resp_ie;
+
+       probe_resp_ie = p2p_group_build_probe_resp_ie(group);
+       if (probe_resp_ie == NULL)
+               return;
+       wpa_hexdump_buf(MSG_MSGDUMP, "P2P: Update GO Probe Response P2P IE",
+                       probe_resp_ie);
+
+       if (group->beacon_update) {
+               beacon_ie = p2p_group_build_beacon_ie(group);
+               if (beacon_ie)
+                       group->beacon_update = 0;
+               wpa_hexdump_buf(MSG_MSGDUMP, "P2P: Update GO Beacon P2P IE",
+                               beacon_ie);
+       } else
+               beacon_ie = NULL;
+
+       group->cfg->ie_update(group->cfg->cb_ctx, beacon_ie, probe_resp_ie);
+}
+
+
+/**
+ * p2p_build_client_info - Build P2P Client Info Descriptor
+ * @addr: MAC address of the peer device
+ * @p2p_ie: P2P IE from (Re)Association Request
+ * @dev_capab: Buffer for returning Device Capability
+ * @dev_addr: Buffer for returning P2P Device Address
+ * Returns: P2P Client Info Descriptor or %NULL on failure
+ *
+ * This function builds P2P Client Info Descriptor based on the information
+ * available from (Re)Association Request frame. Group owner can use this to
+ * build the P2P Group Info attribute for Probe Response frames.
+ */
+static struct wpabuf * p2p_build_client_info(const u8 *addr,
+                                            struct wpabuf *p2p_ie,
+                                            u8 *dev_capab, u8 *dev_addr)
+{
+       const u8 *spos;
+       struct p2p_message msg;
+       u8 *len_pos;
+       struct wpabuf *buf;
+
+       if (p2p_ie == NULL)
+               return NULL;
+
+       os_memset(&msg, 0, sizeof(msg));
+       if (p2p_parse_p2p_ie(p2p_ie, &msg) ||
+           msg.capability == NULL || msg.p2p_device_info == NULL)
+               return NULL;
+
+       buf = wpabuf_alloc(ETH_ALEN + 1 + 1 + msg.p2p_device_info_len);
+       if (buf == NULL)
+               return NULL;
+
+       *dev_capab = msg.capability[0];
+       os_memcpy(dev_addr, msg.p2p_device_addr, ETH_ALEN);
+
+       spos = msg.p2p_device_info; /* P2P Device address */
+
+       /* P2P Client Info Descriptor */
+       /* Length to be set */
+       len_pos = wpabuf_put(buf, 1);
+       /* P2P Device address */
+       wpabuf_put_data(buf, spos, ETH_ALEN);
+       /* P2P Interface address */
+       wpabuf_put_data(buf, addr, ETH_ALEN);
+       /* Device Capability Bitmap */
+       wpabuf_put_u8(buf, msg.capability[0]);
+       /*
+        * Config Methods, Primary Device Type, Number of Secondary Device
+        * Types, Secondary Device Type List, Device Name copied from
+        * Device Info
+        */
+       wpabuf_put_data(buf, spos + ETH_ALEN,
+                       msg.p2p_device_info_len - ETH_ALEN);
+
+       *len_pos = wpabuf_len(buf) - 1;
+
+
+       return buf;
+}
+
+
+static int p2p_group_remove_member(struct p2p_group *group, const u8 *addr)
+{
+       struct p2p_group_member *m, *prev;
+
+       if (group == NULL)
+               return 0;
+
+       m = group->members;
+       prev = NULL;
+       while (m) {
+               if (os_memcmp(m->addr, addr, ETH_ALEN) == 0)
+                       break;
+               prev = m;
+               m = m->next;
+       }
+
+       if (m == NULL)
+               return 0;
+
+       if (prev)
+               prev->next = m->next;
+       else
+               group->members = m->next;
+       p2p_group_free_member(m);
+       group->num_members--;
+
+       return 1;
+}
+
+
+int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
+                         const u8 *ie, size_t len)
+{
+       struct p2p_group_member *m;
+
+       if (group == NULL)
+               return -1;
+
+       m = os_zalloc(sizeof(*m));
+       if (m == NULL)
+               return -1;
+       os_memcpy(m->addr, addr, ETH_ALEN);
+       m->p2p_ie = ieee802_11_vendor_ie_concat(ie, len, P2P_IE_VENDOR_TYPE);
+       if (m->p2p_ie) {
+               m->client_info = p2p_build_client_info(addr, m->p2p_ie,
+                                                      &m->dev_capab,
+                                                      m->dev_addr);
+       }
+
+       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,
+               group->num_members, group->cfg->max_clients);
+       if (group->num_members == group->cfg->max_clients)
+               group->beacon_update = 1;
+       p2p_group_update_ies(group);
+       if (group->num_members == 1)
+               group->cfg->idle_update(group->cfg->cb_ctx, 0);
+
+       return 0;
+}
+
+
+struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
+{
+       struct wpabuf *resp;
+       u8 *rlen;
+
+       /*
+        * (Re)Association Response - P2P IE
+        * Status attribute (shall be present when association request is
+        *      denied)
+        * Extended Listen Timing (may be present)
+        */
+       resp = wpabuf_alloc(20);
+       if (resp == NULL)
+               return NULL;
+       rlen = p2p_buf_add_ie_hdr(resp);
+       if (status != P2P_SC_SUCCESS)
+               p2p_buf_add_status(resp, status);
+       p2p_buf_update_ie_hdr(resp, rlen);
+
+       return resp;
+}
+
+
+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",
+                       MAC2STR(addr), group->num_members,
+                       group->cfg->max_clients);
+               if (group->num_members == group->cfg->max_clients - 1)
+                       group->beacon_update = 1;
+               p2p_group_update_ies(group);
+               if (group->num_members == 0)
+                       group->cfg->idle_update(group->cfg->cb_ctx, 1);
+       }
+}
+
+
+/**
+ * p2p_match_dev_type_member - Match client device type with requested type
+ * @m: Group member
+ * @wps: WPS TLVs from Probe Request frame (concatenated WPS IEs)
+ * Returns: 1 on match, 0 on mismatch
+ *
+ * This function can be used to match the Requested Device Type attribute in
+ * WPS IE with the device types of a group member for deciding whether a GO
+ * should reply to a Probe Request frame.
+ */
+static int p2p_match_dev_type_member(struct p2p_group_member *m,
+                                    struct wpabuf *wps)
+{
+       const u8 *pos, *end;
+       struct wps_parse_attr attr;
+       u8 num_sec;
+
+       if (m->client_info == NULL || wps == NULL)
+               return 0;
+
+       pos = wpabuf_head(m->client_info);
+       end = pos + wpabuf_len(m->client_info);
+
+       pos += 1 + 2 * ETH_ALEN + 1 + 2;
+       if (end - pos < WPS_DEV_TYPE_LEN + 1)
+               return 0;
+
+       if (wps_parse_msg(wps, &attr))
+               return 1; /* assume no Requested Device Type attributes */
+
+       if (attr.num_req_dev_type == 0)
+               return 1; /* no Requested Device Type attributes -> match */
+
+       if (dev_type_list_match(pos, attr.req_dev_type, attr.num_req_dev_type))
+               return 1; /* Match with client Primary Device Type */
+
+       pos += WPS_DEV_TYPE_LEN;
+       num_sec = *pos++;
+       if (end - pos < num_sec * WPS_DEV_TYPE_LEN)
+               return 0;
+       while (num_sec > 0) {
+               num_sec--;
+               if (dev_type_list_match(pos, attr.req_dev_type,
+                                       attr.num_req_dev_type))
+                       return 1; /* Match with client Secondary Device Type */
+               pos += WPS_DEV_TYPE_LEN;
+       }
+
+       /* No matching device type found */
+       return 0;
+}
+
+
+int p2p_group_match_dev_type(struct p2p_group *group, struct wpabuf *wps)
+{
+       struct p2p_group_member *m;
+
+       if (p2p_match_dev_type(group->p2p, wps))
+               return 1; /* Match with own device type */
+
+       for (m = group->members; m; m = m->next) {
+               if (p2p_match_dev_type_member(m, wps))
+                       return 1; /* Match with group client device type */
+       }
+
+       /* No match with Requested Device Type */
+       return 0;
+}
+
+
+void p2p_group_notif_formation_done(struct p2p_group *group)
+{
+       if (group == NULL)
+               return;
+       group->group_formation = 0;
+       group->beacon_update = 1;
+       p2p_group_update_ies(group);
+}
+
+
+int p2p_group_notif_noa(struct p2p_group *group, const u8 *noa,
+                       size_t noa_len)
+{
+       if (noa == NULL) {
+               wpabuf_free(group->noa);
+               group->noa = NULL;
+       } else {
+               if (group->noa) {
+                       if (wpabuf_size(group->noa) >= noa_len) {
+                               group->noa->used = 0;
+                               wpabuf_put_data(group->noa, noa, noa_len);
+                       } else {
+                               wpabuf_free(group->noa);
+                               group->noa = NULL;
+                       }
+               }
+
+               if (!group->noa) {
+                       group->noa = wpabuf_alloc_copy(noa, noa_len);
+                       if (group->noa == NULL)
+                               return -1;
+               }
+       }
+
+       group->beacon_update = 1;
+       p2p_group_update_ies(group);
+       return 0;
+}
+
+
+static struct p2p_group_member * p2p_group_get_client(struct p2p_group *group,
+                                                     const u8 *dev_id)
+{
+       struct p2p_group_member *m;
+
+       for (m = group->members; m; m = m->next) {
+               if (os_memcmp(dev_id, m->dev_addr, ETH_ALEN) == 0)
+                       return m;
+       }
+
+       return NULL;
+}
+
+
+static struct p2p_group_member * p2p_group_get_client_iface(
+       struct p2p_group *group, const u8 *interface_addr)
+{
+       struct p2p_group_member *m;
+
+       for (m = group->members; m; m = m->next) {
+               if (os_memcmp(interface_addr, m->addr, ETH_ALEN) == 0)
+                       return m;
+       }
+
+       return NULL;
+}
+
+
+const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr)
+{
+       struct p2p_group_member *m;
+
+       if (group == NULL)
+               return NULL;
+       m = p2p_group_get_client_iface(group, addr);
+       if (m && !is_zero_ether_addr(m->dev_addr))
+               return m->dev_addr;
+       return NULL;
+}
+
+
+static struct wpabuf * p2p_build_go_disc_req(void)
+{
+       struct wpabuf *buf;
+
+       buf = wpabuf_alloc(100);
+       if (buf == NULL)
+               return NULL;
+
+       p2p_buf_add_action_hdr(buf, P2P_GO_DISC_REQ, 0);
+
+       return buf;
+}
+
+
+int p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id,
+                         const u8 *searching_dev, int rx_freq)
+{
+       struct p2p_group_member *m;
+       struct wpabuf *req;
+       struct p2p_data *p2p = group->p2p;
+       int freq;
+
+       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));
+               return -1;
+       }
+
+       if (!(m->dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
+               wpa_printf(MSG_DEBUG, "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));
+
+       req = p2p_build_go_disc_req();
+       if (req == NULL)
+               return -1;
+
+       /* TODO: Should really use group operating frequency here */
+       freq = rx_freq;
+
+       p2p->pending_action_state = P2P_PENDING_GO_DISC_REQ;
+       if (p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, m->addr,
+                                 group->cfg->interface_addr,
+                                 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");
+       }
+
+       wpabuf_free(req);
+
+       return 0;
+}
+
+
+const u8 * p2p_group_get_interface_addr(struct p2p_group *group)
+{
+       return group->cfg->interface_addr;
+}
+
+
+u8 p2p_group_presence_req(struct p2p_group *group,
+                         const u8 *client_interface_addr,
+                         const u8 *noa, size_t noa_len)
+{
+       struct p2p_group_member *m;
+       u8 curr_noa[50];
+       int curr_noa_len;
+
+       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");
+               return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
+       }
+
+       wpa_hexdump(MSG_DEBUG, "P2P: Presence Request NoA", noa, noa_len);
+
+       if (group->p2p->cfg->get_noa)
+               curr_noa_len = group->p2p->cfg->get_noa(
+                       group->p2p->cfg->cb_ctx, group->cfg->interface_addr,
+                       curr_noa, sizeof(curr_noa));
+       else
+               curr_noa_len = -1;
+       if (curr_noa_len < 0)
+               wpa_printf(MSG_DEBUG, "P2P: Failed to fetch current NoA");
+       else if (curr_noa_len == 0)
+               wpa_printf(MSG_DEBUG, "P2P: No NoA being advertized");
+       else
+               wpa_hexdump(MSG_DEBUG, "P2P: Current NoA", curr_noa,
+                           curr_noa_len);
+
+       /* TODO: properly process request and store copy */
+       if (curr_noa_len > 0 || curr_noa_len == -1)
+               return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
+
+       return P2P_SC_SUCCESS;
+}
+
+
+unsigned int p2p_get_group_num_members(struct p2p_group *group)
+{
+       return group->num_members;
+}
+
+
+const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next)
+{
+       struct p2p_group_member *iter = *next;
+
+       if (!iter)
+               iter = group->members;
+       else
+               iter = iter->next;
+
+       *next = iter;
+
+       if (!iter)
+               return NULL;
+
+       return iter->addr;
+}
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
new file mode 100644 (file)
index 0000000..0dc33e7
--- /dev/null
@@ -0,0 +1,673 @@
+/*
+ * 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.
+ */
+
+#ifndef P2P_I_H
+#define P2P_I_H
+
+#include "utils/list.h"
+#include "p2p.h"
+
+enum p2p_go_state {
+       UNKNOWN_GO,
+       LOCAL_GO,
+       REMOTE_GO
+};
+
+/**
+ * struct p2p_device - P2P Device data (internal to P2P module)
+ */
+struct p2p_device {
+       struct dl_list list;
+       struct os_time last_seen;
+       int listen_freq;
+       enum p2p_wps_method wps_method;
+
+       struct p2p_peer_info info;
+
+       /*
+        * If the peer was discovered based on an interface address (e.g., GO
+        * from Beacon/Probe Response), the interface address is stored here.
+        * p2p_device_addr must still be set in such a case to the unique
+        * identifier for the P2P Device.
+        */
+       u8 interface_addr[ETH_ALEN];
+
+       /*
+        * P2P Device Address of the GO in whose group this P2P Device is a
+        * client.
+        */
+       u8 member_in_go_dev[ETH_ALEN];
+
+       /*
+        * P2P Interface Address of the GO in whose group this P2P Device is a
+        * client.
+        */
+       u8 member_in_go_iface[ETH_ALEN];
+
+       int go_neg_req_sent;
+       enum p2p_go_state go_state;
+       u8 dialog_token;
+       u8 intended_addr[ETH_ALEN];
+
+       char country[3];
+       struct p2p_channels channels;
+       int oper_freq;
+       u8 oper_ssid[32];
+       size_t oper_ssid_len;
+
+       /**
+        * req_config_methods - Pending provision discovery methods
+        */
+       u16 req_config_methods;
+
+       /**
+        * wps_prov_info - Stored provisioning WPS config method
+        *
+        * This is used to store pending WPS config method between Provisioning
+        * Discovery and connection to a running group.
+        */
+       u16 wps_prov_info;
+
+#define P2P_DEV_PROBE_REQ_ONLY BIT(0)
+#define P2P_DEV_REPORTED BIT(1)
+#define P2P_DEV_NOT_YET_READY BIT(2)
+#define P2P_DEV_SD_INFO BIT(3)
+#define P2P_DEV_SD_SCHEDULE BIT(4)
+#define P2P_DEV_PD_PEER_DISPLAY BIT(5)
+#define P2P_DEV_PD_PEER_KEYPAD BIT(6)
+#define P2P_DEV_USER_REJECTED BIT(7)
+#define P2P_DEV_PEER_WAITING_RESPONSE BIT(8)
+#define P2P_DEV_PREFER_PERSISTENT_GROUP BIT(9)
+#define P2P_DEV_WAIT_GO_NEG_RESPONSE BIT(10)
+#define P2P_DEV_WAIT_GO_NEG_CONFIRM BIT(11)
+#define P2P_DEV_GROUP_CLIENT_ONLY BIT(12)
+#define P2P_DEV_FORCE_FREQ BIT(13)
+#define P2P_DEV_PD_FOR_JOIN BIT(14)
+#define P2P_DEV_REPORTED_ONCE BIT(15)
+#define P2P_DEV_PREFER_PERSISTENT_RECONN BIT(16)
+       unsigned int flags;
+
+       int status; /* enum p2p_status_code */
+       unsigned int wait_count;
+       unsigned int connect_reqs;
+       unsigned int invitation_reqs;
+
+       u16 ext_listen_period;
+       u16 ext_listen_interval;
+
+       u8 go_timeout;
+       u8 client_timeout;
+};
+
+struct p2p_sd_query {
+       struct p2p_sd_query *next;
+       u8 peer[ETH_ALEN];
+       int for_all_peers;
+       struct wpabuf *tlvs;
+};
+
+struct p2p_pending_action_tx {
+       unsigned int freq;
+       u8 dst[ETH_ALEN];
+       u8 src[ETH_ALEN];
+       u8 bssid[ETH_ALEN];
+       size_t len;
+       unsigned int wait_time;
+       /* Followed by len octets of the frame */
+};
+
+/**
+ * struct p2p_data - P2P module data (internal to P2P module)
+ */
+struct p2p_data {
+       /**
+        * cfg - P2P module configuration
+        *
+        * This is included in the same memory allocation with the
+        * struct p2p_data and as such, must not be freed separately.
+        */
+       struct p2p_config *cfg;
+
+       /**
+        * state - The current P2P state
+        */
+       enum p2p_state {
+               /**
+                * P2P_IDLE - Idle
+                */
+               P2P_IDLE,
+
+               /**
+                * P2P_SEARCH - Search (Device Discovery)
+                */
+               P2P_SEARCH,
+
+               /**
+                * P2P_CONNECT - Trying to start GO Negotiation
+                */
+               P2P_CONNECT,
+
+               /**
+                * P2P_CONNECT_LISTEN - Listen during GO Negotiation start
+                */
+               P2P_CONNECT_LISTEN,
+
+               /**
+                * P2P_GO_NEG - In GO Negotiation
+                */
+               P2P_GO_NEG,
+
+               /**
+                * P2P_LISTEN_ONLY - Listen only
+                */
+               P2P_LISTEN_ONLY,
+
+               /**
+                * P2P_WAIT_PEER_CONNECT - Waiting peer in List for GO Neg
+                */
+               P2P_WAIT_PEER_CONNECT,
+
+               /**
+                * P2P_WAIT_PEER_IDLE - Waiting peer idle for GO Neg
+                */
+               P2P_WAIT_PEER_IDLE,
+
+               /**
+                * P2P_SD_DURING_FIND - Service Discovery during find
+                */
+               P2P_SD_DURING_FIND,
+
+               /**
+                * P2P_PROVISIONING - Provisioning (during group formation)
+                */
+               P2P_PROVISIONING,
+
+               /**
+                * P2P_PD_DURING_FIND - Provision Discovery during find
+                */
+               P2P_PD_DURING_FIND,
+
+               /**
+                * P2P_INVITE - Trying to start Invite
+                */
+               P2P_INVITE,
+
+               /**
+                * P2P_INVITE_LISTEN - Listen during Invite
+                */
+               P2P_INVITE_LISTEN,
+
+               /**
+                * P2P_SEARCH_WHEN_READY - Waiting to start Search
+                */
+               P2P_SEARCH_WHEN_READY,
+       } state;
+
+       /**
+        * min_disc_int - minDiscoverableInterval
+        */
+       int min_disc_int;
+
+       /**
+        * max_disc_int - maxDiscoverableInterval
+        */
+       int max_disc_int;
+
+       /**
+        * devices - List of known P2P Device peers
+        */
+       struct dl_list devices;
+
+       /**
+        * go_neg_peer - Pointer to GO Negotiation peer
+        */
+       struct p2p_device *go_neg_peer;
+
+       /**
+        * invite_peer - Pointer to Invite peer
+        */
+       struct p2p_device *invite_peer;
+
+       const u8 *invite_go_dev_addr;
+       u8 invite_go_dev_addr_buf[ETH_ALEN];
+
+       /**
+        * sd_peer - Pointer to Service Discovery peer
+        */
+       struct p2p_device *sd_peer;
+
+       /**
+        * sd_query - Pointer to Service Discovery query
+        */
+       struct p2p_sd_query *sd_query;
+
+       /* GO Negotiation data */
+
+       /**
+        * intended_addr - Local Intended P2P Interface Address
+        *
+        * This address is used during group owner negotiation as the Intended
+        * P2P Interface Address and the group interface will be created with
+        * address as the local address in case of successfully completed
+        * negotiation.
+        */
+       u8 intended_addr[ETH_ALEN];
+
+       /**
+        * go_intent - Local GO Intent to be used during GO Negotiation
+        */
+       u8 go_intent;
+
+       /**
+        * next_tie_breaker - Next tie-breaker value to use in GO Negotiation
+        */
+       u8 next_tie_breaker;
+
+       /**
+        * ssid - Selected SSID for GO Negotiation (if local end will be GO)
+        */
+       u8 ssid[32];
+
+       /**
+        * ssid_len - ssid length in octets
+        */
+       size_t ssid_len;
+
+       /**
+        * ssid_set - Whether SSID is already set for GO Negotiation
+        */
+       int ssid_set;
+
+       /**
+        * Regulatory class for own operational channel
+        */
+       u8 op_reg_class;
+
+       /**
+        * op_channel - Own operational channel
+        */
+       u8 op_channel;
+
+       /**
+        * channels - Own supported regulatory classes and channels
+        *
+        * List of supposerted channels per regulatory class. The regulatory
+        * classes are defined in IEEE Std 802.11-2007 Annex J and the
+        * numbering of the clases depends on the configured country code.
+        */
+       struct p2p_channels channels;
+
+       enum p2p_pending_action_state {
+               P2P_NO_PENDING_ACTION,
+               P2P_PENDING_GO_NEG_REQUEST,
+               P2P_PENDING_GO_NEG_RESPONSE,
+               P2P_PENDING_GO_NEG_RESPONSE_FAILURE,
+               P2P_PENDING_GO_NEG_CONFIRM,
+               P2P_PENDING_SD,
+               P2P_PENDING_PD,
+               P2P_PENDING_INVITATION_REQUEST,
+               P2P_PENDING_INVITATION_RESPONSE,
+               P2P_PENDING_DEV_DISC_REQUEST,
+               P2P_PENDING_DEV_DISC_RESPONSE,
+               P2P_PENDING_GO_DISC_REQ
+       } pending_action_state;
+
+       unsigned int pending_listen_freq;
+       unsigned int pending_listen_sec;
+       unsigned int pending_listen_usec;
+
+       u8 dev_capab;
+
+       int in_listen;
+       int drv_in_listen;
+
+       /**
+        * sd_queries - Pending service discovery queries
+        */
+       struct p2p_sd_query *sd_queries;
+
+       /**
+        * srv_update_indic - Service Update Indicator for local services
+        */
+       u16 srv_update_indic;
+
+       struct wpabuf *sd_resp; /* Fragmented SD response */
+       u8 sd_resp_addr[ETH_ALEN];
+       u8 sd_resp_dialog_token;
+       size_t sd_resp_pos; /* Offset in sd_resp */
+       u8 sd_frag_id;
+
+       struct wpabuf *sd_rx_resp; /* Reassembled SD response */
+       u16 sd_rx_update_indic;
+
+       /* P2P Invitation data */
+       enum p2p_invite_role inv_role;
+       u8 inv_bssid[ETH_ALEN];
+       int inv_bssid_set;
+       u8 inv_ssid[32];
+       size_t inv_ssid_len;
+       u8 inv_sa[ETH_ALEN];
+       u8 inv_group_bssid[ETH_ALEN];
+       u8 *inv_group_bssid_ptr;
+       u8 inv_go_dev_addr[ETH_ALEN];
+       u8 inv_status;
+       int inv_op_freq;
+       int inv_persistent;
+
+       enum p2p_discovery_type find_type;
+       unsigned int last_p2p_find_timeout;
+       u8 last_prog_scan_class;
+       u8 last_prog_scan_chan;
+       int p2p_scan_running;
+       enum p2p_after_scan {
+               P2P_AFTER_SCAN_NOTHING,
+               P2P_AFTER_SCAN_LISTEN,
+               P2P_AFTER_SCAN_CONNECT
+       } start_after_scan;
+       u8 after_scan_peer[ETH_ALEN];
+       struct p2p_pending_action_tx *after_scan_tx;
+
+       /* Requested device types for find/search */
+       unsigned int num_req_dev_types;
+       u8 *req_dev_types;
+
+       struct p2p_group **groups;
+       size_t num_groups;
+
+       struct p2p_device *pending_client_disc_go;
+       u8 pending_client_disc_addr[ETH_ALEN];
+       u8 pending_dev_disc_dialog_token;
+       u8 pending_dev_disc_addr[ETH_ALEN];
+       int pending_dev_disc_freq;
+       unsigned int pending_client_disc_freq;
+
+       int ext_listen_only;
+       unsigned int ext_listen_period;
+       unsigned int ext_listen_interval;
+       unsigned int ext_listen_interval_sec;
+       unsigned int ext_listen_interval_usec;
+
+       u8 peer_filter[ETH_ALEN];
+
+       int cross_connect;
+
+       int best_freq_24;
+       int best_freq_5;
+       int best_freq_overall;
+
+       /**
+        * wps_vendor_ext - WPS Vendor Extensions to add
+        */
+       struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
+
+       /*
+        * user_initiated_pd - Whether a PD request is user initiated or not.
+        */
+       u8 user_initiated_pd;
+
+       /*
+        * Keep track of which peer a given PD request was sent to.
+        * Used to raise a timeout alert in case there is no response.
+        */
+       u8 pending_pd_devaddr[ETH_ALEN];
+
+       /*
+        * Retry counter for provision discovery requests when issued
+        * in IDLE state.
+        */
+       int pd_retries;
+};
+
+/**
+ * struct p2p_message - Parsed P2P message (or P2P IE)
+ */
+struct p2p_message {
+       struct wpabuf *p2p_attributes;
+       struct wpabuf *wps_attributes;
+
+       u8 dialog_token;
+
+       const u8 *capability;
+       const u8 *go_intent;
+       const u8 *status;
+       const u8 *listen_channel;
+       const u8 *operating_channel;
+       const u8 *channel_list;
+       u8 channel_list_len;
+       const u8 *config_timeout;
+       const u8 *intended_addr;
+       const u8 *group_bssid;
+       const u8 *invitation_flags;
+
+       const u8 *group_info;
+       size_t group_info_len;
+
+       const u8 *group_id;
+       size_t group_id_len;
+
+       const u8 *device_id;
+
+       const u8 *manageability;
+
+       const u8 *noa;
+       size_t noa_len;
+
+       const u8 *ext_listen_timing;
+
+       const u8 *minor_reason_code;
+
+       /* P2P Device Info */
+       const u8 *p2p_device_info;
+       size_t p2p_device_info_len;
+       const u8 *p2p_device_addr;
+       const u8 *pri_dev_type;
+       u8 num_sec_dev_types;
+       char device_name[33];
+       u16 config_methods;
+
+       /* WPS IE */
+       u16 dev_password_id;
+       u16 wps_config_methods;
+       const u8 *wps_pri_dev_type;
+       const u8 *wps_sec_dev_type_list;
+       size_t wps_sec_dev_type_list_len;
+       const u8 *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
+       size_t wps_vendor_ext_len[P2P_MAX_WPS_VENDOR_EXT];
+       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;
+
+       /* DS Parameter Set IE */
+       const u8 *ds_params;
+
+       /* SSID IE */
+       const u8 *ssid;
+};
+
+
+#define P2P_MAX_GROUP_ENTRIES 50
+
+struct p2p_group_info {
+       unsigned int num_clients;
+       struct p2p_client_info {
+               const u8 *p2p_device_addr;
+               const u8 *p2p_interface_addr;
+               u8 dev_capab;
+               u16 config_methods;
+               const u8 *pri_dev_type;
+               u8 num_sec_dev_types;
+               const u8 *sec_dev_types;
+               const char *dev_name;
+               size_t dev_name_len;
+       } client[P2P_MAX_GROUP_ENTRIES];
+};
+
+
+/* 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);
+void p2p_channels_intersect(const struct p2p_channels *a,
+                           const struct p2p_channels *b,
+                           struct p2p_channels *res);
+int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class,
+                         u8 channel);
+
+/* p2p_parse.c */
+int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg);
+int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg);
+int p2p_parse(const u8 *data, size_t len, struct p2p_message *msg);
+void p2p_parse_free(struct p2p_message *msg);
+int p2p_attr_text(struct wpabuf *data, char *buf, char *end);
+int p2p_group_info_parse(const u8 *gi, size_t gi_len,
+                        struct p2p_group_info *info);
+
+/* p2p_build.c */
+
+struct p2p_noa_desc {
+       u8 count_type;
+       u32 duration;
+       u32 interval;
+       u32 start_time;
+};
+
+/* p2p_group.c */
+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);
+
+
+void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token);
+void p2p_buf_add_public_action_hdr(struct wpabuf *buf, u8 subtype,
+                                  u8 dialog_token);
+u8 * p2p_buf_add_ie_hdr(struct wpabuf *buf);
+void p2p_buf_add_status(struct wpabuf *buf, u8 status);
+void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p,
+                            struct p2p_device *peer);
+void p2p_buf_add_device_id(struct wpabuf *buf, const u8 *dev_addr);
+void p2p_buf_update_ie_hdr(struct wpabuf *buf, u8 *len);
+void p2p_buf_add_capability(struct wpabuf *buf, u8 dev_capab, u8 group_capab);
+void p2p_buf_add_go_intent(struct wpabuf *buf, u8 go_intent);
+void p2p_buf_add_listen_channel(struct wpabuf *buf, const char *country,
+                               u8 reg_class, u8 channel);
+void p2p_buf_add_operating_channel(struct wpabuf *buf, const char *country,
+                                  u8 reg_class, u8 channel);
+void p2p_buf_add_channel_list(struct wpabuf *buf, const char *country,
+                             struct p2p_channels *chan);
+void p2p_buf_add_config_timeout(struct wpabuf *buf, u8 go_timeout,
+                               u8 client_timeout);
+void p2p_buf_add_intended_addr(struct wpabuf *buf, const u8 *interface_addr);
+void p2p_buf_add_group_bssid(struct wpabuf *buf, const u8 *bssid);
+void p2p_buf_add_group_id(struct wpabuf *buf, const u8 *dev_addr,
+                         const u8 *ssid, size_t ssid_len);
+void p2p_buf_add_invitation_flags(struct wpabuf *buf, u8 flags);
+void p2p_buf_add_noa(struct wpabuf *buf, u8 noa_index, u8 opp_ps, u8 ctwindow,
+                    struct p2p_noa_desc *desc1, struct p2p_noa_desc *desc2);
+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,
+                     int all_attr);
+
+/* p2p_sd.c */
+struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
+                                        struct p2p_device *dev);
+void p2p_free_sd_queries(struct p2p_data *p2p);
+void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
+                           const u8 *data, size_t len, int rx_freq);
+void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
+                            const u8 *data, size_t len, int rx_freq);
+void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
+                            const u8 *data, size_t len, int rx_freq);
+void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
+                             const u8 *data, size_t len, int rx_freq);
+int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev);
+
+/* p2p_go_neg.c */
+int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
+                           struct p2p_device *dev,
+                           const u8 *channel_list, size_t channel_list_len);
+void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
+                           const u8 *data, size_t len, int rx_freq);
+void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
+                            const u8 *data, size_t len, int rx_freq);
+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);
+
+/* 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);
+void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
+                               const u8 *data, size_t len);
+int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
+                          int join, int force_freq);
+void p2p_reset_pending_pd(struct p2p_data *p2p);
+
+/* p2p_invitation.c */
+void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
+                               const u8 *data, size_t len, int rx_freq);
+void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
+                                const u8 *data, size_t len);
+int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
+                   const u8 *go_dev_addr);
+void p2p_invitation_req_cb(struct p2p_data *p2p, int success);
+void p2p_invitation_resp_cb(struct p2p_data *p2p, int success);
+
+/* p2p_dev_disc.c */
+void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa,
+                             const u8 *data, size_t len, int rx_freq);
+void p2p_dev_disc_req_cb(struct p2p_data *p2p, int success);
+int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev);
+void p2p_dev_disc_resp_cb(struct p2p_data *p2p, int success);
+void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
+                              const u8 *data, size_t len);
+void p2p_go_disc_req_cb(struct p2p_data *p2p, int success);
+void p2p_process_go_disc_req(struct p2p_data *p2p, const u8 *da, const u8 *sa,
+                            const u8 *data, size_t len, int rx_freq);
+
+/* p2p.c */
+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);
+void p2p_clear_timeout(struct p2p_data *p2p);
+void p2p_continue_find(struct p2p_data *p2p);
+struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p,
+                                               const u8 *addr,
+                                               struct p2p_message *msg);
+void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
+                     struct p2p_device *dev, struct p2p_message *msg);
+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);
+void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer,
+                      int status);
+void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer);
+int p2p_match_dev_type(struct p2p_data *p2p, struct wpabuf *wps);
+int dev_type_list_match(const u8 *dev_type, const u8 *req_dev_type[],
+                       size_t num_req_dev_type);
+struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p);
+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);
+
+#endif /* P2P_I_H */
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
new file mode 100644 (file)
index 0000000..bb2767d
--- /dev/null
@@ -0,0 +1,489 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "common/ieee802_11_defs.h"
+#include "p2p_i.h"
+#include "p2p.h"
+
+
+static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
+                                               struct p2p_device *peer,
+                                               const u8 *go_dev_addr)
+{
+       struct wpabuf *buf;
+       u8 *len;
+       const u8 *dev_addr;
+
+       buf = wpabuf_alloc(1000);
+       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_INVITATION_REQ,
+                                     peer->dialog_token);
+
+       len = p2p_buf_add_ie_hdr(buf);
+       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_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_bssid_set)
+               p2p_buf_add_group_bssid(buf, p2p->inv_bssid);
+       p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels);
+       if (go_dev_addr)
+               dev_addr = go_dev_addr;
+       else if (p2p->inv_role == P2P_INVITE_ROLE_CLIENT)
+               dev_addr = peer->info.p2p_device_addr;
+       else
+               dev_addr = p2p->cfg->dev_addr;
+       p2p_buf_add_group_id(buf, dev_addr, p2p->inv_ssid, p2p->inv_ssid_len);
+       p2p_buf_add_device_info(buf, p2p, peer);
+       p2p_buf_update_ie_hdr(buf, len);
+
+       return buf;
+}
+
+
+static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p,
+                                                struct p2p_device *peer,
+                                                u8 dialog_token, u8 status,
+                                                const u8 *group_bssid,
+                                                u8 reg_class, u8 channel,
+                                                struct p2p_channels *channels)
+{
+       struct wpabuf *buf;
+       u8 *len;
+
+       buf = wpabuf_alloc(1000);
+       if (buf == NULL)
+               return NULL;
+
+       p2p_buf_add_public_action_hdr(buf, P2P_INVITATION_RESP,
+                                     dialog_token);
+
+       len = p2p_buf_add_ie_hdr(buf);
+       p2p_buf_add_status(buf, status);
+       p2p_buf_add_config_timeout(buf, 0, 0); /* FIX */
+       if (reg_class && channel)
+               p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+                                             reg_class, channel);
+       if (group_bssid)
+               p2p_buf_add_group_bssid(buf, group_bssid);
+       if (channels)
+               p2p_buf_add_channel_list(buf, p2p->cfg->country, channels);
+       p2p_buf_update_ie_hdr(buf, len);
+
+       return buf;
+}
+
+
+void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
+                               const u8 *data, size_t len, int rx_freq)
+{
+       struct p2p_device *dev;
+       struct p2p_message msg;
+       struct wpabuf *resp = NULL;
+       u8 status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
+       int freq;
+       int go = 0;
+       u8 group_bssid[ETH_ALEN], *bssid;
+       int op_freq = 0;
+       u8 reg_class = 0, channel = 0;
+       struct p2p_channels intersection, *channels = NULL;
+       int persistent;
+
+       os_memset(group_bssid, 0, sizeof(group_bssid));
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "P2P: Received Invitation Request from " MACSTR " (freq=%d)",
+               MAC2STR(sa), rx_freq);
+
+       if (p2p_parse(data, len, &msg))
+               return;
+
+       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));
+
+               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 "
+                               MACSTR, MAC2STR(sa));
+                       status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
+                       goto fail;
+               }
+
+               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));
+                       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));
+               status = P2P_SC_FAIL_INVALID_PARAMS;
+               goto fail;
+       }
+
+       if (msg.invitation_flags)
+               persistent = *msg.invitation_flags & P2P_INVITATION_FLAGS_TYPE;
+       else {
+               /* Invitation Flags is a mandatory attribute starting from P2P
+                * spec 1.06. As a backwards compatibility mechanism, assume
+                * 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");
+               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");
+               status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+               goto fail;
+       }
+
+       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);
+       }
+
+       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);
+                       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);
+                       status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+                       goto fail;
+               }
+
+               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);
+               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->cfg->country[0], p2p->cfg->country[1],
+                               p2p->cfg->op_reg_class, p2p->cfg->op_channel);
+                       status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+                       goto fail;
+               }
+
+               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;
+                       channels = &intersection;
+               }
+       }
+
+fail:
+       if (go && status == P2P_SC_SUCCESS && !is_zero_ether_addr(group_bssid))
+               bssid = group_bssid;
+       else
+               bssid = NULL;
+       resp = p2p_build_invitation_resp(p2p, dev, msg.dialog_token, status,
+                                        bssid, reg_class, channel, channels);
+
+       if (resp == NULL)
+               goto out;
+
+       if (rx_freq > 0)
+               freq = rx_freq;
+       else
+               freq = p2p_channel_to_freq(p2p->cfg->country,
+                                          p2p->cfg->reg_class,
+                                          p2p->cfg->channel);
+       if (freq < 0) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Unknown regulatory class/channel");
+               goto out;
+       }
+
+       /*
+        * Store copy of invitation data to be used when processing TX status
+        * callback for the Acton frame.
+        */
+       os_memcpy(p2p->inv_sa, sa, ETH_ALEN);
+       if (msg.group_bssid) {
+               os_memcpy(p2p->inv_group_bssid, msg.group_bssid, ETH_ALEN);
+               p2p->inv_group_bssid_ptr = p2p->inv_group_bssid;
+       } else
+               p2p->inv_group_bssid_ptr = NULL;
+       if (msg.group_id_len - ETH_ALEN <= 32) {
+               os_memcpy(p2p->inv_ssid, msg.group_id + ETH_ALEN,
+                         msg.group_id_len - ETH_ALEN);
+               p2p->inv_ssid_len = msg.group_id_len - ETH_ALEN;
+       }
+       os_memcpy(p2p->inv_go_dev_addr, msg.group_id, ETH_ALEN);
+       p2p->inv_status = status;
+       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,
+                           wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Failed to send Action frame");
+       }
+
+out:
+       wpabuf_free(resp);
+       p2p_parse_free(&msg);
+}
+
+
+void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
+                                const u8 *data, size_t len)
+{
+       struct p2p_device *dev;
+       struct p2p_message msg;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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 "
+                       MACSTR, MAC2STR(sa));
+               return;
+       }
+
+       if (dev != p2p->invite_peer) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Ignore unexpected Invitation Response from peer "
+                       MACSTR, MAC2STR(sa));
+               return;
+       }
+
+       if (p2p_parse(data, len, &msg))
+               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_parse_free(&msg);
+               return;
+       }
+
+       if (p2p->cfg->invitation_result)
+               p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status,
+                                           msg.group_bssid);
+
+       p2p_parse_free(&msg);
+
+       p2p_clear_timeout(p2p);
+       p2p_set_state(p2p, P2P_IDLE);
+       p2p->invite_peer = NULL;
+}
+
+
+int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
+                   const u8 *go_dev_addr)
+{
+       struct wpabuf *req;
+       int freq;
+
+       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",
+                       MAC2STR(dev->info.p2p_device_addr));
+               return -1;
+       }
+
+       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");
+       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,
+                           p2p->cfg->dev_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");
+               /* Use P2P find to recover and retry */
+               p2p_set_timeout(p2p, 0, 0);
+       }
+
+       wpabuf_free(req);
+
+       return 0;
+}
+
+
+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);
+
+       if (p2p->invite_peer == NULL) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: No pending Invite");
+               return;
+       }
+
+       /*
+        * Use P2P find, if needed, to find the other device from its listen
+        * channel.
+        */
+       p2p_set_state(p2p, P2P_INVITE);
+       p2p_set_timeout(p2p, 0, 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->cfg->send_action_done(p2p->cfg->cb_ctx);
+
+       if (success && p2p->cfg->invitation_received) {
+               p2p->cfg->invitation_received(p2p->cfg->cb_ctx,
+                                             p2p->inv_sa,
+                                             p2p->inv_group_bssid_ptr,
+                                             p2p->inv_ssid, p2p->inv_ssid_len,
+                                             p2p->inv_go_dev_addr,
+                                             p2p->inv_status,
+                                             p2p->inv_op_freq);
+       }
+}
+
+
+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)
+{
+       struct p2p_device *dev;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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));
+       if (go_dev_addr) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "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",
+                         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,
+                       MAC2STR(peer));
+               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 invite a P2P Device " MACSTR
+                               " that is in a group and is not discoverable",
+                               MAC2STR(peer));
+               }
+               /* TODO: use device discoverability request through GO */
+       }
+
+       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);
+
+       p2p->inv_role = role;
+       p2p->inv_bssid_set = bssid != NULL;
+       if (bssid)
+               os_memcpy(p2p->inv_bssid, bssid, ETH_ALEN);
+       os_memcpy(p2p->inv_ssid, ssid, ssid_len);
+       p2p->inv_ssid_len = ssid_len;
+       p2p->inv_persistent = persistent_group;
+       return p2p_invite_send(p2p, dev, go_dev_addr);
+}
diff --git a/src/p2p/p2p_parse.c b/src/p2p/p2p_parse.c
new file mode 100644 (file)
index 0000000..5c5445a
--- /dev/null
@@ -0,0 +1,718 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "wps/wps_i.h"
+#include "p2p_i.h"
+
+
+static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
+                              struct p2p_message *msg)
+{
+       const u8 *pos;
+       size_t i, nlen;
+       char devtype[WPS_DEV_TYPE_BUFSIZE];
+
+       switch (id) {
+       case P2P_ATTR_CAPABILITY:
+               if (len < 2) {
+                       wpa_printf(MSG_DEBUG, "P2P: Too short Capability "
+                                  "attribute (length %d)", len);
+                       return -1;
+               }
+               msg->capability = data;
+               wpa_printf(MSG_DEBUG, "P2P: * Device Capability %02x "
+                          "Group Capability %02x",
+                          data[0], data[1]);
+               break;
+       case P2P_ATTR_DEVICE_ID:
+               if (len < ETH_ALEN) {
+                       wpa_printf(MSG_DEBUG, "P2P: Too short Device ID "
+                                  "attribute (length %d)", len);
+                       return -1;
+               }
+               msg->device_id = data;
+               wpa_printf(MSG_DEBUG, "P2P: * Device ID " MACSTR,
+                          MAC2STR(msg->device_id));
+               break;
+       case P2P_ATTR_GROUP_OWNER_INTENT:
+               if (len < 1) {
+                       wpa_printf(MSG_DEBUG, "P2P: Too short GO Intent "
+                                  "attribute (length %d)", len);
+                       return -1;
+               }
+               msg->go_intent = data;
+               wpa_printf(MSG_DEBUG, "P2P: * GO Intent: Intent %u "
+                          "Tie breaker %u", data[0] >> 1, data[0] & 0x01);
+               break;
+       case P2P_ATTR_STATUS:
+               if (len < 1) {
+                       wpa_printf(MSG_DEBUG, "P2P: Too short Status "
+                                  "attribute (length %d)", len);
+                       return -1;
+               }
+               msg->status = data;
+               wpa_printf(MSG_DEBUG, "P2P: * Status: %d", data[0]);
+               break;
+       case P2P_ATTR_LISTEN_CHANNEL:
+               if (len == 0) {
+                       wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: Ignore "
+                                  "null channel");
+                       break;
+               }
+               if (len < 5) {
+                       wpa_printf(MSG_DEBUG, "P2P: Too short Listen Channel "
+                                  "attribute (length %d)", len);
+                       return -1;
+               }
+               msg->listen_channel = data;
+               wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: "
+                          "Country %c%c(0x%02x) Regulatory "
+                          "Class %d Channel Number %d", data[0], data[1],
+                          data[2], data[3], data[4]);
+               break;
+       case P2P_ATTR_OPERATING_CHANNEL:
+               if (len == 0) {
+                       wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: "
+                                  "Ignore null channel");
+                       break;
+               }
+               if (len < 5) {
+                       wpa_printf(MSG_DEBUG, "P2P: Too short Operating "
+                                  "Channel attribute (length %d)", len);
+                       return -1;
+               }
+               msg->operating_channel = data;
+               wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: "
+                          "Country %c%c(0x%02x) Regulatory "
+                          "Class %d Channel Number %d", data[0], data[1],
+                          data[2], data[3], data[4]);
+               break;
+       case P2P_ATTR_CHANNEL_LIST:
+               if (len < 3) {
+                       wpa_printf(MSG_DEBUG, "P2P: Too short Channel List "
+                                  "attribute (length %d)", len);
+                       return -1;
+               }
+               msg->channel_list = data;
+               msg->channel_list_len = len;
+               wpa_printf(MSG_DEBUG, "P2P: * Channel List: Country String "
+                          "'%c%c(0x%02x)'", data[0], data[1], data[2]);
+               wpa_hexdump(MSG_MSGDUMP, "P2P: Channel List",
+                           msg->channel_list, msg->channel_list_len);
+               break;
+       case P2P_ATTR_GROUP_INFO:
+               msg->group_info = data;
+               msg->group_info_len = len;
+               wpa_printf(MSG_DEBUG, "P2P: * Group Info");
+               break;
+       case P2P_ATTR_DEVICE_INFO:
+               if (len < ETH_ALEN + 2 + 8 + 1) {
+                       wpa_printf(MSG_DEBUG, "P2P: Too short Device Info "
+                                  "attribute (length %d)", len);
+                       return -1;
+               }
+               msg->p2p_device_info = data;
+               msg->p2p_device_info_len = len;
+               pos = data;
+               msg->p2p_device_addr = pos;
+               pos += ETH_ALEN;
+               msg->config_methods = WPA_GET_BE16(pos);
+               pos += 2;
+               msg->pri_dev_type = pos;
+               pos += 8;
+               msg->num_sec_dev_types = *pos++;
+               if (msg->num_sec_dev_types * 8 > data + len - pos) {
+                       wpa_printf(MSG_DEBUG, "P2P: Device Info underflow");
+                       return -1;
+               }
+               pos += msg->num_sec_dev_types * 8;
+               if (data + len - pos < 4) {
+                       wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name "
+                                  "length %d", (int) (data + len - pos));
+                       return -1;
+               }
+               if (WPA_GET_BE16(pos) != ATTR_DEV_NAME) {
+                       wpa_hexdump(MSG_DEBUG, "P2P: Unexpected Device Name "
+                                   "header", pos, 4);
+                       return -1;
+               }
+               pos += 2;
+               nlen = WPA_GET_BE16(pos);
+               pos += 2;
+               if (data + len - pos < (int) nlen || nlen > 32) {
+                       wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name "
+                                  "length %d (buf len %d)", (int) nlen,
+                                  (int) (data + len - pos));
+                       return -1;
+               }
+               os_memcpy(msg->device_name, pos, nlen);
+               msg->device_name[nlen] = '\0';
+               for (i = 0; i < nlen; i++) {
+                       if (msg->device_name[i] == '\0')
+                               break;
+                       if (msg->device_name[i] > 0 &&
+                           msg->device_name[i] < 32)
+                               msg->device_name[i] = '_';
+               }
+               wpa_printf(MSG_DEBUG, "P2P: * Device Info: addr " MACSTR
+                          " primary device type %s device name '%s' "
+                          "config methods 0x%x",
+                          MAC2STR(msg->p2p_device_addr),
+                          wps_dev_type_bin2str(msg->pri_dev_type, devtype,
+                                               sizeof(devtype)),
+                          msg->device_name, msg->config_methods);
+               break;
+       case P2P_ATTR_CONFIGURATION_TIMEOUT:
+               if (len < 2) {
+                       wpa_printf(MSG_DEBUG, "P2P: Too short Configuration "
+                                  "Timeout attribute (length %d)", len);
+                       return -1;
+               }
+               msg->config_timeout = data;
+               wpa_printf(MSG_DEBUG, "P2P: * Configuration Timeout");
+               break;
+       case P2P_ATTR_INTENDED_INTERFACE_ADDR:
+               if (len < ETH_ALEN) {
+                       wpa_printf(MSG_DEBUG, "P2P: Too short Intended P2P "
+                                  "Interface Address attribute (length %d)",
+                                  len);
+                       return -1;
+               }
+               msg->intended_addr = data;
+               wpa_printf(MSG_DEBUG, "P2P: * Intended P2P Interface Address: "
+                          MACSTR, MAC2STR(msg->intended_addr));
+               break;
+       case P2P_ATTR_GROUP_BSSID:
+               if (len < ETH_ALEN) {
+                       wpa_printf(MSG_DEBUG, "P2P: Too short P2P Group BSSID "
+                                  "attribute (length %d)", len);
+                       return -1;
+               }
+               msg->group_bssid = data;
+               wpa_printf(MSG_DEBUG, "P2P: * P2P Group BSSID: " MACSTR,
+                          MAC2STR(msg->group_bssid));
+               break;
+       case P2P_ATTR_GROUP_ID:
+               if (len < ETH_ALEN || len > ETH_ALEN + 32) {
+                       wpa_printf(MSG_DEBUG, "P2P: Invalid P2P Group ID "
+                                  "attribute length %d", len);
+                       return -1;
+               }
+               msg->group_id = data;
+               msg->group_id_len = len;
+               wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID: Device Address "
+                          MACSTR, MAC2STR(msg->group_id));
+               wpa_hexdump_ascii(MSG_DEBUG, "P2P: * P2P Group ID: SSID",
+                                 msg->group_id + ETH_ALEN,
+                                 msg->group_id_len - ETH_ALEN);
+               break;
+       case P2P_ATTR_INVITATION_FLAGS:
+               if (len < 1) {
+                       wpa_printf(MSG_DEBUG, "P2P: Too short Invitation "
+                                  "Flag attribute (length %d)", len);
+                       return -1;
+               }
+               msg->invitation_flags = data;
+               wpa_printf(MSG_DEBUG, "P2P: * Invitation Flags: bitmap 0x%x",
+                          data[0]);
+               break;
+       case P2P_ATTR_MANAGEABILITY:
+               if (len < 1) {
+                       wpa_printf(MSG_DEBUG, "P2P: Too short Manageability "
+                                  "attribute (length %d)", len);
+                       return -1;
+               }
+               msg->manageability = data;
+               wpa_printf(MSG_DEBUG, "P2P: * Manageability: bitmap 0x%x",
+                          data[0]);
+               break;
+       case P2P_ATTR_NOTICE_OF_ABSENCE:
+               if (len < 2) {
+                       wpa_printf(MSG_DEBUG, "P2P: Too short Notice of "
+                                  "Absence attribute (length %d)", len);
+                       return -1;
+               }
+               msg->noa = data;
+               msg->noa_len = len;
+               wpa_printf(MSG_DEBUG, "P2P: * Notice of Absence");
+               break;
+       case P2P_ATTR_EXT_LISTEN_TIMING:
+               if (len < 4) {
+                       wpa_printf(MSG_DEBUG, "P2P: Too short Extended Listen "
+                                  "Timing attribute (length %d)", len);
+                       return -1;
+               }
+               msg->ext_listen_timing = data;
+               wpa_printf(MSG_DEBUG, "P2P: * Extended Listen Timing "
+                          "(period %u msec  interval %u msec)",
+                          WPA_GET_LE16(msg->ext_listen_timing),
+                          WPA_GET_LE16(msg->ext_listen_timing + 2));
+               break;
+       case P2P_ATTR_MINOR_REASON_CODE:
+               if (len < 1) {
+                       wpa_printf(MSG_DEBUG, "P2P: Too short Minor Reason "
+                                  "Code attribute (length %d)", len);
+                       return -1;
+               }
+               msg->minor_reason_code = data;
+               wpa_printf(MSG_DEBUG, "P2P: * Minor Reason Code: %u",
+                          *msg->minor_reason_code);
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d "
+                          "(length %d)", id, len);
+               break;
+       }
+
+       return 0;
+}
+
+
+/**
+ * p2p_parse_p2p_ie - Parse P2P IE
+ * @buf: Concatenated P2P IE(s) payload
+ * @msg: Buffer for returning parsed attributes
+ * Returns: 0 on success, -1 on failure
+ *
+ * Note: Caller is responsible for clearing the msg data structure before
+ * calling this function.
+ */
+int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg)
+{
+       const u8 *pos = wpabuf_head_u8(buf);
+       const u8 *end = pos + wpabuf_len(buf);
+
+       wpa_printf(MSG_DEBUG, "P2P: Parsing P2P IE");
+
+       while (pos < end) {
+               u16 attr_len;
+               if (pos + 2 >= end) {
+                       wpa_printf(MSG_DEBUG, "P2P: Invalid P2P attribute");
+                       return -1;
+               }
+               attr_len = WPA_GET_LE16(pos + 1);
+               wpa_printf(MSG_DEBUG, "P2P: Attribute %d length %u",
+                          pos[0], attr_len);
+               if (pos + 3 + attr_len > end) {
+                       wpa_printf(MSG_DEBUG, "P2P: Attribute underflow "
+                                  "(len=%u left=%d)",
+                                  attr_len, (int) (end - pos - 3));
+                       wpa_hexdump(MSG_MSGDUMP, "P2P: Data", pos, end - pos);
+                       return -1;
+               }
+               if (p2p_parse_attribute(pos[0], pos + 3, attr_len, msg))
+                       return -1;
+               pos += 3 + attr_len;
+       }
+
+       return 0;
+}
+
+
+static int p2p_parse_wps_ie(const struct wpabuf *buf, struct p2p_message *msg)
+{
+       struct wps_parse_attr attr;
+       int i;
+
+       wpa_printf(MSG_DEBUG, "P2P: Parsing WPS IE");
+       if (wps_parse_msg(buf, &attr))
+               return -1;
+       if (attr.dev_name && attr.dev_name_len < sizeof(msg->device_name) &&
+           !msg->device_name[0])
+               os_memcpy(msg->device_name, attr.dev_name, attr.dev_name_len);
+       if (attr.config_methods) {
+               msg->wps_config_methods =
+                       WPA_GET_BE16(attr.config_methods);
+               wpa_printf(MSG_DEBUG, "P2P: Config Methods (WPS): 0x%x",
+                          msg->wps_config_methods);
+       }
+       if (attr.dev_password_id) {
+               msg->dev_password_id = WPA_GET_BE16(attr.dev_password_id);
+               wpa_printf(MSG_DEBUG, "P2P: Device Password ID: %d",
+                          msg->dev_password_id);
+       }
+       if (attr.primary_dev_type) {
+               char devtype[WPS_DEV_TYPE_BUFSIZE];
+               msg->wps_pri_dev_type = attr.primary_dev_type;
+               wpa_printf(MSG_DEBUG, "P2P: Primary Device Type (WPS): %s",
+                          wps_dev_type_bin2str(msg->wps_pri_dev_type, devtype,
+                                               sizeof(devtype)));
+       }
+       if (attr.sec_dev_type_list) {
+               msg->wps_sec_dev_type_list = attr.sec_dev_type_list;
+               msg->wps_sec_dev_type_list_len = attr.sec_dev_type_list_len;
+       }
+
+       for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+               msg->wps_vendor_ext[i] = attr.vendor_ext[i];
+               msg->wps_vendor_ext_len[i] = attr.vendor_ext_len[i];
+       }
+
+       msg->manufacturer = attr.manufacturer;
+       msg->manufacturer_len = attr.manufacturer_len;
+       msg->model_name = attr.model_name;
+       msg->model_name_len = attr.model_name_len;
+       msg->model_number = attr.model_number;
+       msg->model_number_len = attr.model_number_len;
+       msg->serial_number = attr.serial_number;
+       msg->serial_number_len = attr.serial_number_len;
+
+       return 0;
+}
+
+
+/**
+ * p2p_parse_ies - Parse P2P message IEs (both WPS and P2P IE)
+ * @data: IEs from the message
+ * @len: Length of data buffer in octets
+ * @msg: Buffer for returning parsed attributes
+ * Returns: 0 on success, -1 on failure
+ *
+ * Note: Caller is responsible for clearing the msg data structure before
+ * calling this function.
+ *
+ * Note: Caller must free temporary memory allocations by calling
+ * p2p_parse_free() when the parsed data is not needed anymore.
+ */
+int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg)
+{
+       struct ieee802_11_elems elems;
+
+       ieee802_11_parse_elems(data, len, &elems, 0);
+       if (elems.ds_params && elems.ds_params_len >= 1)
+               msg->ds_params = elems.ds_params;
+       if (elems.ssid)
+               msg->ssid = elems.ssid - 2;
+
+       msg->wps_attributes = ieee802_11_vendor_ie_concat(data, len,
+                                                         WPS_DEV_OUI_WFA);
+       if (msg->wps_attributes &&
+           p2p_parse_wps_ie(msg->wps_attributes, msg)) {
+               p2p_parse_free(msg);
+               return -1;
+       }
+
+       msg->p2p_attributes = ieee802_11_vendor_ie_concat(data, len,
+                                                         P2P_IE_VENDOR_TYPE);
+       if (msg->p2p_attributes &&
+           p2p_parse_p2p_ie(msg->p2p_attributes, msg)) {
+               wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data");
+               if (msg->p2p_attributes)
+                       wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data",
+                                       msg->p2p_attributes);
+               p2p_parse_free(msg);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+/**
+ * p2p_parse - Parse a P2P Action frame contents
+ * @data: Action frame payload after Category and Code fields
+ * @len: Length of data buffer in octets
+ * @msg: Buffer for returning parsed attributes
+ * Returns: 0 on success, -1 on failure
+ *
+ * Note: Caller must free temporary memory allocations by calling
+ * p2p_parse_free() when the parsed data is not needed anymore.
+ */
+int p2p_parse(const u8 *data, size_t len, struct p2p_message *msg)
+{
+       os_memset(msg, 0, sizeof(*msg));
+       wpa_printf(MSG_DEBUG, "P2P: Parsing the received message");
+       if (len < 1) {
+               wpa_printf(MSG_DEBUG, "P2P: No Dialog Token in the message");
+               return -1;
+       }
+       msg->dialog_token = data[0];
+       wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", msg->dialog_token);
+
+       return p2p_parse_ies(data + 1, len - 1, msg);
+}
+
+
+/**
+ * p2p_parse_free - Free temporary data from P2P parsing
+ * @msg: Parsed attributes
+ */
+void p2p_parse_free(struct p2p_message *msg)
+{
+       wpabuf_free(msg->p2p_attributes);
+       msg->p2p_attributes = NULL;
+       wpabuf_free(msg->wps_attributes);
+       msg->wps_attributes = NULL;
+}
+
+
+int p2p_group_info_parse(const u8 *gi, size_t gi_len,
+                        struct p2p_group_info *info)
+{
+       const u8 *g, *gend;
+
+       os_memset(info, 0, sizeof(*info));
+       if (gi == NULL)
+               return 0;
+
+       g = gi;
+       gend = gi + gi_len;
+       while (g < gend) {
+               struct p2p_client_info *cli;
+               const u8 *t, *cend;
+               int count;
+
+               cli = &info->client[info->num_clients];
+               cend = g + 1 + g[0];
+               if (cend > gend)
+                       return -1; /* invalid data */
+               /* g at start of P2P Client Info Descriptor */
+               /* t at Device Capability Bitmap */
+               t = g + 1 + 2 * ETH_ALEN;
+               if (t > cend)
+                       return -1; /* invalid data */
+               cli->p2p_device_addr = g + 1;
+               cli->p2p_interface_addr = g + 1 + ETH_ALEN;
+               cli->dev_capab = t[0];
+
+               if (t + 1 + 2 + 8 + 1 > cend)
+                       return -1; /* invalid data */
+
+               cli->config_methods = WPA_GET_BE16(&t[1]);
+               cli->pri_dev_type = &t[3];
+
+               t += 1 + 2 + 8;
+               /* t at Number of Secondary Device Types */
+               cli->num_sec_dev_types = *t++;
+               if (t + 8 * cli->num_sec_dev_types > cend)
+                       return -1; /* invalid data */
+               cli->sec_dev_types = t;
+               t += 8 * cli->num_sec_dev_types;
+
+               /* t at Device Name in WPS TLV format */
+               if (t + 2 + 2 > cend)
+                       return -1; /* invalid data */
+               if (WPA_GET_BE16(t) != ATTR_DEV_NAME)
+                       return -1; /* invalid Device Name TLV */
+               t += 2;
+               count = WPA_GET_BE16(t);
+               t += 2;
+               if (count > cend - t)
+                       return -1; /* invalid Device Name TLV */
+               if (count >= 32)
+                       count = 32;
+               cli->dev_name = (const char *) t;
+               cli->dev_name_len = count;
+
+               g = cend;
+
+               info->num_clients++;
+               if (info->num_clients == P2P_MAX_GROUP_ENTRIES)
+                       return -1;
+       }
+
+       return 0;
+}
+
+
+static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
+                              char *end)
+{
+       char *pos = buf;
+       int ret;
+       struct p2p_group_info info;
+       unsigned int i;
+
+       if (p2p_group_info_parse(gi, gi_len, &info) < 0)
+               return 0;
+
+       for (i = 0; i < info.num_clients; i++) {
+               struct p2p_client_info *cli;
+               char name[33];
+               char devtype[WPS_DEV_TYPE_BUFSIZE];
+               u8 s;
+               int count;
+
+               cli = &info.client[i];
+               ret = os_snprintf(pos, end - pos, "p2p_group_client: "
+                                 "dev=" MACSTR " iface=" MACSTR,
+                                 MAC2STR(cli->p2p_device_addr),
+                                 MAC2STR(cli->p2p_interface_addr));
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+
+               ret = os_snprintf(pos, end - pos,
+                                 " dev_capab=0x%x config_methods=0x%x "
+                                 "dev_type=%s",
+                                 cli->dev_capab, cli->config_methods,
+                                 wps_dev_type_bin2str(cli->pri_dev_type,
+                                                      devtype,
+                                                      sizeof(devtype)));
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+
+               for (s = 0; s < cli->num_sec_dev_types; s++) {
+                       ret = os_snprintf(pos, end - pos, " dev_type=%s",
+                                         wps_dev_type_bin2str(
+                                                 &cli->sec_dev_types[s * 8],
+                                                 devtype, sizeof(devtype)));
+                       if (ret < 0 || ret >= end - pos)
+                               return pos - buf;
+                       pos += ret;
+               }
+
+               os_memcpy(name, cli->dev_name, cli->dev_name_len);
+               name[cli->dev_name_len] = '\0';
+               count = (int) cli->dev_name_len - 1;
+               while (count >= 0) {
+                       if (name[count] > 0 && name[count] < 32)
+                               name[count] = '_';
+                       count--;
+               }
+
+               ret = os_snprintf(pos, end - pos, " dev_name='%s'\n", name);
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       }
+
+       return pos - buf;
+}
+
+
+/**
+ * p2p_attr_text - Build text format description of P2P IE attributes
+ * @data: P2P IE contents
+ * @buf: Buffer for returning text
+ * @end: Pointer to the end of the buf area
+ * Returns: Number of octets written to the buffer or -1 on faikure
+ *
+ * This function can be used to parse P2P IE contents into text format
+ * field=value lines.
+ */
+int p2p_attr_text(struct wpabuf *data, char *buf, char *end)
+{
+       struct p2p_message msg;
+       char *pos = buf;
+       int ret;
+
+       os_memset(&msg, 0, sizeof(msg));
+       if (p2p_parse_p2p_ie(data, &msg))
+               return -1;
+
+       if (msg.capability) {
+               ret = os_snprintf(pos, end - pos,
+                                 "p2p_dev_capab=0x%x\n"
+                                 "p2p_group_capab=0x%x\n",
+                                 msg.capability[0], msg.capability[1]);
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       }
+
+       if (msg.pri_dev_type) {
+               char devtype[WPS_DEV_TYPE_BUFSIZE];
+               ret = os_snprintf(pos, end - pos,
+                                 "p2p_primary_device_type=%s\n",
+                                 wps_dev_type_bin2str(msg.pri_dev_type,
+                                                      devtype,
+                                                      sizeof(devtype)));
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       }
+
+       ret = os_snprintf(pos, end - pos, "p2p_device_name=%s\n",
+                         msg.device_name);
+       if (ret < 0 || ret >= end - pos)
+               return pos - buf;
+       pos += ret;
+
+       if (msg.p2p_device_addr) {
+               ret = os_snprintf(pos, end - pos, "p2p_device_addr=" MACSTR
+                                 "\n",
+                                 MAC2STR(msg.p2p_device_addr));
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       }
+
+       ret = os_snprintf(pos, end - pos, "p2p_config_methods=0x%x\n",
+                         msg.config_methods);
+       if (ret < 0 || ret >= end - pos)
+               return pos - buf;
+       pos += ret;
+
+       ret = p2p_group_info_text(msg.group_info, msg.group_info_len,
+                                 pos, end);
+       if (ret < 0)
+               return pos - buf;
+       pos += ret;
+
+       return pos - buf;
+}
+
+
+int p2p_get_cross_connect_disallowed(const struct wpabuf *p2p_ie)
+{
+       struct p2p_message msg;
+
+       os_memset(&msg, 0, sizeof(msg));
+       if (p2p_parse_p2p_ie(p2p_ie, &msg))
+               return 0;
+
+       if (!msg.manageability)
+               return 0;
+
+       return !(msg.manageability[0] & P2P_MAN_CROSS_CONNECTION_PERMITTED);
+}
+
+
+u8 p2p_get_group_capab(const struct wpabuf *p2p_ie)
+{
+       struct p2p_message msg;
+
+       os_memset(&msg, 0, sizeof(msg));
+       if (p2p_parse_p2p_ie(p2p_ie, &msg))
+               return 0;
+
+       if (!msg.capability)
+               return 0;
+
+       return msg.capability[1];
+}
+
+
+const u8 * p2p_get_go_dev_addr(const struct wpabuf *p2p_ie)
+{
+       struct p2p_message msg;
+
+       os_memset(&msg, 0, sizeof(msg));
+       if (p2p_parse_p2p_ie(p2p_ie, &msg))
+               return NULL;
+
+       if (msg.p2p_device_addr)
+               return msg.p2p_device_addr;
+       if (msg.device_id)
+               return msg.device_id;
+
+       return NULL;
+}
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
new file mode 100644 (file)
index 0000000..1ee59c5
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "common/ieee802_11_defs.h"
+#include "wps/wps_defs.h"
+#include "p2p_i.h"
+#include "p2p.h"
+
+
+/*
+ * Number of retries to attempt for provision discovery requests during IDLE
+ * state in case the peer is not listening.
+ */
+#define MAX_PROV_DISC_REQ_RETRIES 10
+
+
+static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
+                                           u16 config_methods)
+{
+       u8 *len;
+       wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+       len = wpabuf_put(buf, 1);
+       wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
+
+       /* Config Methods */
+       wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
+       wpabuf_put_be16(buf, 2);
+       wpabuf_put_be16(buf, config_methods);
+
+       p2p_buf_update_ie_hdr(buf, len);
+}
+
+
+static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
+                                              u8 dialog_token,
+                                              u16 config_methods,
+                                              struct p2p_device *go)
+{
+       struct wpabuf *buf;
+       u8 *len;
+
+       buf = wpabuf_alloc(1000);
+       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_device_info(buf, p2p, NULL);
+       if (go) {
+               p2p_buf_add_group_id(buf, go->info.p2p_device_addr,
+                                    go->oper_ssid, go->oper_ssid_len);
+       }
+       p2p_buf_update_ie_hdr(buf, len);
+
+       /* WPS IE with Config Methods attribute */
+       p2p_build_wps_ie_config_methods(buf, config_methods);
+
+       return buf;
+}
+
+
+static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
+                                               u8 dialog_token,
+                                               u16 config_methods)
+{
+       struct wpabuf *buf;
+
+       buf = wpabuf_alloc(100);
+       if (buf == NULL)
+               return NULL;
+
+       p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token);
+
+       /* WPS IE with Config Methods attribute */
+       p2p_build_wps_ie_config_methods(buf, config_methods);
+
+       return buf;
+}
+
+
+void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
+                              const u8 *data, size_t len, int rx_freq)
+{
+       struct p2p_message msg;
+       struct p2p_device *dev;
+       int freq;
+       int reject = 1;
+       struct wpabuf *resp;
+
+       if (p2p_parse(data, len, &msg))
+               return;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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));
+               }
+       }
+
+       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");
+               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
+                       " 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
+                       " requested us to write its PIN using keypad",
+                       MAC2STR(sa));
+               if (dev)
+                       dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
+       }
+
+       reject = 0;
+
+out:
+       resp = p2p_build_prov_disc_resp(p2p, msg.dialog_token,
+                                       reject ? 0 : msg.wps_config_methods);
+       if (resp == NULL) {
+               p2p_parse_free(&msg);
+               return;
+       }
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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,
+                                          p2p->cfg->channel);
+       if (freq < 0) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Unknown regulatory class/channel");
+               wpabuf_free(resp);
+               p2p_parse_free(&msg);
+               return;
+       }
+       p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+       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");
+       }
+
+       wpabuf_free(resp);
+
+       if (!reject && p2p->cfg->prov_disc_req) {
+               const u8 *dev_addr = sa;
+               if (msg.p2p_device_addr)
+                       dev_addr = msg.p2p_device_addr;
+               p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa,
+                                       msg.wps_config_methods,
+                                       dev_addr, msg.pri_dev_type,
+                                       msg.device_name, msg.config_methods,
+                                       msg.capability ? msg.capability[0] : 0,
+                                       msg.capability ? msg.capability[1] :
+                                       0,
+                                       msg.group_id, msg.group_id_len);
+       }
+       p2p_parse_free(&msg);
+}
+
+
+void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
+                               const u8 *data, size_t len)
+{
+       struct p2p_message msg;
+       struct p2p_device *dev;
+       u16 report_config_methods = 0;
+
+       if (p2p_parse(data, len, &msg))
+               return;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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_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)",
+                       msg.dialog_token, dev->dialog_token);
+               p2p_parse_free(&msg);
+               return;
+       }
+
+       /*
+        * If the response is from the peer to whom a user initiated request
+        * was sent earlier, we reset that state info here.
+        */
+       if (p2p->user_initiated_pd &&
+           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 (p2p->cfg->prov_disc_fail)
+                       p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
+                                                P2P_PROV_DISC_REJECTED);
+               p2p_parse_free(&msg);
+               goto out;
+       }
+
+       report_config_methods = dev->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
+                       " 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
+                       " accepted to write our PIN using keypad",
+                       MAC2STR(sa));
+               dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
+       }
+
+       /* Store the provisioning info */
+       dev->wps_prov_info = msg.wps_config_methods;
+
+       p2p_parse_free(&msg);
+
+out:
+       dev->req_config_methods = 0;
+       p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+       if (p2p->cfg->prov_disc_resp)
+               p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa,
+                                        report_config_methods);
+}
+
+
+int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
+                          int join, int force_freq)
+{
+       struct wpabuf *req;
+       int freq;
+
+       if (force_freq > 0)
+               freq = force_freq;
+       else
+               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",
+                       MAC2STR(dev->info.p2p_device_addr));
+               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 use PD with P2P Device " MACSTR
+                               " that is in a group and is not discoverable",
+                               MAC2STR(dev->info.p2p_device_addr));
+                       return -1;
+               }
+               /* 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;
+
+       p2p->pending_action_state = P2P_PENDING_PD;
+       if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
+                           p2p->cfg->dev_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");
+               wpabuf_free(req);
+               return -1;
+       }
+
+       os_memcpy(p2p->pending_pd_devaddr, dev->info.p2p_device_addr, ETH_ALEN);
+
+       wpabuf_free(req);
+       return 0;
+}
+
+
+int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
+                     u16 config_methods, int join, int force_freq)
+{
+       struct p2p_device *dev;
+
+       dev = p2p_get_device(p2p, 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
+                       " 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)",
+               MAC2STR(peer_addr), config_methods);
+       if (config_methods == 0)
+               return -1;
+
+       /* Reset provisioning info */
+       dev->wps_prov_info = 0;
+
+       dev->req_config_methods = config_methods;
+       if (join)
+               dev->flags |= P2P_DEV_PD_FOR_JOIN;
+       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)",
+                       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;
+
+       /* Also set some retries to attempt in case of IDLE state */
+       if (p2p->user_initiated_pd && p2p->state == P2P_IDLE)
+               p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
+
+       return p2p_send_prov_disc_req(p2p, dev, join, force_freq);
+}
+
+
+void p2p_reset_pending_pd(struct p2p_data *p2p)
+{
+       struct p2p_device *dev;
+
+       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))
+                       continue;
+               if (!dev->req_config_methods)
+                       continue;
+               if (dev->flags & P2P_DEV_PD_FOR_JOIN)
+                       continue;
+               /* Reset the config methods of the device */
+               dev->req_config_methods = 0;
+       }
+
+       p2p->user_initiated_pd = 0;
+       os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
+       p2p->pd_retries = 0;
+}
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
new file mode 100644 (file)
index 0000000..f53d4b5
--- /dev/null
@@ -0,0 +1,889 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
+#include "p2p_i.h"
+#include "p2p.h"
+
+
+struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
+                                        struct p2p_device *dev)
+{
+       struct p2p_sd_query *q;
+
+       if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY))
+               return NULL; /* peer does not support SD */
+
+       for (q = p2p->sd_queries; q; q = q->next) {
+               if (q->for_all_peers && !(dev->flags & P2P_DEV_SD_INFO))
+                       return q;
+               if (!q->for_all_peers &&
+                   os_memcmp(q->peer, dev->info.p2p_device_addr, ETH_ALEN) ==
+                   0)
+                       return q;
+       }
+
+       return NULL;
+}
+
+
+static int p2p_unlink_sd_query(struct p2p_data *p2p,
+                              struct p2p_sd_query *query)
+{
+       struct p2p_sd_query *q, *prev;
+       q = p2p->sd_queries;
+       prev = NULL;
+       while (q) {
+               if (q == query) {
+                       if (prev)
+                               prev->next = q->next;
+                       else
+                               p2p->sd_queries = q->next;
+                       if (p2p->sd_query == query)
+                               p2p->sd_query = NULL;
+                       return 1;
+               }
+               prev = q;
+               q = q->next;
+       }
+       return 0;
+}
+
+
+static void p2p_free_sd_query(struct p2p_sd_query *q)
+{
+       if (q == NULL)
+               return;
+       wpabuf_free(q->tlvs);
+       os_free(q);
+}
+
+
+void p2p_free_sd_queries(struct p2p_data *p2p)
+{
+       struct p2p_sd_query *q, *prev;
+       q = p2p->sd_queries;
+       p2p->sd_queries = NULL;
+       while (q) {
+               prev = q;
+               q = q->next;
+               p2p_free_sd_query(prev);
+       }
+}
+
+
+static struct wpabuf * p2p_build_sd_query(u16 update_indic,
+                                         struct wpabuf *tlvs)
+{
+       struct wpabuf *buf;
+       u8 *len_pos;
+
+       buf = gas_anqp_build_initial_req(0, 100 + wpabuf_len(tlvs));
+       if (buf == NULL)
+               return NULL;
+
+       /* ANQP Query Request Frame */
+       len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+       wpabuf_put_be24(buf, OUI_WFA);
+       wpabuf_put_u8(buf, P2P_OUI_TYPE);
+       wpabuf_put_le16(buf, update_indic); /* Service Update Indicator */
+       wpabuf_put_buf(buf, tlvs);
+       gas_anqp_set_element_len(buf, len_pos);
+
+       gas_anqp_set_len(buf);
+
+       return buf;
+}
+
+
+static void p2p_send_gas_comeback_req(struct p2p_data *p2p, const u8 *dst,
+                                     u8 dialog_token, int freq)
+{
+       struct wpabuf *req;
+
+       req = gas_build_comeback_req(dialog_token);
+       if (req == NULL)
+               return;
+
+       p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+       if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr, dst,
+                           wpabuf_head(req), wpabuf_len(req), 200) < 0)
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Failed to send Action frame");
+
+       wpabuf_free(req);
+}
+
+
+static struct wpabuf * p2p_build_sd_response(u8 dialog_token, u16 status_code,
+                                            u16 comeback_delay,
+                                            u16 update_indic,
+                                            const struct wpabuf *tlvs)
+{
+       struct wpabuf *buf;
+       u8 *len_pos;
+
+       buf = gas_anqp_build_initial_resp(dialog_token, status_code,
+                                         comeback_delay,
+                                         100 + (tlvs ? wpabuf_len(tlvs) : 0));
+       if (buf == NULL)
+               return NULL;
+
+       if (tlvs) {
+               /* ANQP Query Response Frame */
+               len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+               wpabuf_put_be24(buf, OUI_WFA);
+               wpabuf_put_u8(buf, P2P_OUI_TYPE);
+                /* Service Update Indicator */
+               wpabuf_put_le16(buf, update_indic);
+               wpabuf_put_buf(buf, tlvs);
+               gas_anqp_set_element_len(buf, len_pos);
+       }
+
+       gas_anqp_set_len(buf);
+
+       return buf;
+}
+
+
+static struct wpabuf * p2p_build_gas_comeback_resp(u8 dialog_token,
+                                                  u16 status_code,
+                                                  u16 update_indic,
+                                                  const u8 *data, size_t len,
+                                                  u8 frag_id, u8 more,
+                                                  u16 total_len)
+{
+       struct wpabuf *buf;
+
+       buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
+                                          more, 0, 100 + len);
+       if (buf == NULL)
+               return NULL;
+
+       if (frag_id == 0) {
+               /* ANQP Query Response Frame */
+               wpabuf_put_le16(buf, ANQP_VENDOR_SPECIFIC); /* Info ID */
+               wpabuf_put_le16(buf, 3 + 1 + 2 + total_len);
+               wpabuf_put_be24(buf, OUI_WFA);
+               wpabuf_put_u8(buf, P2P_OUI_TYPE);
+               /* Service Update Indicator */
+               wpabuf_put_le16(buf, update_indic);
+       }
+
+       wpabuf_put_data(buf, data, len);
+       gas_anqp_set_len(buf);
+
+       return buf;
+}
+
+
+int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev)
+{
+       struct wpabuf *req;
+       int ret = 0;
+       struct p2p_sd_query *query;
+       int freq;
+
+       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",
+                       MAC2STR(dev->info.p2p_device_addr));
+               return -1;
+       }
+
+       query = p2p_pending_sd_req(p2p, dev);
+       if (query == NULL)
+               return -1;
+
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "P2P: Start Service Discovery with " MACSTR,
+               MAC2STR(dev->info.p2p_device_addr));
+
+       req = p2p_build_sd_query(p2p->srv_update_indic, query->tlvs);
+       if (req == NULL)
+               return -1;
+
+       p2p->sd_peer = dev;
+       p2p->sd_query = query;
+       p2p->pending_action_state = P2P_PENDING_SD;
+
+       if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
+                           p2p->cfg->dev_addr, dev->info.p2p_device_addr,
+                           wpabuf_head(req), wpabuf_len(req), 5000) < 0) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Failed to send Action frame");
+               ret = -1;
+       }
+
+       wpabuf_free(req);
+
+       return ret;
+}
+
+
+void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
+                           const u8 *data, size_t len, int rx_freq)
+{
+       const u8 *pos = data;
+       const u8 *end = data + len;
+       const u8 *next;
+       u8 dialog_token;
+       u16 slen;
+       int freq;
+       u16 update_indic;
+
+
+       if (p2p->cfg->sd_request == NULL)
+               return;
+
+       if (rx_freq > 0)
+               freq = rx_freq;
+       else
+               freq = p2p_channel_to_freq(p2p->cfg->country,
+                                          p2p->cfg->reg_class,
+                                          p2p->cfg->channel);
+       if (freq < 0)
+               return;
+
+       if (len < 1 + 2)
+               return;
+
+       dialog_token = *pos++;
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               "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);
+               return;
+       }
+       pos++;
+
+       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");
+               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",
+                       *pos);
+               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 */
+       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));
+               return;
+       }
+       pos += 2;
+
+       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");
+               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));
+               return;
+       }
+       pos += 3;
+
+       if (*pos != P2P_OUI_TYPE) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Unsupported ANQP vendor type %u", *pos);
+               return;
+       }
+       pos++;
+
+       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);
+       pos += 2;
+
+       p2p->cfg->sd_request(p2p->cfg->cb_ctx, freq, sa, dialog_token,
+                            update_indic, pos, end - pos);
+       /* the response will be indicated with a call to p2p_sd_response() */
+}
+
+
+void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
+                    u8 dialog_token, const struct wpabuf *resp_tlvs)
+{
+       struct wpabuf *resp;
+
+       /* 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");
+               if (p2p->sd_resp) {
+                       /*
+                        * TODO: Could consider storing the fragmented response
+                        * separately for each peer to avoid having to drop old
+                        * one if there is more than one pending SD query.
+                        * 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");
+                       wpabuf_free(p2p->sd_resp);
+               }
+               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");
+               resp = p2p_build_sd_response(dialog_token,
+                                            WLAN_STATUS_SUCCESS, 0,
+                                            p2p->srv_update_indic, resp_tlvs);
+       }
+       if (resp == NULL)
+               return;
+
+       p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+       if (p2p_send_action(p2p, freq, dst, 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");
+
+       wpabuf_free(resp);
+}
+
+
+void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
+                            const u8 *data, size_t len, int rx_freq)
+{
+       const u8 *pos = data;
+       const u8 *end = data + len;
+       const u8 *next;
+       u8 dialog_token;
+       u16 status_code;
+       u16 comeback_delay;
+       u16 slen;
+       u16 update_indic;
+
+       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 "
+                       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)",
+               MAC2STR(sa), (int) len);
+
+       if (len < 5 + 2) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Too short GAS Initial Response frame");
+               return;
+       }
+
+       dialog_token = *pos++;
+       /* TODO: check dialog_token match */
+       status_code = WPA_GET_LE16(pos);
+       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",
+               dialog_token, status_code, comeback_delay);
+       if (status_code) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "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);
+               return;
+       }
+       pos++;
+
+       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");
+               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",
+                       *pos);
+               return;
+       }
+
+       pos = next;
+       /* Query Response */
+       if (pos + 2 > end) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "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);
+       if (pos + slen > end) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "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");
+               if (p2p->sd_rx_resp) {
+                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Drop "
+                               "old SD reassembly buffer");
+                       wpabuf_free(p2p->sd_rx_resp);
+                       p2p->sd_rx_resp = NULL;
+               }
+               p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq);
+               return;
+       }
+
+       /* ANQP Query Response */
+       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));
+               return;
+       }
+       pos += 2;
+
+       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");
+               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));
+               return;
+       }
+       pos += 3;
+
+       if (*pos != P2P_OUI_TYPE) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Unsupported ANQP vendor type %u", *pos);
+               return;
+       }
+       pos++;
+
+       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);
+       pos += 2;
+
+       p2p->sd_peer->flags |= P2P_DEV_SD_INFO;
+       p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE;
+       p2p->sd_peer = NULL;
+
+       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->sd_query);
+                       q = p2p->sd_query;
+                       p2p_unlink_sd_query(p2p, p2p->sd_query);
+                       p2p_free_sd_query(q);
+               }
+               p2p->sd_query = NULL;
+       }
+
+       if (p2p->cfg->sd_response)
+               p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa, update_indic,
+                                     pos, end - pos);
+       p2p_continue_find(p2p);
+}
+
+
+void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
+                            const u8 *data, size_t len, int rx_freq)
+{
+       struct wpabuf *resp;
+       u8 dialog_token;
+       size_t frag_len;
+       int more = 0;
+
+       wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Request", data, len);
+       if (len < 1)
+               return;
+       dialog_token = *data;
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "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);
+               return;
+       }
+
+       if (p2p->sd_resp == NULL) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "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));
+               return;
+       }
+
+       frag_len = wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos;
+       if (frag_len > 1400) {
+               frag_len = 1400;
+               more = 1;
+       }
+       resp = p2p_build_gas_comeback_resp(dialog_token, WLAN_STATUS_SUCCESS,
+                                          p2p->srv_update_indic,
+                                          wpabuf_head_u8(p2p->sd_resp) +
+                                          p2p->sd_resp_pos, frag_len,
+                                          p2p->sd_frag_id, more,
+                                          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->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",
+                       (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");
+               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,
+                           wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Failed to send Action frame");
+
+       wpabuf_free(resp);
+}
+
+
+void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
+                             const u8 *data, size_t len, int rx_freq)
+{
+       const u8 *pos = data;
+       const u8 *end = data + len;
+       const u8 *next;
+       u8 dialog_token;
+       u16 status_code;
+       u8 frag_id;
+       u8 more_frags;
+       u16 comeback_delay;
+       u16 slen;
+
+       wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Response", data, len);
+
+       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 "
+                       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)",
+               MAC2STR(sa), (int) len);
+
+       if (len < 6 + 2) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Too short GAS Comeback Response frame");
+               return;
+       }
+
+       dialog_token = *pos++;
+       /* TODO: check dialog_token match */
+       status_code = WPA_GET_LE16(pos);
+       pos += 2;
+       frag_id = *pos & 0x7f;
+       more_frags = (*pos & 0x80) >> 7;
+       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 "
+               "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",
+                       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",
+                       *pos);
+               return;
+       }
+       pos++;
+
+       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");
+               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",
+                       *pos);
+               return;
+       }
+
+       pos = next;
+       /* Query Response */
+       if (pos + 2 > end) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "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);
+       if (pos + slen > end) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Not enough Query "
+                       "Response data");
+               return;
+       }
+       if (slen == 0) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No Query Response "
+                       "data");
+               return;
+       }
+       end = pos + slen;
+
+       if (p2p->sd_rx_resp) {
+                /*
+                 * ANQP header is only included in the first fragment; rest of
+                 * the fragments start with continue TLVs.
+                 */
+               goto skip_nqp_header;
+       }
+
+       /* ANQP Query Response */
+       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));
+               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);
+       if (slen < 3 + 1) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "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));
+               return;
+       }
+       pos += 3;
+
+       if (*pos != P2P_OUI_TYPE) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Unsupported ANQP vendor type %u", *pos);
+               return;
+       }
+       pos++;
+
+       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);
+       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",
+               (unsigned int) wpabuf_len(p2p->sd_rx_resp));
+
+       if (more_frags) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "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");
+                       return;
+               }
+               p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq);
+               return;
+       }
+
+       p2p->sd_peer->flags |= P2P_DEV_SD_INFO;
+       p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE;
+       p2p->sd_peer = NULL;
+
+       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->sd_query);
+                       q = p2p->sd_query;
+                       p2p_unlink_sd_query(p2p, p2p->sd_query);
+                       p2p_free_sd_query(q);
+               }
+               p2p->sd_query = NULL;
+       }
+
+       if (p2p->cfg->sd_response)
+               p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa,
+                                     p2p->sd_rx_update_indic,
+                                     wpabuf_head(p2p->sd_rx_resp),
+                                     wpabuf_len(p2p->sd_rx_resp));
+       wpabuf_free(p2p->sd_rx_resp);
+       p2p->sd_rx_resp = NULL;
+
+       p2p_continue_find(p2p);
+}
+
+
+void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst,
+                     const struct wpabuf *tlvs)
+{
+       struct p2p_sd_query *q;
+
+       q = os_zalloc(sizeof(*q));
+       if (q == NULL)
+               return NULL;
+
+       if (dst)
+               os_memcpy(q->peer, dst, ETH_ALEN);
+       else
+               q->for_all_peers = 1;
+
+       q->tlvs = wpabuf_dup(tlvs);
+       if (q->tlvs == NULL) {
+               p2p_free_sd_query(q);
+               return NULL;
+       }
+
+       q->next = p2p->sd_queries;
+       p2p->sd_queries = q;
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Added SD Query %p", q);
+
+       return q;
+}
+
+
+void p2p_sd_service_update(struct p2p_data *p2p)
+{
+       p2p->srv_update_indic++;
+}
+
+
+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_free_sd_query(req);
+               return 0;
+       }
+       return -1;
+}
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
new file mode 100644 (file)
index 0000000..da4b6ed
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "p2p_i.h"
+
+
+/**
+ * p2p_random - Generate random string for SSID and passphrase
+ * @buf: Buffer for returning the result
+ * @len: Number of octets to write to the buffer
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function generates a random string using the following character set:
+ * 'A'-'Z', 'a'-'z', '0'-'9'.
+ */
+int p2p_random(char *buf, size_t len)
+{
+       u8 val;
+       size_t i;
+       u8 letters = 'Z' - 'A' + 1;
+       u8 numbers = 10;
+
+       if (os_get_random((unsigned char *) buf, len))
+               return -1;
+       /* Character set: 'A'-'Z', 'a'-'z', '0'-'9' */
+       for (i = 0; i < len; i++) {
+               val = buf[i];
+               val %= 2 * letters + numbers;
+               if (val < letters)
+                       buf[i] = 'A' + val;
+               else if (val < 2 * letters)
+                       buf[i] = 'a' + (val - letters);
+               else
+                       buf[i] = '0' + (val - 2 * letters);
+       }
+
+       return 0;
+}
+
+
+static int p2p_channel_to_freq_j4(int reg_class, int channel)
+{
+       /* Table J-4 in P802.11REVmb/D4.0 - Global operating classes */
+       /* TODO: more regulatory classes */
+       switch (reg_class) {
+       case 81:
+               /* channels 1..13 */
+               if (channel < 1 || channel > 13)
+                       return -1;
+               return 2407 + 5 * channel;
+       case 82:
+               /* channel 14 */
+               if (channel != 14)
+                       return -1;
+               return 2414 + 5 * channel;
+       case 83: /* channels 1..9; 40 MHz */
+       case 84: /* channels 5..13; 40 MHz */
+               if (channel < 1 || channel > 13)
+                       return -1;
+               return 2407 + 5 * channel;
+       case 115: /* channels 36,40,44,48; indoor only */
+       case 118: /* channels 52,56,60,64; dfs */
+               if (channel < 36 || channel > 64)
+                       return -1;
+               return 5000 + 5 * channel;
+       case 124: /* channels 149,153,157,161 */
+       case 125: /* channels 149,153,157,161,165,169 */
+               if (channel < 149 || channel > 161)
+                       return -1;
+               return 5000 + 5 * channel;
+       case 116: /* channels 36,44; 40 MHz; indoor only */
+       case 117: /* channels 40,48; 40 MHz; indoor only */
+       case 119: /* channels 52,60; 40 MHz; dfs */
+       case 120: /* channels 56,64; 40 MHz; dfs */
+               if (channel < 36 || channel > 64)
+                       return -1;
+               return 5000 + 5 * channel;
+       case 126: /* channels 149,157; 40 MHz */
+       case 127: /* channels 153,161; 40 MHz */
+               if (channel < 149 || channel > 161)
+                       return -1;
+               return 5000 + 5 * channel;
+       }
+       return -1;
+}
+
+
+/**
+ * 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
+ * @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)
+{
+       /* TODO: more operating classes */
+       if (freq >= 2412 && freq <= 2472) {
+               *reg_class = 81; /* 2.407 GHz, channels 1..13 */
+               *channel = (freq - 2407) / 5;
+               return 0;
+       }
+
+       if (freq == 2484) {
+               *reg_class = 82; /* channel 14 */
+               *channel = 14;
+               return 0;
+       }
+
+       if (freq >= 5180 && freq <= 5240) {
+               *reg_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 */
+               *channel = (freq - 5000) / 5;
+               return 0;
+       }
+
+       return -1;
+}
+
+
+static void p2p_reg_class_intersect(const struct p2p_reg_class *a,
+                                   const struct p2p_reg_class *b,
+                                   struct p2p_reg_class *res)
+{
+       size_t i, j;
+
+       res->reg_class = a->reg_class;
+
+       for (i = 0; i < a->channels; i++) {
+               for (j = 0; j < b->channels; j++) {
+                       if (a->channel[i] != b->channel[j])
+                               continue;
+                       res->channel[res->channels] = a->channel[i];
+                       res->channels++;
+                       if (res->channels == P2P_MAX_REG_CLASS_CHANNELS)
+                               return;
+               }
+       }
+}
+
+
+/**
+ * p2p_channels_intersect - Intersection of supported channel lists
+ * @a: First set of supported channels
+ * @b: Second set of supported channels
+ * @res: Data structure for returning the intersection of support channels
+ *
+ * This function can be used to find a common set of supported channels. Both
+ * input channels sets are assumed to use the same country code. If different
+ * country codes are used, the regulatory class numbers may not be matched
+ * correctly and results are undefined.
+ */
+void p2p_channels_intersect(const struct p2p_channels *a,
+                           const struct p2p_channels *b,
+                           struct p2p_channels *res)
+{
+       size_t i, j;
+
+       os_memset(res, 0, sizeof(*res));
+
+       for (i = 0; i < a->reg_classes; i++) {
+               const struct p2p_reg_class *a_reg = &a->reg_class[i];
+               for (j = 0; j < b->reg_classes; j++) {
+                       const struct p2p_reg_class *b_reg = &b->reg_class[j];
+                       if (a_reg->reg_class != b_reg->reg_class)
+                               continue;
+                       p2p_reg_class_intersect(
+                               a_reg, b_reg,
+                               &res->reg_class[res->reg_classes]);
+                       if (res->reg_class[res->reg_classes].channels) {
+                               res->reg_classes++;
+                               if (res->reg_classes == P2P_MAX_REG_CLASSES)
+                                       return;
+                       }
+               }
+       }
+}
+
+
+/**
+ * p2p_channels_includes - Check whether a channel is included in the list
+ * @channels: List of supported channels
+ * @reg_class: Regulatory class of the channel to search
+ * @channel: Channel number of the channel to search
+ * Returns: 1 if channel was found or 0 if not
+ */
+int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class,
+                         u8 channel)
+{
+       size_t i, j;
+       for (i = 0; i < channels->reg_classes; i++) {
+               const struct p2p_reg_class *reg = &channels->reg_class[i];
+               if (reg->reg_class != reg_class)
+                       continue;
+               for (j = 0; j < reg->channels; j++) {
+                       if (reg->channel[j] == channel)
+                               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)
+               return 0;
+       return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
+                                    op_channel);
+}
diff --git a/src/radius/.gitignore b/src/radius/.gitignore
deleted file mode 100644 (file)
index a89a1f9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-libradius.a
index 70754ef..3ead847 100644 (file)
@@ -218,6 +218,8 @@ static struct radius_attr_type radius_attrs[] =
        { RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
        { RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
          RADIUS_ATTR_HEXDUMP },
+       { RADIUS_ATTR_TUNNEL_PASSWORD, "Tunnel-Password",
+         RADIUS_ATTR_UNDIST },
        { RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
        { RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
        { RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
@@ -1090,8 +1092,7 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
                                  const u8 *secret, size_t secret_len)
 {
        u8 buf[128];
-       int padlen, i;
-       size_t buf_len, pos;
+       size_t padlen, i, buf_len, pos;
        const u8 *addr[2];
        size_t len[2];
        u8 hash[16];
@@ -1103,7 +1104,7 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
        buf_len = data_len;
 
        padlen = data_len % 16;
-       if (padlen) {
+       if (padlen && data_len < sizeof(buf)) {
                padlen = 16 - padlen;
                os_memset(buf + data_len, 0, padlen);
                buf_len += padlen;
@@ -1276,6 +1277,120 @@ int radius_msg_get_vlanid(struct radius_msg *msg)
 }
 
 
+/**
+ * radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password
+ * @msg: Received RADIUS message
+ * @keylen: Length of returned password
+ * @secret: RADIUS shared secret
+ * @secret_len: Length of secret
+ * @sent_msg: Sent RADIUS message
+ * Returns: pointer to 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)
+{
+       u8 *buf = NULL;
+       size_t buflen;
+       const u8 *salt;
+       u8 *str;
+       const u8 *addr[3];
+       size_t len[3];
+       u8 hash[16];
+       u8 *pos;
+       size_t i;
+       struct radius_attr_hdr *attr;
+       const u8 *data;
+       size_t dlen;
+       const u8 *fdata = NULL; /* points to found item */
+       size_t fdlen = -1;
+       char *ret = NULL;
+
+       /* find attribute with lowest tag and check it */
+       for (i = 0; i < msg->attr_used; i++) {
+               attr = radius_get_attr_hdr(msg, i);
+               if (attr == NULL ||
+                   attr->type != RADIUS_ATTR_TUNNEL_PASSWORD) {
+                       continue;
+               }
+               if (attr->length <= 5)
+                       continue;
+               data = (const u8 *) (attr + 1);
+               dlen = attr->length - sizeof(*attr);
+               if (dlen <= 3 || dlen % 16 != 3)
+                       continue;
+               if (fdata != NULL && fdata[0] <= data[0])
+                       continue;
+
+               fdata = data;
+               fdlen = dlen;
+       }
+       if (fdata == NULL)
+               goto out;
+
+       /* alloc writable memory for decryption */
+       buf = os_malloc(fdlen);
+       if (buf == NULL)
+               goto out;
+       os_memcpy(buf, fdata, fdlen);
+       buflen = fdlen;
+
+       /* init pointers */
+       salt = buf + 1;
+       str = buf + 3;
+
+       /* decrypt blocks */
+       pos = buf + buflen - 16; /* last block */
+       while (pos >= str + 16) { /* all but the first block */
+               addr[0] = secret;
+               len[0] = secret_len;
+               addr[1] = pos - 16;
+               len[1] = 16;
+               md5_vector(2, addr, len, hash);
+
+               for (i = 0; i < 16; i++)
+                       pos[i] ^= hash[i];
+
+               pos -= 16;
+       }
+
+       /* decrypt first block */
+       if (str != pos)
+               goto out;
+       addr[0] = secret;
+       len[0] = secret_len;
+       addr[1] = sent_msg->hdr->authenticator;
+       len[1] = 16;
+       addr[2] = salt;
+       len[2] = 2;
+       md5_vector(3, addr, len, hash);
+
+       for (i = 0; i < 16; i++)
+               pos[i] ^= hash[i];
+
+       /* derive plaintext length from first subfield */
+       *keylen = (unsigned char) str[0];
+       if ((u8 *) (str + *keylen) >= (u8 *) (buf + buflen)) {
+               /* decryption error - invalid key length */
+               goto out;
+       }
+       if (*keylen == 0) {
+               /* empty password */
+               goto out;
+       }
+
+       /* copy passphrase into new buffer */
+       ret = os_malloc(*keylen);
+       if (ret)
+               os_memcpy(ret, str + 1, *keylen);
+
+out:
+       /* return new buffer */
+       os_free(buf);
+       return ret;
+}
+
+
 void radius_free_class(struct radius_class_data *c)
 {
        size_t i;
index a3cdac0..e69a047 100644 (file)
@@ -82,6 +82,7 @@ enum { RADIUS_ATTR_USER_NAME = 1,
        RADIUS_ATTR_NAS_PORT_TYPE = 61,
        RADIUS_ATTR_TUNNEL_TYPE = 64,
        RADIUS_ATTR_TUNNEL_MEDIUM_TYPE = 65,
+       RADIUS_ATTR_TUNNEL_PASSWORD = 69,
        RADIUS_ATTR_CONNECT_INFO = 77,
        RADIUS_ATTR_EAP_MESSAGE = 79,
        RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80,
@@ -231,6 +232,9 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
                                  const u8 *secret, size_t secret_len);
 int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len);
 int radius_msg_get_vlanid(struct radius_msg *msg);
+char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
+                                     const u8 *secret, size_t secret_len,
+                                     struct radius_msg *sent_msg);
 
 static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type,
                                            u32 value)
index 171af29..691f77a 100644 (file)
@@ -1489,3 +1489,11 @@ int radius_client_get_mib(struct radius_client_data *radius, char *buf,
 
        return count;
 }
+
+
+void radius_client_reconfig(struct radius_client_data *radius,
+                           struct hostapd_radius_servers *conf)
+{
+       if (radius)
+               radius->conf = conf;
+}
index 644ea23..18e7290 100644 (file)
@@ -259,5 +259,7 @@ void radius_client_flush_auth(struct radius_client_data *radius,
                              const u8 *addr);
 int radius_client_get_mib(struct radius_client_data *radius, char *buf,
                          size_t buflen);
+void radius_client_reconfig(struct radius_client_data *radius,
+                           struct hostapd_radius_servers *conf);
 
 #endif /* RADIUS_CLIENT_H */
index f8780a6..47948bc 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * RADIUS authentication server
- * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ * 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
@@ -222,6 +222,13 @@ struct radius_server_data {
        int tnc;
 
        /**
+        * pwd_group - The D-H group assigned for EAP-pwd
+        *
+        * If EAP-pwd is not used it can be set to zero.
+        */
+       u16 pwd_group;
+
+       /**
         * wps - Wi-Fi Protected Setup context
         *
         * If WPS is used with an external RADIUS server (which is quite
@@ -285,6 +292,10 @@ struct radius_server_data {
         * msg_ctx - Context data for wpa_msg() calls
         */
        void *msg_ctx;
+
+#ifdef CONFIG_RADIUS_TEST
+       char *dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
 };
 
 
@@ -505,6 +516,7 @@ radius_server_get_new_session(struct radius_server_data *data,
        eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind;
        eap_conf.tnc = data->tnc;
        eap_conf.wps = data->wps;
+       eap_conf.pwd_group = data->pwd_group;
        sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
                                       &eap_conf);
        if (sess->eap == NULL) {
@@ -566,6 +578,24 @@ radius_server_encapsulate_eap(struct radius_server_data *data,
 
        if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) {
                int len;
+#ifdef CONFIG_RADIUS_TEST
+               if (data->dump_msk_file) {
+                       FILE *f;
+                       char buf[2 * 64 + 1];
+                       f = fopen(data->dump_msk_file, "a");
+                       if (f) {
+                               len = sess->eap_if->eapKeyDataLen;
+                               if (len > 64)
+                                       len = 64;
+                               len = wpa_snprintf_hex(
+                                       buf, sizeof(buf),
+                                       sess->eap_if->eapKeyData, len);
+                               buf[len] = '\0';
+                               fprintf(f, "%s\n", buf);
+                               fclose(f);
+                       }
+               }
+#endif /* CONFIG_RADIUS_TEST */
                if (sess->eap_if->eapKeyDataLen > 64) {
                        len = 32;
                } else {
@@ -1259,6 +1289,7 @@ radius_server_init(struct radius_server_conf *conf)
        data->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
        data->tnc = conf->tnc;
        data->wps = conf->wps;
+       data->pwd_group = conf->pwd_group;
        if (conf->eap_req_id_text) {
                data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len);
                if (data->eap_req_id_text) {
@@ -1268,6 +1299,11 @@ radius_server_init(struct radius_server_conf *conf)
                }
        }
 
+#ifdef CONFIG_RADIUS_TEST
+       if (conf->dump_msk_file)
+               data->dump_msk_file = os_strdup(conf->dump_msk_file);
+#endif /* CONFIG_RADIUS_TEST */
+
        data->clients = radius_server_read_clients(conf->client_file,
                                                   conf->ipv6);
        if (data->clients == NULL) {
@@ -1319,6 +1355,9 @@ void radius_server_deinit(struct radius_server_data *data)
        os_free(data->eap_fast_a_id);
        os_free(data->eap_fast_a_id_info);
        os_free(data->eap_req_id_text);
+#ifdef CONFIG_RADIUS_TEST
+       os_free(data->dump_msk_file);
+#endif /* CONFIG_RADIUS_TEST */
        os_free(data);
 }
 
index f9c951d..8d6e2ab 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * RADIUS authentication server
- * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ * 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
@@ -143,6 +143,13 @@ struct radius_server_conf {
        int tnc;
 
        /**
+        * pwd_group - EAP-pwd D-H group
+        *
+        * This is used to select which D-H group to use with EAP-pwd.
+        */
+       u16 pwd_group;
+
+       /**
         * wps - Wi-Fi Protected Setup context
         *
         * If WPS is used with an external RADIUS server (which is quite
@@ -194,6 +201,10 @@ struct radius_server_conf {
         * msg_ctx - Context data for wpa_msg() calls
         */
        void *msg_ctx;
+
+#ifdef CONFIG_RADIUS_TEST
+       const char *dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
 };
 
 
index 9d60d4a..2b3332e 100644 (file)
@@ -20,6 +20,7 @@
 #include "eloop.h"
 #include "crypto/sha1.h"
 #include "crypto/sha256.h"
+#include "crypto/random.h"
 #include "common/ieee802_11_defs.h"
 #include "wpa.h"
 #include "wpa_i.h"
@@ -254,7 +255,7 @@ static int wpa_supplicant_process_smk_m2(
                peerkey->use_sha256 = 1;
 #endif /* CONFIG_IEEE80211W */
 
-       if (os_get_random(peerkey->pnonce, WPA_NONCE_LEN)) {
+       if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
                wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                        "WPA: Failed to get random data for PNonce");
                wpa_supplicant_peerkey_free(sm, peerkey);
@@ -370,7 +371,7 @@ static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm,
        wpa_add_kde((u8 *) (msg + 1), RSN_KEY_DATA_PMKID,
                    peerkey->smkid, PMKID_LEN);
 
-       if (os_get_random(peerkey->inonce, WPA_NONCE_LEN)) {
+       if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) {
                wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                        "RSN: Failed to get random data for INonce (STK)");
                os_free(mbuf);
@@ -697,7 +698,7 @@ static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm,
                return;
        }
 
-       if (os_get_random(peerkey->pnonce, WPA_NONCE_LEN)) {
+       if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
                wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                        "RSN: Failed to get random data for PNonce");
                return;
@@ -1097,7 +1098,7 @@ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
                  WPA_REPLAY_COUNTER_LEN);
        inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
 
-       if (os_get_random(peerkey->inonce, WPA_NONCE_LEN)) {
+       if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) {
                wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                        "WPA: Failed to get random data for INonce");
                os_free(rbuf);
@@ -1140,6 +1141,7 @@ void peerkey_deinit(struct wpa_sm *sm)
                peerkey = peerkey->next;
                os_free(prev);
        }
+       sm->peerkey = NULL;
 }
 
 
index cac8c83..3877efb 100644 (file)
@@ -49,6 +49,7 @@ static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
                                   struct rsn_pmksa_cache_entry *entry,
                                   int replace)
 {
+       wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid);
        pmksa->pmksa_count--;
        pmksa->free_cb(entry, pmksa->ctx, replace);
        _pmksa_cache_free_entry(entry);
@@ -185,6 +186,14 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
                        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.
+                        */
+                       pmksa_cache_flush(pmksa, network_ctx);
                        break;
                }
                prev = pos;
@@ -198,7 +207,6 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
                wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
                           "entry (for " MACSTR ") to make room for new one",
                           MAC2STR(pos->aa));
-               wpa_sm_remove_pmkid(pmksa->sm, pos->aa, pos->pmkid);
                pmksa_cache_free_entry(pmksa, pos, 0);
        }
 
@@ -229,6 +237,39 @@ 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
+ */
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx)
+{
+       struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp;
+       int removed = 0;
+
+       entry = pmksa->pmksa;
+       while (entry) {
+               if (entry->network_ctx == network_ctx || network_ctx == NULL) {
+                       wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry "
+                                  "for " MACSTR, MAC2STR(entry->aa));
+                       if (prev)
+                               prev->next = entry->next;
+                       else
+                               pmksa->pmksa = entry->next;
+                       tmp = entry;
+                       entry = entry->next;
+                       pmksa_cache_free_entry(pmksa, tmp, 0);
+                       removed++;
+               } else {
+                       prev = entry;
+                       entry = entry->next;
+               }
+       }
+       if (removed)
+               pmksa_cache_set_expiration(pmksa);
+}
+
+
+/**
  * pmksa_cache_deinit - Free all entries in PMKSA cache
  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
  */
@@ -273,22 +314,6 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
 }
 
 
-/**
- * pmksa_cache_notify_reconfig - Reconfiguration notification for PMKSA cache
- * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
- *
- * Clear references to old data structures when wpa_supplicant is reconfigured.
- */
-void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa)
-{
-       struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
-       while (entry) {
-               entry->network_ctx = NULL;
-               entry = entry->next;
-       }
-}
-
-
 static struct rsn_pmksa_cache_entry *
 pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
                        const struct rsn_pmksa_cache_entry *old_entry,
@@ -327,6 +352,7 @@ pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
 {
        struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
 
+       wpa_printf(MSG_DEBUG, "RSN: Consider " MACSTR " for OKC", MAC2STR(aa));
        if (network_ctx == NULL)
                return NULL;
        while (entry) {
index a1447e5..840827d 100644 (file)
@@ -57,7 +57,6 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
 struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
                const u8 *aa, const u8 *spa, void *network_ctx, int akmp);
-void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa);
 struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
 void pmksa_cache_clear_current(struct wpa_sm *sm);
 int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
@@ -66,6 +65,7 @@ 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);
 
 #else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
 
@@ -106,10 +106,6 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
        return NULL;
 }
 
-static inline void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa)
-{
-}
-
 static inline void pmksa_cache_clear_current(struct wpa_sm *sm)
 {
 }
@@ -122,6 +118,11 @@ static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
        return -1;
 }
 
+static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa,
+                                    void *network_ctx)
+{
+}
+
 #endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
 
 #endif /* PMKSA_CACHE_H */
index 6109f5e..fefca83 100644 (file)
@@ -22,7 +22,6 @@
 #include "preauth.h"
 #include "pmksa_cache.h"
 #include "wpa_i.h"
-#include "common/ieee802_11_defs.h"
 
 
 #if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
new file mode 100644 (file)
index 0000000..27090e3
--- /dev/null
@@ -0,0 +1,2338 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/os.h"
+#include "common/ieee802_11_defs.h"
+#include "crypto/sha256.h"
+#include "crypto/crypto.h"
+#include "crypto/aes_wrap.h"
+#include "rsn_supp/wpa.h"
+#include "rsn_supp/wpa_ie.h"
+#include "rsn_supp/wpa_i.h"
+#include "drivers/driver.h"
+#include "l2_packet/l2_packet.h"
+
+#ifdef CONFIG_TDLS_TESTING
+#define TDLS_TESTING_LONG_FRAME BIT(0)
+#define TDLS_TESTING_ALT_RSN_IE BIT(1)
+#define TDLS_TESTING_DIFF_BSSID BIT(2)
+#define TDLS_TESTING_SHORT_LIFETIME BIT(3)
+#define TDLS_TESTING_WRONG_LIFETIME_RESP BIT(4)
+#define TDLS_TESTING_WRONG_LIFETIME_CONF BIT(5)
+#define TDLS_TESTING_LONG_LIFETIME BIT(6)
+#define TDLS_TESTING_CONCURRENT_INIT BIT(7)
+#define TDLS_TESTING_NO_TPK_EXPIRATION BIT(8)
+#define TDLS_TESTING_DECLINE_RESP BIT(9)
+#define TDLS_TESTING_IGNORE_AP_PROHIBIT BIT(10)
+unsigned int tdls_testing = 0;
+#endif /* CONFIG_TDLS_TESTING */
+
+#define TPK_LIFETIME 43200 /* 12 hours */
+#define TPK_RETRY_COUNT 3
+#define TPK_TIMEOUT 5000 /* in milliseconds */
+
+#define TDLS_MIC_LEN           16
+
+#define TDLS_TIMEOUT_LEN       4
+
+struct wpa_tdls_ftie {
+       u8 ie_type; /* FTIE */
+       u8 ie_len;
+       u8 mic_ctrl[2];
+       u8 mic[TDLS_MIC_LEN];
+       u8 Anonce[WPA_NONCE_LEN]; /* Responder Nonce in TDLS */
+       u8 Snonce[WPA_NONCE_LEN]; /* Initiator Nonce in TDLS */
+       /* followed by optional elements */
+} STRUCT_PACKED;
+
+struct wpa_tdls_timeoutie {
+       u8 ie_type; /* Timeout IE */
+       u8 ie_len;
+       u8 interval_type;
+       u8 value[TDLS_TIMEOUT_LEN];
+} STRUCT_PACKED;
+
+struct wpa_tdls_lnkid {
+       u8 ie_type; /* Link Identifier IE */
+       u8 ie_len;
+       u8 bssid[ETH_ALEN];
+       u8 init_sta[ETH_ALEN];
+       u8 resp_sta[ETH_ALEN];
+} STRUCT_PACKED;
+
+/* TDLS frame headers as per IEEE Std 802.11z-2010 */
+struct wpa_tdls_frame {
+       u8 payloadtype; /* IEEE80211_TDLS_RFTYPE */
+       u8 category; /* Category */
+       u8 action; /* Action (enum tdls_frame_type) */
+} STRUCT_PACKED;
+
+static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs);
+static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx);
+static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer);
+
+
+#define TDLS_MAX_IE_LEN 80
+#define IEEE80211_MAX_SUPP_RATES 32
+
+struct wpa_tdls_peer {
+       struct wpa_tdls_peer *next;
+       int initiator; /* whether this end was initiator for TDLS setup */
+       u8 addr[ETH_ALEN]; /* other end MAC address */
+       u8 inonce[WPA_NONCE_LEN]; /* Initiator Nonce */
+       u8 rnonce[WPA_NONCE_LEN]; /* Responder Nonce */
+       u8 rsnie_i[TDLS_MAX_IE_LEN]; /* Initiator RSN IE */
+       size_t rsnie_i_len;
+       u8 rsnie_p[TDLS_MAX_IE_LEN]; /* Peer RSN IE */
+       size_t rsnie_p_len;
+       u32 lifetime;
+       int cipher; /* Selected cipher (WPA_CIPHER_*) */
+       u8 dtoken;
+
+       struct tpk {
+               u8 kck[16]; /* TPK-KCK */
+               u8 tk[16]; /* TPK-TK; assuming only CCMP will be used */
+       } tpk;
+       int tpk_set;
+       int tpk_success;
+
+       struct tpk_timer {
+               u8 dest[ETH_ALEN];
+               int count;      /* Retry Count */
+               int timer;      /* Timeout in milliseconds */
+               u8 action_code; /* TDLS frame type */
+               u8 dialog_token;
+               u16 status_code;
+               int buf_len;    /* length of TPK message for retransmission */
+               u8 *buf;        /* buffer for TPK message */
+       } sm_tmr;
+
+       u16 capability;
+
+       u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
+       size_t supp_rates_len;
+};
+
+
+static int wpa_tdls_get_privacy(struct wpa_sm *sm)
+{
+       /*
+        * Get info needed from supplicant to check if the current BSS supports
+        * security. Other than OPEN mode, rest are considered secured
+        * WEP/WPA/WPA2 hence TDLS frames are processed for TPK handshake.
+        */
+       return sm->pairwise_cipher != WPA_CIPHER_NONE;
+}
+
+
+static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len)
+{
+       os_memcpy(pos, ie, ie_len);
+       return pos + ie_len;
+}
+
+
+static int wpa_tdls_del_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+{
+       if (wpa_sm_set_key(sm, WPA_ALG_NONE, peer->addr,
+                          0, 0, NULL, 0, NULL, 0) < 0) {
+               wpa_printf(MSG_WARNING, "TDLS: Failed to delete TPK-TK from "
+                          "the driver");
+               return -1;
+       }
+
+       return 0;
+}
+
+
+static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+{
+       u8 key_len;
+       u8 rsc[6];
+       enum wpa_alg alg;
+
+       os_memset(rsc, 0, 6);
+
+       switch (peer->cipher) {
+       case WPA_CIPHER_CCMP:
+               alg = WPA_ALG_CCMP;
+               key_len = 16;
+               break;
+       case WPA_CIPHER_NONE:
+               wpa_printf(MSG_DEBUG, "TDLS: Pairwise Cipher Suite: "
+                          "NONE - do not use pairwise keys");
+               return -1;
+       default:
+               wpa_printf(MSG_WARNING, "TDLS: Unsupported pairwise cipher %d",
+                          sm->pairwise_cipher);
+               return -1;
+       }
+
+       if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1,
+                          rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) {
+               wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the "
+                          "driver");
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wpa_tdls_send_tpk_msg(struct wpa_sm *sm, const u8 *dst,
+                                u8 action_code, u8 dialog_token,
+                                u16 status_code, const u8 *buf, size_t len)
+{
+       return wpa_sm_send_tdls_mgmt(sm, dst, action_code, dialog_token,
+                                    status_code, buf, len);
+}
+
+
+static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
+                            u8 dialog_token, u16 status_code,
+                            const u8 *msg, size_t msg_len)
+{
+       struct wpa_tdls_peer *peer;
+
+       wpa_printf(MSG_DEBUG, "TDLS: TPK send dest=" MACSTR " action_code=%u "
+                  "dialog_token=%u status_code=%u msg_len=%u",
+                  MAC2STR(dest), action_code, dialog_token, status_code,
+                  (unsigned int) msg_len);
+
+       if (wpa_tdls_send_tpk_msg(sm, dest, action_code, dialog_token,
+                                 status_code, msg, msg_len)) {
+               wpa_printf(MSG_INFO, "TDLS: Failed to send message "
+                          "(action_code=%u)", action_code);
+               return -1;
+       }
+
+       if (action_code == WLAN_TDLS_SETUP_CONFIRM ||
+           action_code == WLAN_TDLS_TEARDOWN ||
+           action_code == WLAN_TDLS_DISCOVERY_REQUEST ||
+           action_code == WLAN_TDLS_DISCOVERY_RESPONSE)
+               return 0; /* No retries */
+
+       for (peer = sm->tdls; peer; peer = peer->next) {
+               if (os_memcmp(peer->addr, dest, ETH_ALEN) == 0)
+                       break;
+       }
+
+       if (peer == NULL) {
+               wpa_printf(MSG_INFO, "TDLS: No matching entry found for "
+                          "retry " MACSTR, MAC2STR(dest));
+               return 0;
+       }
+
+       eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
+
+       peer->sm_tmr.count = TPK_RETRY_COUNT;
+       peer->sm_tmr.timer = TPK_TIMEOUT;
+
+       /* Copy message to resend on timeout */
+       os_memcpy(peer->sm_tmr.dest, dest, ETH_ALEN);
+       peer->sm_tmr.action_code = action_code;
+       peer->sm_tmr.dialog_token = dialog_token;
+       peer->sm_tmr.status_code = status_code;
+       peer->sm_tmr.buf_len = msg_len;
+       os_free(peer->sm_tmr.buf);
+       peer->sm_tmr.buf = os_malloc(msg_len);
+       if (peer->sm_tmr.buf == NULL)
+               return -1;
+       os_memcpy(peer->sm_tmr.buf, msg, msg_len);
+
+       wpa_printf(MSG_DEBUG, "TDLS: Retry timeout registered "
+                  "(action_code=%u)", action_code);
+       eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
+                              wpa_tdls_tpk_retry_timeout, sm, peer);
+       return 0;
+}
+
+
+static int wpa_tdls_do_teardown(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
+                               u16 reason_code, int free_peer)
+{
+       int ret;
+
+       if (sm->tdls_external_setup) {
+               ret = wpa_tdls_send_teardown(sm, peer->addr, reason_code);
+
+               /* disable the link after teardown was sent */
+               wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+       } else {
+               ret = wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
+       }
+
+       if (sm->tdls_external_setup || free_peer)
+               wpa_tdls_peer_free(sm, peer);
+
+       return ret;
+}
+
+
+static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+
+       struct wpa_sm *sm = eloop_ctx;
+       struct wpa_tdls_peer *peer = timeout_ctx;
+
+       if (peer->sm_tmr.count) {
+               peer->sm_tmr.count--;
+               peer->sm_tmr.timer = TPK_TIMEOUT;
+
+               wpa_printf(MSG_INFO, "TDLS: Retrying sending of message "
+                          "(action_code=%u)",
+                          peer->sm_tmr.action_code);
+
+               if (peer->sm_tmr.buf == NULL) {
+                       wpa_printf(MSG_INFO, "TDLS: No retry buffer available "
+                                  "for action_code=%u",
+                                  peer->sm_tmr.action_code);
+                       eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm,
+                                            peer);
+                       return;
+               }
+
+               /* resend TPK Handshake Message to Peer */
+               if (wpa_tdls_send_tpk_msg(sm, peer->sm_tmr.dest,
+                                         peer->sm_tmr.action_code,
+                                         peer->sm_tmr.dialog_token,
+                                         peer->sm_tmr.status_code,
+                                         peer->sm_tmr.buf,
+                                         peer->sm_tmr.buf_len)) {
+                       wpa_printf(MSG_INFO, "TDLS: Failed to retry "
+                                  "transmission");
+               }
+
+               eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
+               eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
+                                      wpa_tdls_tpk_retry_timeout, sm, peer);
+       } else {
+               eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
+
+               wpa_printf(MSG_DEBUG, "TDLS: Sending Teardown Request");
+               wpa_tdls_do_teardown(sm, peer,
+                                    WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
+       }
+}
+
+
+static void wpa_tdls_tpk_retry_timeout_cancel(struct wpa_sm *sm,
+                                             struct wpa_tdls_peer *peer,
+                                             u8 action_code)
+{
+       if (action_code == peer->sm_tmr.action_code) {
+               wpa_printf(MSG_DEBUG, "TDLS: Retry timeout cancelled for "
+                          "action_code=%u", action_code);
+
+               /* Cancel Timeout registered */
+               eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
+
+               /* free all resources meant for retry */
+               os_free(peer->sm_tmr.buf);
+               peer->sm_tmr.buf = NULL;
+
+               peer->sm_tmr.count = 0;
+               peer->sm_tmr.timer = 0;
+               peer->sm_tmr.buf_len = 0;
+               peer->sm_tmr.action_code = 0xff;
+       } else {
+               wpa_printf(MSG_INFO, "TDLS: Error in cancelling retry timeout "
+                          "(Unknown action_code=%u)", action_code);
+       }
+}
+
+
+static void wpa_tdls_generate_tpk(struct wpa_tdls_peer *peer,
+                                 const u8 *own_addr, const u8 *bssid)
+{
+       u8 key_input[SHA256_MAC_LEN];
+       const u8 *nonce[2];
+       size_t len[2];
+       u8 data[3 * ETH_ALEN];
+
+       /* IEEE Std 802.11z-2010 8.5.9.1:
+        * TPK-Key-Input = SHA-256(min(SNonce, ANonce) || max(SNonce, ANonce))
+        */
+       len[0] = WPA_NONCE_LEN;
+       len[1] = WPA_NONCE_LEN;
+       if (os_memcmp(peer->inonce, peer->rnonce, WPA_NONCE_LEN) < 0) {
+               nonce[0] = peer->inonce;
+               nonce[1] = peer->rnonce;
+       } else {
+               nonce[0] = peer->rnonce;
+               nonce[1] = peer->inonce;
+       }
+       wpa_hexdump(MSG_DEBUG, "TDLS: min(Nonce)", nonce[0], WPA_NONCE_LEN);
+       wpa_hexdump(MSG_DEBUG, "TDLS: max(Nonce)", nonce[1], WPA_NONCE_LEN);
+       sha256_vector(2, nonce, len, key_input);
+       wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-Key-Input",
+                       key_input, SHA256_MAC_LEN);
+
+       /*
+        * TPK-Key-Data = KDF-N_KEY(TPK-Key-Input, "TDLS PMK",
+        *      min(MAC_I, MAC_R) || max(MAC_I, MAC_R) || BSSID || N_KEY)
+        * TODO: is N_KEY really included in KDF Context and if so, in which
+        * presentation format (little endian 16-bit?) is it used? It gets
+        * added by the KDF anyway..
+        */
+
+       if (os_memcmp(own_addr, peer->addr, ETH_ALEN) < 0) {
+               os_memcpy(data, own_addr, ETH_ALEN);
+               os_memcpy(data + ETH_ALEN, peer->addr, ETH_ALEN);
+       } else {
+               os_memcpy(data, peer->addr, ETH_ALEN);
+               os_memcpy(data + ETH_ALEN, own_addr, ETH_ALEN);
+       }
+       os_memcpy(data + 2 * ETH_ALEN, bssid, ETH_ALEN);
+       wpa_hexdump(MSG_DEBUG, "TDLS: KDF Context", data, sizeof(data));
+
+       sha256_prf(key_input, SHA256_MAC_LEN, "TDLS PMK", data, sizeof(data),
+                  (u8 *) &peer->tpk, sizeof(peer->tpk));
+       wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-KCK",
+                       peer->tpk.kck, sizeof(peer->tpk.kck));
+       wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-TK",
+                       peer->tpk.tk, sizeof(peer->tpk.tk));
+       peer->tpk_set = 1;
+}
+
+
+/**
+ * wpa_tdls_ftie_mic - Calculate TDLS FTIE MIC
+ * @kck: TPK-KCK
+ * @lnkid: Pointer to the beginning of Link Identifier IE
+ * @rsnie: Pointer to the beginning of RSN IE used for handshake
+ * @timeoutie: Pointer to the beginning of Timeout IE used for handshake
+ * @ftie: Pointer to the beginning of FT IE
+ * @mic: Pointer for writing MIC
+ *
+ * Calculate MIC for TDLS frame.
+ */
+static int wpa_tdls_ftie_mic(const u8 *kck, u8 trans_seq, const u8 *lnkid,
+                            const u8 *rsnie, const u8 *timeoutie,
+                            const u8 *ftie, u8 *mic)
+{
+       u8 *buf, *pos;
+       struct wpa_tdls_ftie *_ftie;
+       const struct wpa_tdls_lnkid *_lnkid;
+       int ret;
+       int len = 2 * ETH_ALEN + 1 + 2 + lnkid[1] + 2 + rsnie[1] +
+               2 + timeoutie[1] + 2 + ftie[1];
+       buf = os_zalloc(len);
+       if (!buf) {
+               wpa_printf(MSG_WARNING, "TDLS: No memory for MIC calculation");
+               return -1;
+       }
+
+       pos = buf;
+       _lnkid = (const struct wpa_tdls_lnkid *) lnkid;
+       /* 1) TDLS initiator STA MAC address */
+       os_memcpy(pos, _lnkid->init_sta, ETH_ALEN);
+       pos += ETH_ALEN;
+       /* 2) TDLS responder STA MAC address */
+       os_memcpy(pos, _lnkid->resp_sta, ETH_ALEN);
+       pos += ETH_ALEN;
+       /* 3) Transaction Sequence number */
+       *pos++ = trans_seq;
+       /* 4) Link Identifier IE */
+       os_memcpy(pos, lnkid, 2 + lnkid[1]);
+       pos += 2 + lnkid[1];
+       /* 5) RSN IE */
+       os_memcpy(pos, rsnie, 2 + rsnie[1]);
+       pos += 2 + rsnie[1];
+       /* 6) Timeout Interval IE */
+       os_memcpy(pos, timeoutie, 2 + timeoutie[1]);
+       pos += 2 + timeoutie[1];
+       /* 7) FTIE, with the MIC field of the FTIE set to 0 */
+       os_memcpy(pos, ftie, 2 + ftie[1]);
+       _ftie = (struct wpa_tdls_ftie *) pos;
+       os_memset(_ftie->mic, 0, TDLS_MIC_LEN);
+       pos += 2 + ftie[1];
+
+       wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf);
+       wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", kck, 16);
+       ret = omac1_aes_128(kck, buf, pos - buf, mic);
+       os_free(buf);
+       wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16);
+       return ret;
+}
+
+
+/**
+ * wpa_tdls_key_mic_teardown - Calculate TDLS FTIE MIC for Teardown frame
+ * @kck: TPK-KCK
+ * @trans_seq: Transaction Sequence Number (4 - Teardown)
+ * @rcode: Reason code for Teardown
+ * @dtoken: Dialog Token used for that particular link
+ * @lnkid: Pointer to the beginning of Link Identifier IE
+ * @ftie: Pointer to the beginning of FT IE
+ * @mic: Pointer for writing MIC
+ *
+ * Calculate MIC for TDLS frame.
+ */
+static int wpa_tdls_key_mic_teardown(const u8 *kck, u8 trans_seq, u16 rcode,
+                                    u8 dtoken, const u8 *lnkid,
+                                    const u8 *ftie, u8 *mic)
+{
+       u8 *buf, *pos;
+       struct wpa_tdls_ftie *_ftie;
+       int ret;
+       int len;
+
+       if (lnkid == NULL)
+               return -1;
+
+       len = 2 + lnkid[1] + sizeof(rcode) + sizeof(dtoken) +
+               sizeof(trans_seq) + 2 + ftie[1];
+
+       buf = os_zalloc(len);
+       if (!buf) {
+               wpa_printf(MSG_WARNING, "TDLS: No memory for MIC calculation");
+               return -1;
+       }
+
+       pos = buf;
+       /* 1) Link Identifier IE */
+       os_memcpy(pos, lnkid, 2 + lnkid[1]);
+       pos += 2 + lnkid[1];
+       /* 2) Reason Code */
+       WPA_PUT_LE16(pos, rcode);
+       pos += sizeof(rcode);
+       /* 3) Dialog token */
+       *pos++ = dtoken;
+       /* 4) Transaction Sequence number */
+       *pos++ = trans_seq;
+       /* 7) FTIE, with the MIC field of the FTIE set to 0 */
+       os_memcpy(pos, ftie, 2 + ftie[1]);
+       _ftie = (struct wpa_tdls_ftie *) pos;
+       os_memset(_ftie->mic, 0, TDLS_MIC_LEN);
+       pos += 2 + ftie[1];
+
+       wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf);
+       wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", kck, 16);
+       ret = omac1_aes_128(kck, buf, pos - buf, mic);
+       os_free(buf);
+       wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16);
+       return ret;
+}
+
+
+static int wpa_supplicant_verify_tdls_mic(u8 trans_seq,
+                                         struct wpa_tdls_peer *peer,
+                                         const u8 *lnkid, const u8 *timeoutie,
+                                         const struct wpa_tdls_ftie *ftie)
+{
+       u8 mic[16];
+
+       if (peer->tpk_set) {
+               wpa_tdls_ftie_mic(peer->tpk.kck, trans_seq, lnkid,
+                                 peer->rsnie_p, timeoutie, (u8 *) ftie,
+                                 mic);
+               if (os_memcmp(mic, ftie->mic, 16) != 0) {
+                       wpa_printf(MSG_INFO, "TDLS: Invalid MIC in FTIE - "
+                                  "dropping packet");
+                       wpa_hexdump(MSG_DEBUG, "TDLS: Received MIC",
+                                   ftie->mic, 16);
+                       wpa_hexdump(MSG_DEBUG, "TDLS: Calculated MIC",
+                                   mic, 16);
+                       return -1;
+               }
+       } else {
+               wpa_printf(MSG_WARNING, "TDLS: Could not verify TDLS MIC, "
+                          "TPK not set - dropping packet");
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wpa_supplicant_verify_tdls_mic_teardown(
+       u8 trans_seq, u16 rcode, u8 dtoken, struct wpa_tdls_peer *peer,
+       const u8 *lnkid, const struct wpa_tdls_ftie *ftie)
+{
+       u8 mic[16];
+
+       if (peer->tpk_set) {
+               wpa_tdls_key_mic_teardown(peer->tpk.kck, trans_seq, rcode,
+                                         dtoken, lnkid, (u8 *) ftie, mic);
+               if (os_memcmp(mic, ftie->mic, 16) != 0) {
+                       wpa_printf(MSG_INFO, "TDLS: Invalid MIC in Teardown - "
+                                  "dropping packet");
+                       return -1;
+               }
+       } else {
+               wpa_printf(MSG_INFO, "TDLS: Could not verify TDLS Teardown "
+                          "MIC, TPK not set - dropping packet");
+               return -1;
+       }
+       return 0;
+}
+
+
+static void wpa_tdls_tpk_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_sm *sm = eloop_ctx;
+       struct wpa_tdls_peer *peer = timeout_ctx;
+
+       /*
+        * On TPK lifetime expiration, we have an option of either tearing down
+        * the direct link or trying to re-initiate it. The selection of what
+        * to do is not strictly speaking controlled by our role in the expired
+        * link, but for now, use that to select whether to renew or tear down
+        * the link.
+        */
+
+       if (peer->initiator) {
+               wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR
+                          " - try to renew", MAC2STR(peer->addr));
+               wpa_tdls_start(sm, peer->addr);
+       } else {
+               wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR
+                          " - tear down", MAC2STR(peer->addr));
+               wpa_tdls_do_teardown(sm, peer,
+                                    WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
+       }
+}
+
+
+static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+{
+       wpa_printf(MSG_DEBUG, "TDLS: Clear state for peer " MACSTR,
+                  MAC2STR(peer->addr));
+       eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
+       eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
+       peer->initiator = 0;
+       os_free(peer->sm_tmr.buf);
+       peer->sm_tmr.buf = NULL;
+       peer->rsnie_i_len = peer->rsnie_p_len = 0;
+       peer->cipher = 0;
+       peer->tpk_set = peer->tpk_success = 0;
+       os_memset(&peer->tpk, 0, sizeof(peer->tpk));
+       os_memset(peer->inonce, 0, WPA_NONCE_LEN);
+       os_memset(peer->rnonce, 0, WPA_NONCE_LEN);
+}
+
+
+static void wpa_tdls_linkid(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
+                           struct wpa_tdls_lnkid *lnkid)
+{
+       lnkid->ie_type = WLAN_EID_LINK_ID;
+       lnkid->ie_len = 3 * ETH_ALEN;
+       os_memcpy(lnkid->bssid, sm->bssid, ETH_ALEN);
+       if (peer->initiator) {
+               os_memcpy(lnkid->init_sta, sm->own_addr, ETH_ALEN);
+               os_memcpy(lnkid->resp_sta, peer->addr, ETH_ALEN);
+       } else {
+               os_memcpy(lnkid->init_sta, peer->addr, ETH_ALEN);
+               os_memcpy(lnkid->resp_sta, sm->own_addr, ETH_ALEN);
+       }
+}
+
+
+int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code)
+{
+       struct wpa_tdls_peer *peer;
+       struct wpa_tdls_ftie *ftie;
+       struct wpa_tdls_lnkid lnkid;
+       u8 dialog_token;
+       u8 *rbuf, *pos;
+       int ielen;
+
+       if (sm->tdls_disabled || !sm->tdls_supported)
+               return -1;
+
+       /* Find the node and free from the list */
+       for (peer = sm->tdls; peer; peer = peer->next) {
+               if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+                       break;
+       }
+
+       if (peer == NULL) {
+               wpa_printf(MSG_INFO, "TDLS: No matching entry found for "
+                          "Teardown " MACSTR, MAC2STR(addr));
+               return 0;
+       }
+
+       dialog_token = peer->dtoken;
+
+       wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown for " MACSTR,
+                  MAC2STR(addr));
+
+       ielen = 0;
+       if (wpa_tdls_get_privacy(sm) && peer->tpk_set && peer->tpk_success) {
+               /* To add FTIE for Teardown request and compute MIC */
+               ielen += sizeof(*ftie);
+#ifdef CONFIG_TDLS_TESTING
+               if (tdls_testing & TDLS_TESTING_LONG_FRAME)
+                       ielen += 170;
+#endif /* CONFIG_TDLS_TESTING */
+       }
+
+       rbuf = os_zalloc(ielen + 1);
+       if (rbuf == NULL)
+               return -1;
+       pos = rbuf;
+
+       if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success)
+               goto skip_ies;
+
+       ftie = (struct wpa_tdls_ftie *) pos;
+       ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION;
+       /* Using the recent nonce which should be for CONFIRM frame */
+       os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN);
+       os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN);
+       ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2;
+       pos = (u8 *) (ftie + 1);
+#ifdef CONFIG_TDLS_TESTING
+       if (tdls_testing & TDLS_TESTING_LONG_FRAME) {
+               wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to "
+                          "FTIE");
+               ftie->ie_len += 170;
+               *pos++ = 255; /* FTIE subelem */
+               *pos++ = 168; /* FTIE subelem length */
+               pos += 168;
+       }
+#endif /* CONFIG_TDLS_TESTING */
+       wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TDLS Teardown handshake",
+                   (u8 *) ftie, pos - (u8 *) ftie);
+
+       /* compute MIC before sending */
+       wpa_tdls_linkid(sm, peer, &lnkid);
+       wpa_tdls_key_mic_teardown(peer->tpk.kck, 4, reason_code,
+                                 dialog_token, (u8 *) &lnkid, (u8 *) ftie,
+                                 ftie->mic);
+
+skip_ies:
+       /* TODO: register for a Timeout handler, if Teardown is not received at
+        * the other end, then try again another time */
+
+       /* request driver to send Teardown using this FTIE */
+       wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0,
+                         WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, rbuf,
+                         pos - rbuf);
+       os_free(rbuf);
+
+       /* clear the Peerkey statemachine */
+       wpa_tdls_peer_free(sm, peer);
+
+       return 0;
+}
+
+
+int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code)
+{
+       struct wpa_tdls_peer *peer;
+
+       if (sm->tdls_disabled || !sm->tdls_supported)
+               return -1;
+
+       for (peer = sm->tdls; peer; peer = peer->next) {
+               if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+                       break;
+       }
+
+       if (peer == NULL) {
+               wpa_printf(MSG_DEBUG, "TDLS: Could not find peer " MACSTR
+                  " for link Teardown", MAC2STR(addr));
+               return -1;
+       }
+
+       if (!peer->tpk_success) {
+               wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR
+                  " not connected - cannot Teardown link", MAC2STR(addr));
+               return -1;
+       }
+
+       return wpa_tdls_do_teardown(sm, peer, reason_code, 0);
+}
+
+
+void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr)
+{
+       struct wpa_tdls_peer *peer;
+
+       for (peer = sm->tdls; peer; peer = peer->next) {
+               if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+                       break;
+       }
+
+       if (peer) {
+               wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr);
+               wpa_tdls_peer_free(sm, peer);
+       }
+}
+
+
+static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr,
+                                 const u8 *buf, size_t len)
+{
+       struct wpa_tdls_peer *peer = NULL;
+       struct wpa_tdls_ftie *ftie;
+       struct wpa_tdls_lnkid *lnkid;
+       struct wpa_eapol_ie_parse kde;
+       u16 reason_code;
+       const u8 *pos;
+       int ielen;
+
+       /* Find the node and free from the list */
+       for (peer = sm->tdls; peer; peer = peer->next) {
+               if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0)
+                       break;
+       }
+
+       if (peer == NULL) {
+               wpa_printf(MSG_INFO, "TDLS: No matching entry found for "
+                          "Teardown " MACSTR, MAC2STR(src_addr));
+               return 0;
+       }
+
+       pos = buf;
+       pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
+
+       reason_code = WPA_GET_LE16(pos);
+       pos += 2;
+
+       wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown Request from " MACSTR
+                  " (reason code %u)", MAC2STR(src_addr), reason_code);
+
+       ielen = len - (pos - buf); /* start of IE in buf */
+       if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) {
+               wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in Teardown");
+               return -1;
+       }
+
+       if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
+               wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TDLS "
+                          "Teardown");
+               return -1;
+       }
+       lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
+
+       if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success)
+               goto skip_ftie;
+
+       if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) {
+               wpa_printf(MSG_INFO, "TDLS: No FTIE in TDLS Teardown");
+               return -1;
+       }
+
+       ftie = (struct wpa_tdls_ftie *) kde.ftie;
+
+       /* Process MIC check to see if TDLS Teardown is right */
+       if (wpa_supplicant_verify_tdls_mic_teardown(4, reason_code,
+                                                   peer->dtoken, peer,
+                                                   (u8 *) lnkid, ftie) < 0) {
+               wpa_printf(MSG_DEBUG, "TDLS: MIC failure for TDLS "
+                          "Teardown Request from " MACSTR, MAC2STR(src_addr));
+               return -1;
+       }
+
+skip_ftie:
+       /*
+        * Request the driver to disable the direct link and clear associated
+        * keys.
+        */
+       wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+
+       /* clear the Peerkey statemachine */
+       wpa_tdls_peer_free(sm, peer);
+
+       return 0;
+}
+
+
+/**
+ * wpa_tdls_send_error - To send suitable TDLS status response with
+ *     appropriate status code mentioning reason for error/failure.
+ * @dst        - MAC addr of Peer station
+ * @tdls_action - TDLS frame type for which error code is sent
+ * @status     - status code mentioning reason
+ */
+
+static int wpa_tdls_send_error(struct wpa_sm *sm, const u8 *dst,
+                              u8 tdls_action, u8 dialog_token, u16 status)
+{
+       wpa_printf(MSG_DEBUG, "TDLS: Sending error to " MACSTR
+                  " (action=%u status=%u)",
+                  MAC2STR(dst), tdls_action, status);
+       return wpa_tdls_tpk_send(sm, dst, tdls_action, dialog_token, status,
+                                NULL, 0);
+}
+
+
+static struct wpa_tdls_peer *
+wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr)
+{
+       struct wpa_tdls_peer *peer;
+
+       wpa_printf(MSG_INFO, "TDLS: Creating peer entry for " MACSTR,
+                  MAC2STR(addr));
+
+       peer = os_zalloc(sizeof(*peer));
+       if (peer == NULL)
+               return NULL;
+
+       os_memcpy(peer->addr, addr, ETH_ALEN);
+       peer->next = sm->tdls;
+       sm->tdls = peer;
+
+       return peer;
+}
+
+
+static int wpa_tdls_send_tpk_m1(struct wpa_sm *sm,
+                               struct wpa_tdls_peer *peer)
+{
+       size_t buf_len;
+       struct wpa_tdls_timeoutie timeoutie;
+       u16 rsn_capab;
+       struct wpa_tdls_ftie *ftie;
+       u8 *rbuf, *pos, *count_pos;
+       u16 count;
+       struct rsn_ie_hdr *hdr;
+
+       if (!wpa_tdls_get_privacy(sm)) {
+               wpa_printf(MSG_DEBUG, "TDLS: No security used on the link");
+               peer->rsnie_i_len = 0;
+               goto skip_rsnie;
+       }
+
+       /*
+        * TPK Handshake Message 1:
+        * FTIE: ANonce=0, SNonce=initiator nonce MIC=0, DataKDs=(RSNIE_I,
+        * Timeout Interval IE))
+        */
+
+       /* Filling RSN IE */
+       hdr = (struct rsn_ie_hdr *) peer->rsnie_i;
+       hdr->elem_id = WLAN_EID_RSN;
+       WPA_PUT_LE16(hdr->version, RSN_VERSION);
+
+       pos = (u8 *) (hdr + 1);
+       RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+       pos += RSN_SELECTOR_LEN;
+       count_pos = pos;
+       pos += 2;
+
+       count = 0;
+
+       /*
+        * AES-CCMP is the default Encryption preferred for TDLS, so
+        * RSN IE is filled only with CCMP CIPHER
+        * Note: TKIP is not used to encrypt TDLS link.
+        *
+        * Regardless of the cipher used on the AP connection, select CCMP
+        * here.
+        */
+       RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+       pos += RSN_SELECTOR_LEN;
+       count++;
+
+       WPA_PUT_LE16(count_pos, count);
+
+       WPA_PUT_LE16(pos, 1);
+       pos += 2;
+       RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE);
+       pos += RSN_SELECTOR_LEN;
+
+       rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED;
+       rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2;
+#ifdef CONFIG_TDLS_TESTING
+       if (tdls_testing & TDLS_TESTING_ALT_RSN_IE) {
+               wpa_printf(MSG_DEBUG, "TDLS: Use alternative RSN IE for "
+                          "testing");
+               rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED;
+       }
+#endif /* CONFIG_TDLS_TESTING */
+       WPA_PUT_LE16(pos, rsn_capab);
+       pos += 2;
+#ifdef CONFIG_TDLS_TESTING
+       if (tdls_testing & TDLS_TESTING_ALT_RSN_IE) {
+               /* Number of PMKIDs */
+               *pos++ = 0x00;
+               *pos++ = 0x00;
+       }
+#endif /* CONFIG_TDLS_TESTING */
+
+       hdr->len = (pos - peer->rsnie_i) - 2;
+       peer->rsnie_i_len = pos - peer->rsnie_i;
+       wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for TPK handshake",
+                   peer->rsnie_i, peer->rsnie_i_len);
+
+skip_rsnie:
+       buf_len = 0;
+       if (wpa_tdls_get_privacy(sm))
+               buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) +
+                       sizeof(struct wpa_tdls_timeoutie);
+#ifdef CONFIG_TDLS_TESTING
+       if (wpa_tdls_get_privacy(sm) &&
+           (tdls_testing & TDLS_TESTING_LONG_FRAME))
+               buf_len += 170;
+       if (tdls_testing & TDLS_TESTING_DIFF_BSSID)
+               buf_len += sizeof(struct wpa_tdls_lnkid);
+#endif /* CONFIG_TDLS_TESTING */
+       rbuf = os_zalloc(buf_len + 1);
+       if (rbuf == NULL) {
+               wpa_tdls_peer_free(sm, peer);
+               return -1;
+       }
+       pos = rbuf;
+
+       if (!wpa_tdls_get_privacy(sm))
+               goto skip_ies;
+
+       /* Initiator RSN IE */
+       pos = wpa_add_ie(pos, peer->rsnie_i, peer->rsnie_i_len);
+
+       ftie = (struct wpa_tdls_ftie *) pos;
+       ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION;
+       ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2;
+
+       if (os_get_random(peer->inonce, WPA_NONCE_LEN)) {
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "TDLS: Failed to get random data for initiator Nonce");
+               os_free(rbuf);
+               wpa_tdls_peer_free(sm, peer);
+               return -1;
+       }
+       wpa_hexdump(MSG_DEBUG, "TDLS: Initiator Nonce for TPK handshake",
+                   peer->inonce, WPA_NONCE_LEN);
+       os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN);
+
+       wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TPK Handshake M1",
+                   (u8 *) ftie, sizeof(struct wpa_tdls_ftie));
+
+       pos = (u8 *) (ftie + 1);
+
+#ifdef CONFIG_TDLS_TESTING
+       if (tdls_testing & TDLS_TESTING_LONG_FRAME) {
+               wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to "
+                          "FTIE");
+               ftie->ie_len += 170;
+               *pos++ = 255; /* FTIE subelem */
+               *pos++ = 168; /* FTIE subelem length */
+               pos += 168;
+       }
+#endif /* CONFIG_TDLS_TESTING */
+
+       /* Lifetime */
+       peer->lifetime = TPK_LIFETIME;
+#ifdef CONFIG_TDLS_TESTING
+       if (tdls_testing & TDLS_TESTING_SHORT_LIFETIME) {
+               wpa_printf(MSG_DEBUG, "TDLS: Testing - use short TPK "
+                          "lifetime");
+               peer->lifetime = 301;
+       }
+       if (tdls_testing & TDLS_TESTING_LONG_LIFETIME) {
+               wpa_printf(MSG_DEBUG, "TDLS: Testing - use long TPK "
+                          "lifetime");
+               peer->lifetime = 0xffffffff;
+       }
+#endif /* CONFIG_TDLS_TESTING */
+       pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie,
+                                    sizeof(timeoutie), peer->lifetime);
+       wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", peer->lifetime);
+
+skip_ies:
+
+#ifdef CONFIG_TDLS_TESTING
+       if (tdls_testing & TDLS_TESTING_DIFF_BSSID) {
+               wpa_printf(MSG_DEBUG, "TDLS: Testing - use incorrect BSSID in "
+                          "Link Identifier");
+               struct wpa_tdls_lnkid *l = (struct wpa_tdls_lnkid *) pos;
+               wpa_tdls_linkid(sm, peer, l);
+               l->bssid[5] ^= 0x01;
+               pos += sizeof(*l);
+       }
+#endif /* CONFIG_TDLS_TESTING */
+
+       wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Request / TPK "
+                  "Handshake Message 1 (peer " MACSTR ")",
+                  MAC2STR(peer->addr));
+
+       wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, 1, 0,
+                         rbuf, pos - rbuf);
+       os_free(rbuf);
+
+       return 0;
+}
+
+
+static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm,
+                               const unsigned char *src_addr, u8 dtoken,
+                               struct wpa_tdls_lnkid *lnkid,
+                               const struct wpa_tdls_peer *peer)
+{
+       u8 *rbuf, *pos;
+       size_t buf_len;
+       u32 lifetime;
+       struct wpa_tdls_timeoutie timeoutie;
+       struct wpa_tdls_ftie *ftie;
+
+       buf_len = 0;
+       if (wpa_tdls_get_privacy(sm)) {
+               /* Peer RSN IE, FTIE(Initiator Nonce, Responder Nonce),
+                * Lifetime */
+               buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) +
+                       sizeof(struct wpa_tdls_timeoutie);
+#ifdef CONFIG_TDLS_TESTING
+               if (tdls_testing & TDLS_TESTING_LONG_FRAME)
+                       buf_len += 170;
+#endif /* CONFIG_TDLS_TESTING */
+       }
+
+       rbuf = os_zalloc(buf_len + 1);
+       if (rbuf == NULL)
+               return -1;
+       pos = rbuf;
+
+       if (!wpa_tdls_get_privacy(sm))
+               goto skip_ies;
+
+       /* Peer RSN IE */
+       pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len);
+
+       ftie = (struct wpa_tdls_ftie *) pos;
+       ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION;
+       /* TODO: ftie->mic_control to set 2-RESPONSE */
+       os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN);
+       os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN);
+       ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2;
+       wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TPK M2",
+                   (u8 *) ftie, sizeof(*ftie));
+
+       pos = (u8 *) (ftie + 1);
+
+#ifdef CONFIG_TDLS_TESTING
+       if (tdls_testing & TDLS_TESTING_LONG_FRAME) {
+               wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to "
+                          "FTIE");
+               ftie->ie_len += 170;
+               *pos++ = 255; /* FTIE subelem */
+               *pos++ = 168; /* FTIE subelem length */
+               pos += 168;
+       }
+#endif /* CONFIG_TDLS_TESTING */
+
+       /* Lifetime */
+       lifetime = peer->lifetime;
+#ifdef CONFIG_TDLS_TESTING
+       if (tdls_testing & TDLS_TESTING_WRONG_LIFETIME_RESP) {
+               wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong TPK "
+                          "lifetime in response");
+               lifetime++;
+       }
+#endif /* CONFIG_TDLS_TESTING */
+       pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie,
+                                    sizeof(timeoutie), lifetime);
+       wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds from initiator",
+                  lifetime);
+
+       /* compute MIC before sending */
+       wpa_tdls_ftie_mic(peer->tpk.kck, 2, (u8 *) lnkid, peer->rsnie_p,
+                         (u8 *) &timeoutie, (u8 *) ftie, ftie->mic);
+
+skip_ies:
+       wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, 0,
+                         rbuf, pos - rbuf);
+       os_free(rbuf);
+
+       return 0;
+}
+
+
+static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm,
+                               const unsigned char *src_addr, u8 dtoken,
+                               struct wpa_tdls_lnkid *lnkid,
+                               const struct wpa_tdls_peer *peer)
+{
+       u8 *rbuf, *pos;
+       size_t buf_len;
+       struct wpa_tdls_ftie *ftie;
+       struct wpa_tdls_timeoutie timeoutie;
+       u32 lifetime;
+
+       buf_len = 0;
+       if (wpa_tdls_get_privacy(sm)) {
+               /* Peer RSN IE, FTIE(Initiator Nonce, Responder Nonce),
+                * Lifetime */
+               buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) +
+                       sizeof(struct wpa_tdls_timeoutie);
+#ifdef CONFIG_TDLS_TESTING
+               if (tdls_testing & TDLS_TESTING_LONG_FRAME)
+                       buf_len += 170;
+#endif /* CONFIG_TDLS_TESTING */
+       }
+
+       rbuf = os_zalloc(buf_len + 1);
+       if (rbuf == NULL)
+               return -1;
+       pos = rbuf;
+
+       if (!wpa_tdls_get_privacy(sm))
+               goto skip_ies;
+
+       /* Peer RSN IE */
+       pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len);
+
+       ftie = (struct wpa_tdls_ftie *) pos;
+       ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION;
+       /*TODO: ftie->mic_control to set 3-CONFIRM */
+       os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN);
+       os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN);
+       ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2;
+
+       pos = (u8 *) (ftie + 1);
+
+#ifdef CONFIG_TDLS_TESTING
+       if (tdls_testing & TDLS_TESTING_LONG_FRAME) {
+               wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to "
+                          "FTIE");
+               ftie->ie_len += 170;
+               *pos++ = 255; /* FTIE subelem */
+               *pos++ = 168; /* FTIE subelem length */
+               pos += 168;
+       }
+#endif /* CONFIG_TDLS_TESTING */
+
+       /* Lifetime */
+       lifetime = peer->lifetime;
+#ifdef CONFIG_TDLS_TESTING
+       if (tdls_testing & TDLS_TESTING_WRONG_LIFETIME_CONF) {
+               wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong TPK "
+                          "lifetime in confirm");
+               lifetime++;
+       }
+#endif /* CONFIG_TDLS_TESTING */
+       pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie,
+                                    sizeof(timeoutie), lifetime);
+       wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds",
+                  lifetime);
+
+       /* compute MIC before sending */
+       wpa_tdls_ftie_mic(peer->tpk.kck, 3, (u8 *) lnkid, peer->rsnie_p,
+                         (u8 *) &timeoutie, (u8 *) ftie, ftie->mic);
+
+skip_ies:
+       wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 0,
+                         rbuf, pos - rbuf);
+       os_free(rbuf);
+
+       return 0;
+}
+
+
+static int wpa_tdls_send_discovery_response(struct wpa_sm *sm,
+                                           struct wpa_tdls_peer *peer,
+                                           u8 dialog_token)
+{
+       wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Discovery Response "
+                  "(peer " MACSTR ")", MAC2STR(peer->addr));
+
+       return wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE,
+                                dialog_token, 0, NULL, 0);
+}
+
+
+static int
+wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr,
+                                  const u8 *buf, size_t len)
+{
+       struct wpa_eapol_ie_parse kde;
+       const struct wpa_tdls_lnkid *lnkid;
+       struct wpa_tdls_peer *peer;
+       size_t min_req_len = sizeof(struct wpa_tdls_frame) +
+               1 /* dialog token */ + sizeof(struct wpa_tdls_lnkid);
+       u8 dialog_token;
+
+       wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from " MACSTR,
+                  MAC2STR(addr));
+
+       if (len < min_req_len) {
+               wpa_printf(MSG_DEBUG, "TDLS Discovery Request is too short: "
+                          "%d", (int) len);
+               return -1;
+       }
+
+       dialog_token = buf[sizeof(struct wpa_tdls_frame)];
+
+       if (wpa_supplicant_parse_ies(buf + sizeof(struct wpa_tdls_frame) + 1,
+                                    len - (sizeof(struct wpa_tdls_frame) + 1),
+                                    &kde) < 0)
+               return -1;
+
+       if (!kde.lnkid) {
+               wpa_printf(MSG_DEBUG, "TDLS: Link ID not found in Discovery "
+                          "Request");
+               return -1;
+       }
+
+       lnkid = (const struct wpa_tdls_lnkid *) kde.lnkid;
+
+       if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
+               wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from different "
+                          " BSS " MACSTR, MAC2STR(lnkid->bssid));
+               return -1;
+       }
+
+       peer = wpa_tdls_add_peer(sm, addr);
+       if (peer == NULL)
+               return -1;
+
+       return wpa_tdls_send_discovery_response(sm, peer, dialog_token);
+}
+
+
+int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr)
+{
+       if (sm->tdls_disabled || !sm->tdls_supported)
+               return -1;
+
+       wpa_printf(MSG_DEBUG, "TDLS: Sending Discovery Request to peer "
+                  MACSTR, MAC2STR(addr));
+       return wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_DISCOVERY_REQUEST,
+                                1, 0, NULL, 0);
+}
+
+
+static int copy_supp_rates(const struct wpa_eapol_ie_parse *kde,
+                          struct wpa_tdls_peer *peer)
+{
+       if (!kde->supp_rates) {
+               wpa_printf(MSG_DEBUG, "TDLS: No supported rates received");
+               return -1;
+       }
+
+       peer->supp_rates_len = kde->supp_rates_len - 2;
+       if (peer->supp_rates_len > IEEE80211_MAX_SUPP_RATES)
+               peer->supp_rates_len = IEEE80211_MAX_SUPP_RATES;
+       os_memcpy(peer->supp_rates, kde->supp_rates + 2, peer->supp_rates_len);
+
+       if (kde->ext_supp_rates) {
+               int clen = kde->ext_supp_rates_len - 2;
+               if (peer->supp_rates_len + clen > IEEE80211_MAX_SUPP_RATES)
+                       clen = IEEE80211_MAX_SUPP_RATES - peer->supp_rates_len;
+               os_memcpy(peer->supp_rates + peer->supp_rates_len,
+                         kde->ext_supp_rates + 2, clen);
+               peer->supp_rates_len += clen;
+       }
+
+       return 0;
+}
+
+
+static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
+                                  const u8 *buf, size_t len)
+{
+       struct wpa_tdls_peer *peer;
+       struct wpa_eapol_ie_parse kde;
+       struct wpa_ie_data ie;
+       int cipher;
+       const u8 *cpos;
+       struct wpa_tdls_ftie *ftie = NULL;
+       struct wpa_tdls_timeoutie *timeoutie;
+       struct wpa_tdls_lnkid *lnkid;
+       u32 lifetime = 0;
+#if 0
+       struct rsn_ie_hdr *hdr;
+       u8 *pos;
+       u16 rsn_capab;
+       u16 rsn_ver;
+#endif
+       u8 dtoken;
+       u16 ielen;
+       u16 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+       int tdls_prohibited = sm->tdls_prohibited;
+       int existing_peer = 0;
+
+       if (len < 3 + 3)
+               return -1;
+
+       cpos = buf;
+       cpos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
+
+       /* driver had already verified the frame format */
+       dtoken = *cpos++; /* dialog token */
+
+       wpa_printf(MSG_INFO, "TDLS: Dialog Token in TPK M1 %d", dtoken);
+
+       for (peer = sm->tdls; peer; peer = peer->next) {
+               if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) {
+                       existing_peer = 1;
+                       break;
+               }
+       }
+
+       if (peer == NULL) {
+               peer = wpa_tdls_add_peer(sm, src_addr);
+               if (peer == NULL)
+                       goto error;
+       }
+
+       /* capability information */
+       peer->capability = WPA_GET_LE16(cpos);
+       cpos += 2;
+
+       ielen = len - (cpos - buf); /* start of IE in buf */
+       if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0) {
+               wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in TPK M1");
+               goto error;
+       }
+
+       if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
+               wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in "
+                          "TPK M1");
+               goto error;
+       }
+       wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M1",
+                   kde.lnkid, kde.lnkid_len);
+       lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
+       if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
+               wpa_printf(MSG_INFO, "TDLS: TPK M1 from diff BSS");
+               status = WLAN_STATUS_NOT_IN_SAME_BSS;
+               goto error;
+       }
+
+       wpa_printf(MSG_DEBUG, "TDLS: TPK M1 - TPK initiator " MACSTR,
+                  MAC2STR(src_addr));
+
+       if (copy_supp_rates(&kde, peer) < 0)
+               goto error;
+
+#ifdef CONFIG_TDLS_TESTING
+       if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
+               for (peer = sm->tdls; peer; peer = peer->next) {
+                       if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0)
+                               break;
+               }
+               if (peer == NULL) {
+                       peer = wpa_tdls_add_peer(sm, src_addr);
+                       if (peer == NULL)
+                               goto error;
+               }
+               wpa_printf(MSG_DEBUG, "TDLS: Testing concurrent initiation of "
+                          "TDLS setup - send own request");
+               peer->initiator = 1;
+               wpa_tdls_send_tpk_m1(sm, peer);
+       }
+
+       if ((tdls_testing & TDLS_TESTING_IGNORE_AP_PROHIBIT) &&
+           tdls_prohibited) {
+               wpa_printf(MSG_DEBUG, "TDLS: Testing - ignore AP prohibition "
+                          "on TDLS");
+               tdls_prohibited = 0;
+       }
+#endif /* CONFIG_TDLS_TESTING */
+
+       if (tdls_prohibited) {
+               wpa_printf(MSG_INFO, "TDLS: TDLS prohibited in this BSS");
+               status = WLAN_STATUS_REQUEST_DECLINED;
+               goto error;
+       }
+
+       if (!wpa_tdls_get_privacy(sm)) {
+               if (kde.rsn_ie) {
+                       wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M1 while "
+                                  "security is disabled");
+                       status = WLAN_STATUS_SECURITY_DISABLED;
+                       goto error;
+               }
+               goto skip_rsn;
+       }
+
+       if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie) ||
+           kde.rsn_ie == NULL) {
+               wpa_printf(MSG_INFO, "TDLS: No FTIE or RSN IE in TPK M1");
+               status = WLAN_STATUS_INVALID_PARAMETERS;
+               goto error;
+       }
+
+       if (kde.rsn_ie_len > TDLS_MAX_IE_LEN) {
+               wpa_printf(MSG_INFO, "TDLS: Too long Initiator RSN IE in "
+                          "TPK M1");
+               status = WLAN_STATUS_INVALID_RSNIE;
+               goto error;
+       }
+
+       if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) {
+               wpa_printf(MSG_INFO, "TDLS: Failed to parse RSN IE in TPK M1");
+               status = WLAN_STATUS_INVALID_RSNIE;
+               goto error;
+       }
+
+       cipher = ie.pairwise_cipher;
+       if (cipher & WPA_CIPHER_CCMP) {
+               wpa_printf(MSG_DEBUG, "TDLS: Using CCMP for direct link");
+               cipher = WPA_CIPHER_CCMP;
+       } else {
+               wpa_printf(MSG_INFO, "TDLS: No acceptable cipher in TPK M1");
+               status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+               goto error;
+       }
+
+       if ((ie.capabilities &
+            (WPA_CAPABILITY_NO_PAIRWISE | WPA_CAPABILITY_PEERKEY_ENABLED)) !=
+           WPA_CAPABILITY_PEERKEY_ENABLED) {
+               wpa_printf(MSG_INFO, "TDLS: Invalid RSN Capabilities in "
+                          "TPK M1");
+               status = WLAN_STATUS_INVALID_RSN_IE_CAPAB;
+               goto error;
+       }
+
+       /* Lifetime */
+       if (kde.key_lifetime == NULL) {
+               wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M1");
+               status = WLAN_STATUS_UNACCEPTABLE_LIFETIME;
+               goto error;
+       }
+       timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime;
+       lifetime = WPA_GET_LE32(timeoutie->value);
+       wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", lifetime);
+       if (lifetime < 300) {
+               wpa_printf(MSG_INFO, "TDLS: Too short TPK lifetime");
+               status = WLAN_STATUS_UNACCEPTABLE_LIFETIME;
+               goto error;
+       }
+
+skip_rsn:
+       /* If found, use existing entry instead of adding a new one;
+        * how to handle the case where both ends initiate at the
+        * same time? */
+       if (existing_peer) {
+               if (peer->tpk_success) {
+                       wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while "
+                                  "direct link is enabled - tear down the "
+                                  "old link first");
+#if 0
+                       /* TODO: Disabling the link would be more proper
+                        * operation here, but it seems to trigger a race with
+                        * some drivers handling the new request frame. */
+                       wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+#else
+                       if (sm->tdls_external_setup)
+                               wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
+                                                src_addr);
+                       else
+                               wpa_tdls_del_key(sm, peer);
+#endif
+                       wpa_tdls_peer_free(sm, peer);
+               }
+
+               /*
+                * An entry is already present, so check if we already sent a
+                * TDLS Setup Request. If so, compare MAC addresses and let the
+                * STA with the lower MAC address continue as the initiator.
+                * The other negotiation is terminated.
+                */
+               if (peer->initiator) {
+                       if (os_memcmp(sm->own_addr, src_addr, ETH_ALEN) < 0) {
+                               wpa_printf(MSG_DEBUG, "TDLS: Discard request "
+                                          "from peer with higher address "
+                                          MACSTR, MAC2STR(src_addr));
+                               return -1;
+                       } else {
+                               wpa_printf(MSG_DEBUG, "TDLS: Accept request "
+                                          "from peer with lower address "
+                                          MACSTR " (terminate previously "
+                                          "initiated negotiation",
+                                          MAC2STR(src_addr));
+                               wpa_tdls_peer_free(sm, peer);
+                       }
+               }
+       }
+
+#ifdef CONFIG_TDLS_TESTING
+       if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
+               if (os_memcmp(sm->own_addr, peer->addr, ETH_ALEN) < 0) {
+                       /*
+                        * The request frame from us is going to win, so do not
+                        * replace information based on this request frame from
+                        * the peer.
+                        */
+                       goto skip_rsn_check;
+               }
+       }
+#endif /* CONFIG_TDLS_TESTING */
+
+       peer->initiator = 0; /* Need to check */
+       peer->dtoken = dtoken;
+
+       if (!wpa_tdls_get_privacy(sm)) {
+               peer->rsnie_i_len = 0;
+               peer->rsnie_p_len = 0;
+               peer->cipher = WPA_CIPHER_NONE;
+               goto skip_rsn_check;
+       }
+
+       ftie = (struct wpa_tdls_ftie *) kde.ftie;
+       os_memcpy(peer->inonce, ftie->Snonce, WPA_NONCE_LEN);
+       os_memcpy(peer->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
+       peer->rsnie_i_len = kde.rsn_ie_len;
+       peer->cipher = cipher;
+
+       if (os_get_random(peer->rnonce, WPA_NONCE_LEN)) {
+               wpa_msg(sm->ctx->ctx, MSG_WARNING,
+                       "TDLS: Failed to get random data for responder nonce");
+               wpa_tdls_peer_free(sm, peer);
+               goto error;
+       }
+
+#if 0
+       /* get version info from RSNIE received from Peer */
+       hdr = (struct rsn_ie_hdr *) kde.rsn_ie;
+       rsn_ver = WPA_GET_LE16(hdr->version);
+
+       /* use min(peer's version, out version) */
+       if (rsn_ver > RSN_VERSION)
+               rsn_ver = RSN_VERSION;
+
+       hdr = (struct rsn_ie_hdr *) peer->rsnie_p;
+
+       hdr->elem_id = WLAN_EID_RSN;
+       WPA_PUT_LE16(hdr->version, rsn_ver);
+       pos = (u8 *) (hdr + 1);
+
+       RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+       pos += RSN_SELECTOR_LEN;
+       /* Include only the selected cipher in pairwise cipher suite */
+       WPA_PUT_LE16(pos, 1);
+       pos += 2;
+       if (cipher == WPA_CIPHER_CCMP)
+               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+       pos += RSN_SELECTOR_LEN;
+
+       WPA_PUT_LE16(pos, 1);
+       pos += 2;
+       RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE);
+       pos += RSN_SELECTOR_LEN;
+
+       rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED;
+       rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2;
+       WPA_PUT_LE16(pos, rsn_capab);
+       pos += 2;
+
+       hdr->len = (pos - peer->rsnie_p) - 2;
+       peer->rsnie_p_len = pos - peer->rsnie_p;
+#endif
+
+       /* temp fix: validation of RSNIE later */
+       os_memcpy(peer->rsnie_p, peer->rsnie_i, peer->rsnie_i_len);
+       peer->rsnie_p_len = peer->rsnie_i_len;
+
+       wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for TPK handshake",
+                   peer->rsnie_p, peer->rsnie_p_len);
+
+       peer->lifetime = lifetime;
+
+       wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid);
+
+skip_rsn_check:
+       /* add the peer to the driver as a "setup in progress" peer */
+       wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+
+       wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
+       if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) {
+               wpa_tdls_disable_link(sm, peer->addr);
+               goto error;
+       }
+
+       return 0;
+
+error:
+       wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken,
+                           status);
+       return -1;
+}
+
+
+static void wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+{
+       peer->tpk_success = 1;
+       eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
+       if (wpa_tdls_get_privacy(sm)) {
+               u32 lifetime = peer->lifetime;
+               /*
+                * Start the initiator process a bit earlier to avoid race
+                * condition with the responder sending teardown request.
+                */
+               if (lifetime > 3 && peer->initiator)
+                       lifetime -= 3;
+               eloop_register_timeout(lifetime, 0, wpa_tdls_tpk_timeout,
+                                      sm, peer);
+#ifdef CONFIG_TDLS_TESTING
+       if (tdls_testing & TDLS_TESTING_NO_TPK_EXPIRATION) {
+               wpa_printf(MSG_DEBUG, "TDLS: Testing - disable TPK "
+                          "expiration");
+               eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
+       }
+#endif /* CONFIG_TDLS_TESTING */
+       }
+
+       /* add supported rates and capabilities to the TDLS peer */
+       wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->capability,
+                               peer->supp_rates, peer->supp_rates_len);
+
+       wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr);
+}
+
+
+static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
+                                  const u8 *buf, size_t len)
+{
+       struct wpa_tdls_peer *peer;
+       struct wpa_eapol_ie_parse kde;
+       struct wpa_ie_data ie;
+       int cipher;
+       struct wpa_tdls_ftie *ftie;
+       struct wpa_tdls_timeoutie *timeoutie;
+       struct wpa_tdls_lnkid *lnkid;
+       u32 lifetime;
+       u8 dtoken;
+       int ielen;
+       u16 status;
+       const u8 *pos;
+
+       wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Response / TPK M2 "
+                  "(Peer " MACSTR ")", MAC2STR(src_addr));
+       for (peer = sm->tdls; peer; peer = peer->next) {
+               if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0)
+                       break;
+       }
+       if (peer == NULL) {
+               wpa_printf(MSG_INFO, "TDLS: No matching peer found for "
+                          "TPK M2: " MACSTR, MAC2STR(src_addr));
+               return -1;
+       }
+       wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_REQUEST);
+
+       if (len < 3 + 2 + 1)
+               return -1;
+       pos = buf;
+       pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
+       status = WPA_GET_LE16(pos);
+       pos += 2 /* status code */;
+
+       if (status != WLAN_STATUS_SUCCESS) {
+               wpa_printf(MSG_INFO, "TDLS: Status code in TPK M2: %u",
+                          status);
+               if (sm->tdls_external_setup)
+                       wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+               return -1;
+       }
+
+       status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+       /* TODO: need to verify dialog token matches here or in kernel */
+       dtoken = *pos++; /* dialog token */
+
+       wpa_printf(MSG_DEBUG, "TDLS: Dialog Token in TPK M2 %d", dtoken);
+
+       if (len < 3 + 2 + 1 + 2)
+               return -1;
+
+       /* capability information */
+       peer->capability = WPA_GET_LE16(pos);
+       pos += 2;
+
+       ielen = len - (pos - buf); /* start of IE in buf */
+       if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0) {
+               wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in TPK M2");
+               goto error;
+       }
+
+#ifdef CONFIG_TDLS_TESTING
+       if (tdls_testing & TDLS_TESTING_DECLINE_RESP) {
+               wpa_printf(MSG_DEBUG, "TDLS: Testing - decline response");
+               status = WLAN_STATUS_REQUEST_DECLINED;
+               goto error;
+       }
+#endif /* CONFIG_TDLS_TESTING */
+
+       if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
+               wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in "
+                          "TPK M2");
+               goto error;
+       }
+       wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M2",
+                   kde.lnkid, kde.lnkid_len);
+       lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
+
+       if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
+               wpa_printf(MSG_INFO, "TDLS: TPK M2 from different BSS");
+               status = WLAN_STATUS_NOT_IN_SAME_BSS;
+               goto error;
+       }
+
+       if (copy_supp_rates(&kde, peer) < 0)
+               goto error;
+
+       if (!wpa_tdls_get_privacy(sm)) {
+               peer->rsnie_p_len = 0;
+               peer->cipher = WPA_CIPHER_NONE;
+               goto skip_rsn;
+       }
+
+       if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie) ||
+           kde.rsn_ie == NULL) {
+               wpa_printf(MSG_INFO, "TDLS: No FTIE or RSN IE in TPK M2");
+               status = WLAN_STATUS_INVALID_PARAMETERS;
+               goto error;
+       }
+       wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2",
+                   kde.rsn_ie, kde.rsn_ie_len);
+
+       /*
+        * FIX: bitwise comparison of RSN IE is not the correct way of
+        * validation this. It can be different, but certain fields must
+        * match. Since we list only a single pairwise cipher in TPK M1, the
+        * memcmp is likely to work in most cases, though.
+        */
+       if (kde.rsn_ie_len != peer->rsnie_i_len ||
+           os_memcmp(peer->rsnie_i, kde.rsn_ie, peer->rsnie_i_len) != 0) {
+               wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M2 does "
+                          "not match with RSN IE used in TPK M1");
+               wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Sent in TPK M1",
+                           peer->rsnie_i, peer->rsnie_i_len);
+               wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2",
+                           kde.rsn_ie, kde.rsn_ie_len);
+               status = WLAN_STATUS_INVALID_RSNIE;
+               goto error;
+       }
+
+       if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) {
+               wpa_printf(MSG_INFO, "TDLS: Failed to parse RSN IE in TPK M2");
+               status = WLAN_STATUS_INVALID_RSNIE;
+               goto error;
+       }
+
+       cipher = ie.pairwise_cipher;
+       if (cipher == WPA_CIPHER_CCMP) {
+               wpa_printf(MSG_DEBUG, "TDLS: Using CCMP for direct link");
+               cipher = WPA_CIPHER_CCMP;
+       } else {
+               wpa_printf(MSG_INFO, "TDLS: No acceptable cipher in TPK M2");
+               status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+               goto error;
+       }
+
+       wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M2",
+                   kde.ftie, sizeof(*ftie));
+       ftie = (struct wpa_tdls_ftie *) kde.ftie;
+
+       if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) {
+               wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M2 does "
+                          "not match with FTIE SNonce used in TPK M1");
+               /* Silently discard the frame */
+               return -1;
+       }
+
+       /* Responder Nonce and RSN IE */
+       os_memcpy(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN);
+       os_memcpy(peer->rsnie_p, kde.rsn_ie, kde.rsn_ie_len);
+       peer->rsnie_p_len = kde.rsn_ie_len;
+       peer->cipher = cipher;
+
+       /* Lifetime */
+       if (kde.key_lifetime == NULL) {
+               wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M2");
+               status = WLAN_STATUS_UNACCEPTABLE_LIFETIME;
+               goto error;
+       }
+       timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime;
+       lifetime = WPA_GET_LE32(timeoutie->value);
+       wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds in TPK M2",
+                  lifetime);
+       if (lifetime != peer->lifetime) {
+               wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in "
+                          "TPK M2 (expected %u)", lifetime, peer->lifetime);
+               status = WLAN_STATUS_UNACCEPTABLE_LIFETIME;
+               goto error;
+       }
+
+       wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid);
+
+       /* Process MIC check to see if TPK M2 is right */
+       if (wpa_supplicant_verify_tdls_mic(2, peer, (u8 *) lnkid,
+                                          (u8 *) timeoutie, ftie) < 0) {
+               /* Discard the frame */
+               wpa_tdls_del_key(sm, peer);
+               wpa_tdls_peer_free(sm, peer);
+               if (sm->tdls_external_setup)
+                       wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+               return -1;
+       }
+
+       wpa_tdls_set_key(sm, peer);
+
+skip_rsn:
+       peer->dtoken = dtoken;
+
+       wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Confirm / "
+                  "TPK Handshake Message 3");
+       wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer);
+
+       wpa_tdls_enable_link(sm, peer);
+
+       return 0;
+
+error:
+       wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken,
+                           status);
+       if (sm->tdls_external_setup)
+               wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+       return -1;
+}
+
+
+static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
+                                  const u8 *buf, size_t len)
+{
+       struct wpa_tdls_peer *peer;
+       struct wpa_eapol_ie_parse kde;
+       struct wpa_tdls_ftie *ftie;
+       struct wpa_tdls_timeoutie *timeoutie;
+       struct wpa_tdls_lnkid *lnkid;
+       int ielen;
+       u16 status;
+       const u8 *pos;
+       u32 lifetime;
+
+       wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Confirm / TPK M3 "
+                  "(Peer " MACSTR ")", MAC2STR(src_addr));
+       for (peer = sm->tdls; peer; peer = peer->next) {
+               if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0)
+                       break;
+       }
+       if (peer == NULL) {
+               wpa_printf(MSG_INFO, "TDLS: No matching peer found for "
+                          "TPK M3: " MACSTR, MAC2STR(src_addr));
+               return -1;
+       }
+       wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_RESPONSE);
+
+       if (len < 3 + 3)
+               return -1;
+       pos = buf;
+       pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
+
+       status = WPA_GET_LE16(pos);
+
+       if (status != 0) {
+               wpa_printf(MSG_INFO, "TDLS: Status code in TPK M3: %u",
+                          status);
+               if (sm->tdls_external_setup)
+                       wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+               return -1;
+       }
+       pos += 2 /* status code */ + 1 /* dialog token */;
+
+       ielen = len - (pos - buf); /* start of IE in buf */
+       if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) {
+               wpa_printf(MSG_INFO, "TDLS: Failed to parse KDEs in TPK M3");
+               return -1;
+       }
+
+       if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
+               wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TPK M3");
+               return -1;
+       }
+       wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M3",
+                   (u8 *) kde.lnkid, kde.lnkid_len);
+       lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
+
+       if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
+               wpa_printf(MSG_INFO, "TDLS: TPK M3 from diff BSS");
+               return -1;
+       }
+
+       if (!wpa_tdls_get_privacy(sm))
+               goto skip_rsn;
+
+       if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) {
+               wpa_printf(MSG_INFO, "TDLS: No FTIE in TPK M3");
+               return -1;
+       }
+       wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M3",
+                   kde.ftie, sizeof(*ftie));
+       ftie = (struct wpa_tdls_ftie *) kde.ftie;
+
+       if (kde.rsn_ie == NULL) {
+               wpa_printf(MSG_INFO, "TDLS: No RSN IE in TPK M3");
+               return -1;
+       }
+       wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M3",
+                   kde.rsn_ie, kde.rsn_ie_len);
+       if (kde.rsn_ie_len != peer->rsnie_p_len ||
+           os_memcmp(kde.rsn_ie, peer->rsnie_p, peer->rsnie_p_len) != 0) {
+               wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M3 does not match "
+                          "with the one sent in TPK M2");
+               return -1;
+       }
+
+       if (!os_memcmp(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN) == 0) {
+               wpa_printf(MSG_INFO, "TDLS: FTIE ANonce in TPK M3 does "
+                          "not match with FTIE ANonce used in TPK M2");
+               return -1;
+       }
+
+       if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) {
+               wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M3 does not "
+                          "match with FTIE SNonce used in TPK M1");
+               return -1;
+       }
+
+       if (kde.key_lifetime == NULL) {
+               wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M3");
+               return -1;
+       }
+       timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime;
+       wpa_hexdump(MSG_DEBUG, "TDLS: Timeout IE Received from TPK M3",
+                   (u8 *) timeoutie, sizeof(*timeoutie));
+       lifetime = WPA_GET_LE32(timeoutie->value);
+       wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds in TPK M3",
+                  lifetime);
+       if (lifetime != peer->lifetime) {
+               wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in "
+                          "TPK M3 (expected %u)", lifetime, peer->lifetime);
+               if (sm->tdls_external_setup)
+                       wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+               return -1;
+       }
+
+       if (wpa_supplicant_verify_tdls_mic(3, peer, (u8 *) lnkid,
+                                          (u8 *) timeoutie, ftie) < 0) {
+               wpa_tdls_del_key(sm, peer);
+               wpa_tdls_peer_free(sm, peer);
+               return -1;
+       }
+
+       if (wpa_tdls_set_key(sm, peer) < 0)
+               return -1;
+
+skip_rsn:
+       wpa_tdls_enable_link(sm, peer);
+
+       return 0;
+}
+
+
+static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs)
+{
+       struct wpa_tdls_timeoutie *lifetime = (struct wpa_tdls_timeoutie *) ie;
+
+       os_memset(lifetime, 0, ie_len);
+       lifetime->ie_type = WLAN_EID_TIMEOUT_INTERVAL;
+       lifetime->ie_len = sizeof(struct wpa_tdls_timeoutie) - 2;
+       lifetime->interval_type = WLAN_TIMEOUT_KEY_LIFETIME;
+       WPA_PUT_LE32(lifetime->value, tsecs);
+       os_memcpy(pos, ie, ie_len);
+       return pos + ie_len;
+}
+
+
+/**
+ * wpa_tdls_start - Initiate TDLS handshake (send TPK Handshake Message 1)
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @peer: MAC address of the peer STA
+ * Returns: 0 on success, or -1 on failure
+ *
+ * Send TPK Handshake Message 1 info to driver to start TDLS
+ * handshake with the peer.
+ */
+int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
+{
+       struct wpa_tdls_peer *peer;
+       int tdls_prohibited = sm->tdls_prohibited;
+
+       if (sm->tdls_disabled || !sm->tdls_supported)
+               return -1;
+
+#ifdef CONFIG_TDLS_TESTING
+       if ((tdls_testing & TDLS_TESTING_IGNORE_AP_PROHIBIT) &&
+           tdls_prohibited) {
+               wpa_printf(MSG_DEBUG, "TDLS: Testing - ignore AP prohibition "
+                          "on TDLS");
+               tdls_prohibited = 0;
+       }
+#endif /* CONFIG_TDLS_TESTING */
+
+       if (tdls_prohibited) {
+               wpa_printf(MSG_DEBUG, "TDLS: TDLS is prohibited in this BSS - "
+                          "reject request to start setup");
+               return -1;
+       }
+
+       /* Find existing entry and if found, use that instead of adding
+        * a new one */
+       for (peer = sm->tdls; peer; peer = peer->next) {
+               if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+                       break;
+       }
+
+       if (peer == NULL) {
+               peer = wpa_tdls_add_peer(sm, addr);
+               if (peer == NULL)
+                       return -1;
+       }
+
+       peer->initiator = 1;
+
+       /* add the peer to the driver as a "setup in progress" peer */
+       wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+
+       if (wpa_tdls_send_tpk_m1(sm, peer) < 0) {
+               wpa_tdls_disable_link(sm, peer->addr);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr)
+{
+       struct wpa_tdls_peer *peer;
+
+       if (sm->tdls_disabled || !sm->tdls_supported)
+               return -1;
+
+       for (peer = sm->tdls; peer; peer = peer->next) {
+               if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+                       break;
+       }
+
+       if (peer == NULL || !peer->tpk_success)
+               return -1;
+
+       if (sm->tdls_external_setup) {
+               /*
+                * Disable previous link to allow renegotiation to be completed
+                * on AP path.
+                */
+               wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+       }
+
+       return wpa_tdls_start(sm, addr);
+}
+
+
+/**
+ * wpa_supplicant_rx_tdls - Receive TDLS data frame
+ *
+ * This function is called to receive TDLS (ethertype = 0x890d) data frames.
+ */
+static void wpa_supplicant_rx_tdls(void *ctx, const u8 *src_addr,
+                                  const u8 *buf, size_t len)
+{
+       struct wpa_sm *sm = ctx;
+       struct wpa_tdls_frame *tf;
+
+       wpa_hexdump(MSG_DEBUG, "TDLS: Received Data frame encapsulation",
+                   buf, len);
+
+       if (sm->tdls_disabled || !sm->tdls_supported) {
+               wpa_printf(MSG_DEBUG, "TDLS: Discard message - TDLS disabled "
+                          "or unsupported by driver");
+               return;
+       }
+
+       if (os_memcmp(src_addr, sm->own_addr, ETH_ALEN) == 0) {
+               wpa_printf(MSG_DEBUG, "TDLS: Discard copy of own message");
+               return;
+       }
+
+       if (len < sizeof(*tf)) {
+               wpa_printf(MSG_INFO, "TDLS: Drop too short frame");
+               return;
+       }
+
+       /* Check to make sure its a valid encapsulated TDLS frame */
+       tf = (struct wpa_tdls_frame *) buf;
+       if (tf->payloadtype != 2 /* TDLS_RFTYPE */ ||
+           tf->category != WLAN_ACTION_TDLS) {
+               wpa_printf(MSG_INFO, "TDLS: Invalid frame - payloadtype=%u "
+                          "category=%u action=%u",
+                          tf->payloadtype, tf->category, tf->action);
+               return;
+       }
+
+       switch (tf->action) {
+       case WLAN_TDLS_SETUP_REQUEST:
+               wpa_tdls_process_tpk_m1(sm, src_addr, buf, len);
+               break;
+       case WLAN_TDLS_SETUP_RESPONSE:
+               wpa_tdls_process_tpk_m2(sm, src_addr, buf, len);
+               break;
+       case WLAN_TDLS_SETUP_CONFIRM:
+               wpa_tdls_process_tpk_m3(sm, src_addr, buf, len);
+               break;
+       case WLAN_TDLS_TEARDOWN:
+               wpa_tdls_recv_teardown(sm, src_addr, buf, len);
+               break;
+       case WLAN_TDLS_DISCOVERY_REQUEST:
+               wpa_tdls_process_discovery_request(sm, src_addr, buf, len);
+               break;
+       default:
+               /* Kernel code will process remaining frames */
+               wpa_printf(MSG_DEBUG, "TDLS: Ignore TDLS frame action code %u",
+                          tf->action);
+               break;
+       }
+}
+
+
+/**
+ * wpa_tdls_init - Initialize driver interface parameters for TDLS
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called to initialize driver interface parameters for TDLS.
+ * wpa_drv_init() must have been called before this function to initialize the
+ * driver interface.
+ */
+int wpa_tdls_init(struct wpa_sm *sm)
+{
+       if (sm == NULL)
+               return -1;
+
+       sm->l2_tdls = l2_packet_init(sm->ifname, sm->own_addr,
+                                    ETH_P_80211_ENCAP, wpa_supplicant_rx_tdls,
+                                    sm, 0);
+       if (sm->l2_tdls == NULL) {
+               wpa_printf(MSG_ERROR, "TDLS: Failed to open l2_packet "
+                          "connection");
+               return -1;
+       }
+
+       /*
+        * Drivers that support TDLS but don't implement the get_capa callback
+        * are assumed to perform everything internally
+        */
+       if (wpa_sm_tdls_get_capa(sm, &sm->tdls_supported,
+                                &sm->tdls_external_setup) < 0) {
+               sm->tdls_supported = 1;
+               sm->tdls_external_setup = 0;
+       }
+
+       wpa_printf(MSG_DEBUG, "TDLS: TDLS operation%s supported by "
+                  "driver", sm->tdls_supported ? "" : " not");
+       wpa_printf(MSG_DEBUG, "TDLS: Driver uses %s link setup",
+                  sm->tdls_external_setup ? "external" : "internal");
+
+       return 0;
+}
+
+
+static void wpa_tdls_remove_peers(struct wpa_sm *sm)
+{
+       struct wpa_tdls_peer *peer, *tmp;
+
+       peer = sm->tdls;
+       sm->tdls = NULL;
+
+       while (peer) {
+               int res;
+               tmp = peer->next;
+               res = wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+               wpa_printf(MSG_DEBUG, "TDLS: Remove peer " MACSTR " (res=%d)",
+                          MAC2STR(peer->addr), res);
+               wpa_tdls_peer_free(sm, peer);
+               os_free(peer);
+               peer = tmp;
+       }
+}
+
+
+/**
+ * wpa_tdls_deinit - Deinitialize driver interface parameters for TDLS
+ *
+ * This function is called to recover driver interface parameters for TDLS
+ * and frees resources allocated for it.
+ */
+void wpa_tdls_deinit(struct wpa_sm *sm)
+{
+       if (sm == NULL)
+               return;
+
+       if (sm->l2_tdls)
+               l2_packet_deinit(sm->l2_tdls);
+       sm->l2_tdls = NULL;
+
+       wpa_tdls_remove_peers(sm);
+}
+
+
+void wpa_tdls_assoc(struct wpa_sm *sm)
+{
+       wpa_printf(MSG_DEBUG, "TDLS: Remove peers on association");
+       wpa_tdls_remove_peers(sm);
+}
+
+
+void wpa_tdls_disassoc(struct wpa_sm *sm)
+{
+       wpa_printf(MSG_DEBUG, "TDLS: Remove peers on disassociation");
+       wpa_tdls_remove_peers(sm);
+}
+
+
+static int wpa_tdls_prohibited(const u8 *ies, size_t len)
+{
+       struct wpa_eapol_ie_parse elems;
+
+       if (ies == NULL)
+               return 0;
+
+       if (wpa_supplicant_parse_ies(ies, len, &elems) < 0)
+               return 0;
+
+       if (elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
+               return 0;
+
+        /* bit 38 - TDLS Prohibited */
+       return !!(elems.ext_capab[2 + 4] & 0x40);
+}
+
+
+void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len)
+{
+       sm->tdls_prohibited = wpa_tdls_prohibited(ies, len);
+       wpa_printf(MSG_DEBUG, "TDLS: TDLS is %s in the target BSS",
+                  sm->tdls_prohibited ? "prohibited" : "allowed");
+}
+
+
+void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len)
+{
+       if (!sm->tdls_prohibited && wpa_tdls_prohibited(ies, len)) {
+               wpa_printf(MSG_DEBUG, "TDLS: TDLS prohibited based on "
+                          "(Re)Association Response IEs");
+               sm->tdls_prohibited = 1;
+       }
+}
+
+
+void wpa_tdls_enable(struct wpa_sm *sm, int enabled)
+{
+       wpa_printf(MSG_DEBUG, "TDLS: %s", enabled ? "enabled" : "disabled");
+       sm->tdls_disabled = !enabled;
+}
+
+
+int wpa_tdls_is_external_setup(struct wpa_sm *sm)
+{
+       return sm->tdls_external_setup;
+}
index 9439f97..f35f9ee 100644 (file)
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "crypto/aes_wrap.h"
 #include "crypto/crypto.h"
+#include "crypto/random.h"
 #include "common/ieee802_11_defs.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "wpa.h"
@@ -49,21 +50,26 @@ void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
                 * BSSID from the driver.
                 */
                if (wpa_sm_get_bssid(sm, sm->bssid) < 0) {
-                       wpa_printf(MSG_DEBUG, "WPA: Failed to read BSSID for "
-                                  "EAPOL-Key destination address");
+                       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                               "WPA: Failed to read BSSID for "
+                               "EAPOL-Key destination address");
                } else {
                        dest = sm->bssid;
-                       wpa_printf(MSG_DEBUG, "WPA: Use BSSID (" MACSTR
-                                  ") as the destination for EAPOL-Key",
-                                  MAC2STR(dest));
+                       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                               "WPA: Use BSSID (" MACSTR
+                               ") as the destination for EAPOL-Key",
+                               MAC2STR(dest));
                }
        }
        if (key_mic &&
            wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic)) {
-               wpa_printf(MSG_ERROR, "WPA: Failed to generate EAPOL-Key "
-                          "version %d MIC", ver);
+               wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+                       "WPA: Failed to generate EAPOL-Key "
+                       "version %d MIC", ver);
                goto out;
        }
+       wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, 16);
+       wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, 16);
        wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len);
        wpa_sm_ether_send(sm, dest, proto, msg, msg_len);
        eapol_sm_notify_tx_eapol_key(sm->eapol);
@@ -97,8 +103,8 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
                ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
 
        if (wpa_sm_get_bssid(sm, bssid) < 0) {
-               wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key "
-                          "request");
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "Failed to read BSSID for EAPOL-Key request");
                return;
        }
 
@@ -124,9 +130,10 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
 
        WPA_PUT_BE16(reply->key_data_length, 0);
 
-       wpa_printf(MSG_INFO, "WPA: Sending EAPOL-Key Request (error=%d "
-                  "pairwise=%d ptk_set=%d len=%lu)",
-                  error, pairwise, sm->ptk_set, (unsigned long) rlen);
+       wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+               "WPA: Sending EAPOL-Key Request (error=%d "
+               "pairwise=%d ptk_set=%d len=%lu)",
+               error, pairwise, sm->ptk_set, (unsigned long) rlen);
        wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
                           rbuf, rlen, key_info & WPA_KEY_INFO_MIC ?
                           reply->key_mic : NULL);
@@ -146,10 +153,11 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
                 * matching PMKSA cache entry here. */
                sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid);
                if (sm->cur_pmksa) {
-                       wpa_printf(MSG_DEBUG, "RSN: found matching PMKID from "
-                                  "PMKSA cache");
+                       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                               "RSN: found matching PMKID from PMKSA cache");
                } else {
-                       wpa_printf(MSG_DEBUG, "RSN: no matching PMKID found");
+                       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                               "RSN: no matching PMKID found");
                        abort_cached = 1;
                }
        }
@@ -190,26 +198,28 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
                        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) {
+                       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);
                        }
                        if (!sm->cur_pmksa && pmkid &&
                            pmksa_cache_get(sm->pmksa, src_addr, pmkid)) {
-                               wpa_printf(MSG_DEBUG, "RSN: the new PMK "
-                                          "matches with the PMKID");
+                               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                                       "RSN: the new PMK matches with the "
+                                       "PMKID");
                                abort_cached = 0;
                        }
                } else {
                        wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                                "WPA: Failed to get master session key from "
-                               "EAPOL state machines");
-                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
-                               "WPA: Key handshake aborted");
+                               "EAPOL state machines - key handshake "
+                               "aborted");
                        if (sm->cur_pmksa) {
-                               wpa_printf(MSG_DEBUG, "RSN: Cancelled PMKSA "
-                                          "caching attempt");
+                               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                                       "RSN: Cancelled PMKSA caching "
+                                       "attempt");
                                sm->cur_pmksa = NULL;
                                abort_cached = 1;
                        } else if (!abort_cached) {
@@ -218,13 +228,15 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
                }
        }
 
-       if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) {
+       if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) &&
+           !wpa_key_mgmt_ft(sm->key_mgmt)) {
                /* Send EAPOL-Start to trigger full EAP authentication. */
                u8 *buf;
                size_t buflen;
 
-               wpa_printf(MSG_DEBUG, "RSN: no PMKSA entry found - trigger "
-                          "full EAP authentication");
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "RSN: no PMKSA entry found - trigger "
+                       "full EAP authentication");
                buf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_START,
                                         NULL, 0, &buflen, NULL);
                if (buf) {
@@ -265,8 +277,8 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
        u8 *rsn_ie_buf = NULL;
 
        if (wpa_ie == NULL) {
-               wpa_printf(MSG_WARNING, "WPA: No wpa_ie set - cannot "
-                          "generate msg 2/4");
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No wpa_ie set - "
+                       "cannot generate msg 2/4");
                return -1;
        }
 
@@ -321,6 +333,8 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
                os_memcpy(reply->key_length, key->key_length, 2);
        os_memcpy(reply->replay_counter, key->replay_counter,
                  WPA_REPLAY_COUNTER_LEN);
+       wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter", reply->replay_counter,
+                   WPA_REPLAY_COUNTER_LEN);
 
        WPA_PUT_BE16(reply->key_data_length, wpa_ie_len);
        os_memcpy(reply + 1, wpa_ie, wpa_ie_len);
@@ -328,7 +342,7 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
 
        os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
 
-       wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4");
+       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4");
        wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
                           rbuf, rlen, reply->key_mic);
 
@@ -365,14 +379,14 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
        int res;
 
        if (wpa_sm_get_network_ctx(sm) == NULL) {
-               wpa_printf(MSG_WARNING, "WPA: No SSID info found (msg 1 of "
-                          "4).");
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No SSID info "
+                       "found (msg 1 of 4)");
                return;
        }
 
        wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
-       wpa_printf(MSG_DEBUG, "WPA: RX message 1 of 4-Way Handshake from "
-                  MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
+       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of 4-Way "
+               "Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
 
        os_memset(&ie, 0, sizeof(ie));
 
@@ -382,7 +396,8 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
                const u8 *_buf = (const u8 *) (key + 1);
                size_t len = WPA_GET_BE16(key->key_data_length);
                wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", _buf, len);
-               wpa_supplicant_parse_ies(_buf, len, &ie);
+               if (wpa_supplicant_parse_ies(_buf, len, &ie) < 0)
+                       goto failed;
                if (ie.pmkid) {
                        wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
                                    "Authenticator", ie.pmkid, PMKID_LEN);
@@ -392,15 +407,15 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
 
        res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);
        if (res == -2) {
-               wpa_printf(MSG_DEBUG, "RSN: Do not reply to msg 1/4 - "
-                          "requesting full EAP authentication");
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: Do not reply to "
+                       "msg 1/4 - requesting full EAP authentication");
                return;
        }
        if (res)
                goto failed;
 
        if (sm->renew_snonce) {
-               if (os_get_random(sm->snonce, WPA_NONCE_LEN)) {
+               if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) {
                        wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                                "WPA: Failed to get random data for SNonce");
                        goto failed;
@@ -462,15 +477,16 @@ static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
                 * Start preauthentication after a short wait to avoid a
                 * possible race condition between the data receive and key
                 * configuration after the 4-Way Handshake. This increases the
-                * likelyhood of the first preauth EAPOL-Start frame getting to
+                * likelihood of the first preauth EAPOL-Start frame getting to
                 * the target AP.
                 */
                eloop_register_timeout(1, 0, wpa_sm_start_preauth, sm, NULL);
        }
 
        if (sm->cur_pmksa && sm->cur_pmksa->opportunistic) {
-               wpa_printf(MSG_DEBUG, "RSN: Authenticator accepted "
-                          "opportunistic PMKSA entry - marking it valid");
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "RSN: Authenticator accepted "
+                       "opportunistic PMKSA entry - marking it valid");
                sm->cur_pmksa->opportunistic = 0;
        }
 
@@ -486,7 +502,7 @@ static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
 static void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
 {
        struct wpa_sm *sm = eloop_ctx;
-       wpa_printf(MSG_DEBUG, "WPA: Request PTK rekeying");
+       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Request PTK rekeying");
        wpa_sm_key_request(sm, 0, 1);
 }
 
@@ -499,7 +515,8 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
        const u8 *key_rsc;
        u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
-       wpa_printf(MSG_DEBUG, "WPA: Installing PTK to the driver.");
+       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+               "WPA: Installing PTK to the driver");
 
        switch (sm->pairwise_cipher) {
        case WPA_CIPHER_CCMP:
@@ -513,12 +530,13 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
                rsclen = 6;
                break;
        case WPA_CIPHER_NONE:
-               wpa_printf(MSG_DEBUG, "WPA: Pairwise Cipher Suite: "
-                          "NONE - do not use pairwise keys");
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Pairwise Cipher "
+                       "Suite: NONE - do not use pairwise keys");
                return 0;
        default:
-               wpa_printf(MSG_WARNING, "WPA: Unsupported pairwise cipher %d",
-                          sm->pairwise_cipher);
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "WPA: Unsupported pairwise cipher %d",
+                       sm->pairwise_cipher);
                return -1;
        }
 
@@ -531,9 +549,10 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
 
        if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
                           (u8 *) sm->ptk.tk1, keylen) < 0) {
-               wpa_printf(MSG_WARNING, "WPA: Failed to set PTK to the "
-                          "driver (alg=%d keylen=%d bssid=" MACSTR ")",
-                          alg, keylen, MAC2STR(sm->bssid));
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "WPA: Failed to set PTK to the "
+                       "driver (alg=%d keylen=%d bssid=" MACSTR ")",
+                       alg, keylen, MAC2STR(sm->bssid));
                return -1;
        }
 
@@ -547,7 +566,8 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
 }
 
 
-static int wpa_supplicant_check_group_cipher(int group_cipher,
+static int wpa_supplicant_check_group_cipher(struct wpa_sm *sm,
+                                            int group_cipher,
                                             int keylen, int maxkeylen,
                                             int *key_rsc_len,
                                             enum wpa_alg *alg)
@@ -588,15 +608,16 @@ static int wpa_supplicant_check_group_cipher(int group_cipher,
                *alg = WPA_ALG_WEP;
                break;
        default:
-               wpa_printf(MSG_WARNING, "WPA: Unsupported Group Cipher %d",
-                          group_cipher);
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "WPA: Unsupported Group Cipher %d",
+                       group_cipher);
                return -1;
        }
 
        if (ret < 0 ) {
-               wpa_printf(MSG_WARNING, "WPA: Unsupported %s Group Cipher key "
-                          "length %d (%d).",
-                          wpa_cipher_txt(group_cipher), keylen, maxkeylen);
+               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 ret;
@@ -619,9 +640,9 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
        u8 gtk_buf[32];
 
        wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len);
-       wpa_printf(MSG_DEBUG, "WPA: Installing GTK to the driver "
-                  "(keyidx=%d tx=%d len=%d).", gd->keyidx, gd->tx,
-                  gd->gtk_len);
+       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+               "WPA: Installing GTK to the driver (keyidx=%d tx=%d len=%d)",
+               gd->keyidx, gd->tx, gd->gtk_len);
        wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, gd->key_rsc_len);
        if (sm->group_cipher == WPA_CIPHER_TKIP) {
                /* Swap Tx/Rx keys for Michael MIC */
@@ -631,21 +652,21 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
                _gtk = gtk_buf;
        }
        if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
-               if (wpa_sm_set_key(sm, gd->alg,
-                                  (u8 *) "\xff\xff\xff\xff\xff\xff",
+               if (wpa_sm_set_key(sm, gd->alg, NULL,
                                   gd->keyidx, 1, key_rsc, gd->key_rsc_len,
                                   _gtk, gd->gtk_len) < 0) {
-                       wpa_printf(MSG_WARNING, "WPA: Failed to set "
-                                  "GTK to the driver (Group only).");
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "WPA: Failed to set GTK to the driver "
+                               "(Group only)");
                        return -1;
                }
-       } else if (wpa_sm_set_key(sm, gd->alg,
-                                 (u8 *) "\xff\xff\xff\xff\xff\xff",
+       } else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr,
                                  gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len,
                                  _gtk, gd->gtk_len) < 0) {
-               wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to "
-                          "the driver (alg=%d keylen=%d keyidx=%d)",
-                          gd->alg, gd->gtk_len, gd->keyidx);
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "WPA: Failed to set GTK to "
+                       "the driver (alg=%d keylen=%d keyidx=%d)",
+                       gd->alg, gd->gtk_len, gd->keyidx);
                return -1;
        }
 
@@ -662,8 +683,9 @@ static int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm,
                 * doing Group Key only APs) and without this workaround, the
                 * data connection does not work because wpa_supplicant
                 * configured non-zero keyidx to be used for unicast. */
-               wpa_printf(MSG_INFO, "WPA: Tx bit set for GTK, but pairwise "
-                          "keys are used - ignore Tx bit");
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "WPA: Tx bit set for GTK, but pairwise "
+                       "keys are used - ignore Tx bit");
                return 0;
        }
        return tx;
@@ -702,11 +724,12 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
        os_memcpy(gd.gtk, gtk, gtk_len);
        gd.gtk_len = gtk_len;
 
-       if (wpa_supplicant_check_group_cipher(sm->group_cipher,
+       if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
                                              gtk_len, gtk_len,
                                              &gd.key_rsc_len, &gd.alg) ||
            wpa_supplicant_install_gtk(sm, &gd, key->key_rsc)) {
-               wpa_printf(MSG_DEBUG, "RSN: Failed to install GTK");
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "RSN: Failed to install GTK");
                return -1;
        }
 
@@ -733,22 +756,21 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
                        return -1;
                igtk = (const struct wpa_igtk_kde *) ie->igtk;
                keyidx = WPA_GET_LE16(igtk->keyid);
-               wpa_printf(MSG_DEBUG, "WPA: IGTK keyid %d "
-                          "pn %02x%02x%02x%02x%02x%02x",
-                          keyidx, MAC2STR(igtk->pn));
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: IGTK keyid %d "
+                       "pn %02x%02x%02x%02x%02x%02x",
+                       keyidx, MAC2STR(igtk->pn));
                wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK",
                                igtk->igtk, WPA_IGTK_LEN);
                if (keyidx > 4095) {
-                       wpa_printf(MSG_WARNING, "WPA: Invalid IGTK KeyID %d",
-                                  keyidx);
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "WPA: Invalid IGTK KeyID %d", keyidx);
                        return -1;
                }
-               if (wpa_sm_set_key(sm, WPA_ALG_IGTK,
-                                  (u8 *) "\xff\xff\xff\xff\xff\xff",
+               if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr,
                                   keyidx, 0, igtk->pn, sizeof(igtk->pn),
                                   igtk->igtk, WPA_IGTK_LEN) < 0) {
-                       wpa_printf(MSG_WARNING, "WPA: Failed to configure IGTK"
-                                  " to the driver");
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "WPA: Failed to configure IGTK to the driver");
                        return -1;
                }
        }
@@ -774,8 +796,8 @@ static void wpa_report_ie_mismatch(struct wpa_sm *sm,
        }
        if (wpa_ie) {
                if (!sm->ap_wpa_ie) {
-                       wpa_printf(MSG_INFO, "WPA: No WPA IE in "
-                                  "Beacon/ProbeResp");
+                       wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                               "WPA: No WPA IE in Beacon/ProbeResp");
                }
                wpa_hexdump(MSG_INFO, "WPA: WPA IE in 3/4 msg",
                            wpa_ie, wpa_ie_len);
@@ -787,8 +809,8 @@ static void wpa_report_ie_mismatch(struct wpa_sm *sm,
        }
        if (rsn_ie) {
                if (!sm->ap_rsn_ie) {
-                       wpa_printf(MSG_INFO, "WPA: No RSN IE in "
-                                  "Beacon/ProbeResp");
+                       wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                               "WPA: No RSN IE in Beacon/ProbeResp");
                }
                wpa_hexdump(MSG_INFO, "WPA: RSN IE in 3/4 msg",
                            rsn_ie, rsn_ie_len);
@@ -811,15 +833,15 @@ static int ft_validate_mdie(struct wpa_sm *sm,
        if (ie->mdie == NULL || ie->mdie_len < 2 + sizeof(*mdie) ||
            os_memcmp(mdie->mobility_domain, sm->mobility_domain,
                      MOBILITY_DOMAIN_ID_LEN) != 0) {
-               wpa_printf(MSG_DEBUG, "FT: MDIE in msg 3/4 did not "
-                          "match with the current mobility domain");
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: MDIE in msg 3/4 did "
+                       "not match with the current mobility domain");
                return -1;
        }
 
        if (assoc_resp_mdie &&
            (assoc_resp_mdie[1] != ie->mdie[1] ||
             os_memcmp(assoc_resp_mdie, ie->mdie, 2 + ie->mdie[1]) != 0)) {
-               wpa_printf(MSG_DEBUG, "FT: MDIE mismatch");
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: MDIE mismatch");
                wpa_hexdump(MSG_DEBUG, "FT: MDIE in EAPOL-Key msg 3/4",
                            ie->mdie, 2 + ie->mdie[1]);
                wpa_hexdump(MSG_DEBUG, "FT: MDIE in (Re)Association Response",
@@ -837,7 +859,8 @@ static int ft_validate_ftie(struct wpa_sm *sm,
                            const u8 *assoc_resp_ftie)
 {
        if (ie->ftie == NULL) {
-               wpa_printf(MSG_DEBUG, "FT: No FTIE in EAPOL-Key msg 3/4");
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "FT: No FTIE in EAPOL-Key msg 3/4");
                return -1;
        }
 
@@ -846,7 +869,7 @@ static int ft_validate_ftie(struct wpa_sm *sm,
 
        if (assoc_resp_ftie[1] != ie->ftie[1] ||
            os_memcmp(assoc_resp_ftie, ie->ftie, 2 + ie->ftie[1]) != 0) {
-               wpa_printf(MSG_DEBUG, "FT: FTIE mismatch");
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: FTIE mismatch");
                wpa_hexdump(MSG_DEBUG, "FT: FTIE in EAPOL-Key msg 3/4",
                            ie->ftie, 2 + ie->ftie[1]);
                wpa_hexdump(MSG_DEBUG, "FT: FTIE in (Re)Association Response",
@@ -873,14 +896,15 @@ static int ft_validate_rsnie(struct wpa_sm *sm,
         */
        if (wpa_parse_wpa_ie_rsn(ie->rsn_ie, ie->rsn_ie_len, &rsn) < 0 ||
            rsn.num_pmkid != 1 || rsn.pmkid == NULL) {
-               wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in "
-                          "FT 4-way handshake message 3/4");
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: No PMKR1Name in "
+                       "FT 4-way handshake message 3/4");
                return -1;
        }
 
        if (os_memcmp(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) {
-               wpa_printf(MSG_DEBUG, "FT: PMKR1Name mismatch in "
-                          "FT 4-way handshake message 3/4");
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "FT: PMKR1Name mismatch in "
+                       "FT 4-way handshake message 3/4");
                wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Authenticator",
                            rsn.pmkid, WPA_PMK_NAME_LEN);
                wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name",
@@ -932,14 +956,17 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
                                      struct wpa_eapol_ie_parse *ie)
 {
        if (sm->ap_wpa_ie == NULL && sm->ap_rsn_ie == NULL) {
-               wpa_printf(MSG_DEBUG, "WPA: No WPA/RSN IE for this AP known. "
-                          "Trying to get from scan results");
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "WPA: No WPA/RSN IE for this AP known. "
+                       "Trying to get from scan results");
                if (wpa_sm_get_beacon_ie(sm) < 0) {
-                       wpa_printf(MSG_WARNING, "WPA: Could not find AP from "
-                                  "the scan results");
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "WPA: Could not find AP from "
+                               "the scan results");
                } else {
-                       wpa_printf(MSG_DEBUG, "WPA: Found the current AP from "
-                                  "updated scan results");
+                       wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+                               "WPA: Found the current AP from "
+                               "updated scan results");
                }
        }
 
@@ -1034,7 +1061,7 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
        if (kde)
                os_memcpy(reply + 1, kde, kde_len);
 
-       wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
+       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
        wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
                           rbuf, rlen, reply->key_mic);
 
@@ -1051,29 +1078,32 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
        struct wpa_eapol_ie_parse ie;
 
        wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
-       wpa_printf(MSG_DEBUG, "WPA: RX message 3 of 4-Way Handshake from "
-                  MACSTR " (ver=%d)", MAC2STR(sm->bssid), ver);
+       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 3 of 4-Way "
+               "Handshake from " MACSTR " (ver=%d)", MAC2STR(sm->bssid), ver);
 
        key_info = WPA_GET_BE16(key->key_info);
 
        pos = (const u8 *) (key + 1);
        len = WPA_GET_BE16(key->key_data_length);
        wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len);
-       wpa_supplicant_parse_ies(pos, len, &ie);
+       if (wpa_supplicant_parse_ies(pos, len, &ie) < 0)
+               goto failed;
        if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
-               wpa_printf(MSG_WARNING, "WPA: GTK IE in unencrypted key data");
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "WPA: GTK IE in unencrypted key data");
                goto failed;
        }
 #ifdef CONFIG_IEEE80211W
        if (ie.igtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
-               wpa_printf(MSG_WARNING, "WPA: IGTK KDE in unencrypted key "
-                          "data");
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "WPA: IGTK KDE in unencrypted key data");
                goto failed;
        }
 
        if (ie.igtk && ie.igtk_len != sizeof(struct wpa_igtk_kde)) {
-               wpa_printf(MSG_WARNING, "WPA: Invalid IGTK KDE length %lu",
-                          (unsigned long) ie.igtk_len);
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "WPA: Invalid IGTK KDE length %lu",
+                       (unsigned long) ie.igtk_len);
                goto failed;
        }
 #endif /* CONFIG_IEEE80211W */
@@ -1082,9 +1112,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
                goto failed;
 
        if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
-               wpa_printf(MSG_WARNING, "WPA: ANonce from message 1 of 4-Way "
-                          "Handshake differs from 3 of 4-Way Handshake - drop"
-                          " packet (src=" MACSTR ")", MAC2STR(sm->bssid));
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "WPA: ANonce from message 1 of 4-Way Handshake "
+                       "differs from 3 of 4-Way Handshake - drop packet (src="
+                       MACSTR ")", MAC2STR(sm->bssid));
                goto failed;
        }
 
@@ -1092,17 +1123,17 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
        switch (sm->pairwise_cipher) {
        case WPA_CIPHER_CCMP:
                if (keylen != 16) {
-                       wpa_printf(MSG_WARNING, "WPA: Invalid CCMP key length "
-                                  "%d (src=" MACSTR ")",
-                                  keylen, MAC2STR(sm->bssid));
+                       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_printf(MSG_WARNING, "WPA: Invalid TKIP key length "
-                                  "%d (src=" MACSTR ")",
-                                  keylen, MAC2STR(sm->bssid));
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "WPA: Invalid TKIP key length %d (src=" MACSTR
+                               ")", keylen, MAC2STR(sm->bssid));
                        goto failed;
                }
                break;
@@ -1134,15 +1165,19 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
        if (ie.gtk &&
            wpa_supplicant_pairwise_gtk(sm, key,
                                        ie.gtk, ie.gtk_len, key_info) < 0) {
-               wpa_printf(MSG_INFO, "RSN: Failed to configure GTK");
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "RSN: Failed to configure GTK");
                goto failed;
        }
 
        if (ieee80211w_set_keys(sm, &ie) < 0) {
-               wpa_printf(MSG_INFO, "RSN: Failed to configure IGTK");
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "RSN: Failed to configure IGTK");
                goto failed;
        }
 
+       wpa_sm_set_rekey_offload(sm);
+
        return;
 
 failed:
@@ -1160,18 +1195,21 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
        struct wpa_eapol_ie_parse ie;
 
        wpa_hexdump(MSG_DEBUG, "RSN: msg 1/2 key data", keydata, keydatalen);
-       wpa_supplicant_parse_ies(keydata, keydatalen, &ie);
+       if (wpa_supplicant_parse_ies(keydata, keydatalen, &ie) < 0)
+               return -1;
        if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
-               wpa_printf(MSG_WARNING, "WPA: GTK IE in unencrypted key data");
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "WPA: GTK IE in unencrypted key data");
                return -1;
        }
        if (ie.gtk == NULL) {
-               wpa_printf(MSG_INFO, "WPA: No GTK IE in Group Key msg 1/2");
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "WPA: No GTK IE in Group Key msg 1/2");
                return -1;
        }
        maxkeylen = gd->gtk_len = ie.gtk_len - 2;
 
-       if (wpa_supplicant_check_group_cipher(sm->group_cipher,
+       if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
                                              gd->gtk_len, maxkeylen,
                                              &gd->key_rsc_len, &gd->alg))
                return -1;
@@ -1182,14 +1220,16 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
        gd->tx = wpa_supplicant_gtk_tx_bit_workaround(sm,
                                                      !!(ie.gtk[0] & BIT(2)));
        if (ie.gtk_len - 2 > sizeof(gd->gtk)) {
-               wpa_printf(MSG_INFO, "RSN: Too long GTK in GTK IE "
-                          "(len=%lu)", (unsigned long) ie.gtk_len - 2);
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "RSN: Too long GTK in GTK IE (len=%lu)",
+                       (unsigned long) ie.gtk_len - 2);
                return -1;
        }
        os_memcpy(gd->gtk, ie.gtk + 2, ie.gtk_len - 2);
 
        if (ieee80211w_set_keys(sm, &ie) < 0)
-               wpa_printf(MSG_INFO, "RSN: Failed to configure IGTK");
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "RSN: Failed to configure IGTK");
 
        return 0;
 }
@@ -1207,22 +1247,23 @@ static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
        gd->gtk_len = WPA_GET_BE16(key->key_length);
        maxkeylen = keydatalen;
        if (keydatalen > extra_len) {
-               wpa_printf(MSG_INFO, "WPA: Truncated EAPOL-Key packet:"
-                          " key_data_length=%lu > extra_len=%lu",
-                          (unsigned long) keydatalen,
-                          (unsigned long) extra_len);
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "WPA: Truncated EAPOL-Key packet: "
+                       "key_data_length=%lu > extra_len=%lu",
+                       (unsigned long) keydatalen, (unsigned long) extra_len);
                return -1;
        }
        if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
                if (maxkeylen < 8) {
-                       wpa_printf(MSG_INFO, "WPA: Too short maxkeylen (%lu)",
-                                  (unsigned long) maxkeylen);
+                       wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                               "WPA: Too short maxkeylen (%lu)",
+                               (unsigned long) maxkeylen);
                        return -1;
                }
                maxkeylen -= 8;
        }
 
-       if (wpa_supplicant_check_group_cipher(sm->group_cipher,
+       if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
                                              gd->gtk_len, maxkeylen,
                                              &gd->key_rsc_len, &gd->alg))
                return -1;
@@ -1233,38 +1274,42 @@ static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
                os_memcpy(ek, key->key_iv, 16);
                os_memcpy(ek + 16, sm->ptk.kek, 16);
                if (keydatalen > sizeof(gd->gtk)) {
-                       wpa_printf(MSG_WARNING, "WPA: RC4 key data "
-                                  "too long (%lu)",
-                                  (unsigned long) keydatalen);
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "WPA: RC4 key data too long (%lu)",
+                               (unsigned long) keydatalen);
                        return -1;
                }
                os_memcpy(gd->gtk, key + 1, keydatalen);
                if (rc4_skip(ek, 32, 256, gd->gtk, keydatalen)) {
-                       wpa_printf(MSG_ERROR, "WPA: RC4 failed");
+                       wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+                               "WPA: RC4 failed");
                        return -1;
                }
        } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
                if (keydatalen % 8) {
-                       wpa_printf(MSG_WARNING, "WPA: Unsupported AES-WRAP "
-                                  "len %lu", (unsigned long) keydatalen);
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "WPA: Unsupported AES-WRAP len %lu",
+                               (unsigned long) keydatalen);
                        return -1;
                }
                if (maxkeylen > sizeof(gd->gtk)) {
-                       wpa_printf(MSG_WARNING, "WPA: AES-WRAP key data "
-                                  "too long (keydatalen=%lu maxkeylen=%lu)",
-                                  (unsigned long) keydatalen,
-                                  (unsigned long) maxkeylen);
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "WPA: AES-WRAP key data "
+                               "too long (keydatalen=%lu maxkeylen=%lu)",
+                               (unsigned long) keydatalen,
+                               (unsigned long) maxkeylen);
                        return -1;
                }
                if (aes_unwrap(sm->ptk.kek, maxkeylen / 8,
                               (const u8 *) (key + 1), gd->gtk)) {
-                       wpa_printf(MSG_WARNING, "WPA: AES unwrap "
-                                  "failed - could not decrypt GTK");
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "WPA: AES unwrap failed - could not decrypt "
+                               "GTK");
                        return -1;
                }
        } else {
-               wpa_printf(MSG_WARNING, "WPA: Unsupported key_info type %d",
-                          ver);
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "WPA: Unsupported key_info type %d", ver);
                return -1;
        }
        gd->tx = wpa_supplicant_gtk_tx_bit_workaround(
@@ -1300,7 +1345,7 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
 
        WPA_PUT_BE16(reply->key_data_length, 0);
 
-       wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
+       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
        wpa_eapol_key_send(sm, sm->ptk.kck, ver, sm->bssid, ETH_P_EAPOL,
                           rbuf, rlen, reply->key_mic);
 
@@ -1320,8 +1365,8 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
        os_memset(&gd, 0, sizeof(gd));
 
        rekey = wpa_sm_get_state(sm) == WPA_COMPLETED;
-       wpa_printf(MSG_DEBUG, "WPA: RX message 1 of Group Key Handshake from "
-                  MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
+       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of Group Key "
+               "Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
 
        key_info = WPA_GET_BE16(key->key_info);
        keydatalen = WPA_GET_BE16(key->key_data_length);
@@ -1352,6 +1397,8 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
                        MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher));
                wpa_sm_cancel_auth_timeout(sm);
                wpa_sm_set_state(sm, WPA_COMPLETED);
+
+               wpa_sm_set_rekey_offload(sm);
        } else {
                wpa_supplicant_key_neg_complete(sm, sm->bssid,
                                                key_info &
@@ -1378,8 +1425,9 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
                wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len,
                                  key->key_mic);
                if (os_memcmp(mic, key->key_mic, 16) != 0) {
-                       wpa_printf(MSG_WARNING, "WPA: Invalid EAPOL-Key MIC "
-                                  "when using TPTK - ignoring TPTK");
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "WPA: Invalid EAPOL-Key MIC "
+                               "when using TPTK - ignoring TPTK");
                } else {
                        ok = 1;
                        sm->tptk_set = 0;
@@ -1393,16 +1441,18 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
                wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len,
                                  key->key_mic);
                if (os_memcmp(mic, key->key_mic, 16) != 0) {
-                       wpa_printf(MSG_WARNING, "WPA: Invalid EAPOL-Key MIC "
-                                  "- dropping packet");
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "WPA: Invalid EAPOL-Key MIC - "
+                               "dropping packet");
                        return -1;
                }
                ok = 1;
        }
 
        if (!ok) {
-               wpa_printf(MSG_WARNING, "WPA: Could not verify EAPOL-Key MIC "
-                          "- dropping packet");
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "WPA: Could not verify EAPOL-Key MIC - "
+                       "dropping packet");
                return -1;
        }
 
@@ -1422,8 +1472,9 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
        wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data",
                    (u8 *) (key + 1), keydatalen);
        if (!sm->ptk_set) {
-               wpa_printf(MSG_WARNING, "WPA: PTK not available, "
-                          "cannot decrypt EAPOL-Key key data.");
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "WPA: PTK not available, cannot decrypt EAPOL-Key Key "
+                       "Data");
                return -1;
        }
 
@@ -1434,37 +1485,40 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
                os_memcpy(ek, key->key_iv, 16);
                os_memcpy(ek + 16, sm->ptk.kek, 16);
                if (rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen)) {
-                       wpa_printf(MSG_ERROR, "WPA: RC4 failed");
+                       wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+                               "WPA: RC4 failed");
                        return -1;
                }
        } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
                   ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
                u8 *buf;
                if (keydatalen % 8) {
-                       wpa_printf(MSG_WARNING, "WPA: Unsupported "
-                                  "AES-WRAP len %d", keydatalen);
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "WPA: Unsupported AES-WRAP len %d",
+                               keydatalen);
                        return -1;
                }
                keydatalen -= 8; /* AES-WRAP adds 8 bytes */
                buf = os_malloc(keydatalen);
                if (buf == NULL) {
-                       wpa_printf(MSG_WARNING, "WPA: No memory for "
-                                  "AES-UNWRAP buffer");
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "WPA: No memory for AES-UNWRAP buffer");
                        return -1;
                }
                if (aes_unwrap(sm->ptk.kek, keydatalen / 8,
                               (u8 *) (key + 1), buf)) {
                        os_free(buf);
-                       wpa_printf(MSG_WARNING, "WPA: AES unwrap failed - "
-                                  "could not decrypt EAPOL-Key key data");
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "WPA: AES unwrap failed - "
+                               "could not decrypt EAPOL-Key key data");
                        return -1;
                }
                os_memcpy(key + 1, buf, keydatalen);
                os_free(buf);
                WPA_PUT_BE16(key->key_data_length, keydatalen);
        } else {
-               wpa_printf(MSG_WARNING, "WPA: Unsupported key_info type %d",
-                          ver);
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "WPA: Unsupported key_info type %d", ver);
                return -1;
        }
        wpa_hexdump_key(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data",
@@ -1480,35 +1534,38 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
 void wpa_sm_aborted_cached(struct wpa_sm *sm)
 {
        if (sm && sm->cur_pmksa) {
-               wpa_printf(MSG_DEBUG, "RSN: Cancelling PMKSA caching attempt");
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "RSN: Cancelling PMKSA caching attempt");
                sm->cur_pmksa = NULL;
        }
 }
 
 
-static void wpa_eapol_key_dump(const struct wpa_eapol_key *key)
+static void wpa_eapol_key_dump(struct wpa_sm *sm,
+                              const struct wpa_eapol_key *key)
 {
 #ifndef CONFIG_NO_STDOUT_DEBUG
        u16 key_info = WPA_GET_BE16(key->key_info);
 
-       wpa_printf(MSG_DEBUG, "  EAPOL-Key type=%d", key->type);
-       wpa_printf(MSG_DEBUG, "  key_info 0x%x (ver=%d keyidx=%d rsvd=%d %s"
-                  "%s%s%s%s%s%s%s)",
-                  key_info, key_info & WPA_KEY_INFO_TYPE_MASK,
-                  (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
-                  WPA_KEY_INFO_KEY_INDEX_SHIFT,
-                  (key_info & (BIT(13) | BIT(14) | BIT(15))) >> 13,
-                  key_info & WPA_KEY_INFO_KEY_TYPE ? "Pairwise" : "Group",
-                  key_info & WPA_KEY_INFO_INSTALL ? " Install" : "",
-                  key_info & WPA_KEY_INFO_ACK ? " Ack" : "",
-                  key_info & WPA_KEY_INFO_MIC ? " MIC" : "",
-                  key_info & WPA_KEY_INFO_SECURE ? " Secure" : "",
-                  key_info & WPA_KEY_INFO_ERROR ? " Error" : "",
-                  key_info & WPA_KEY_INFO_REQUEST ? " Request" : "",
-                  key_info & WPA_KEY_INFO_ENCR_KEY_DATA ? " Encr" : "");
-       wpa_printf(MSG_DEBUG, "  key_length=%u key_data_length=%u",
-                  WPA_GET_BE16(key->key_length),
-                  WPA_GET_BE16(key->key_data_length));
+       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "  EAPOL-Key type=%d", key->type);
+       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+               "  key_info 0x%x (ver=%d keyidx=%d rsvd=%d %s%s%s%s%s%s%s%s)",
+               key_info, key_info & WPA_KEY_INFO_TYPE_MASK,
+               (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
+               WPA_KEY_INFO_KEY_INDEX_SHIFT,
+               (key_info & (BIT(13) | BIT(14) | BIT(15))) >> 13,
+               key_info & WPA_KEY_INFO_KEY_TYPE ? "Pairwise" : "Group",
+               key_info & WPA_KEY_INFO_INSTALL ? " Install" : "",
+               key_info & WPA_KEY_INFO_ACK ? " Ack" : "",
+               key_info & WPA_KEY_INFO_MIC ? " MIC" : "",
+               key_info & WPA_KEY_INFO_SECURE ? " Secure" : "",
+               key_info & WPA_KEY_INFO_ERROR ? " Error" : "",
+               key_info & WPA_KEY_INFO_REQUEST ? " Request" : "",
+               key_info & WPA_KEY_INFO_ENCR_KEY_DATA ? " Encr" : "");
+       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+               "  key_length=%u key_data_length=%u",
+               WPA_GET_BE16(key->key_length),
+               WPA_GET_BE16(key->key_data_length));
        wpa_hexdump(MSG_DEBUG, "  replay_counter",
                    key->replay_counter, WPA_REPLAY_COUNTER_LEN);
        wpa_hexdump(MSG_DEBUG, "  key_nonce", key->key_nonce, WPA_NONCE_LEN);
@@ -1552,10 +1609,11 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
 #endif /* CONFIG_IEEE80211R */
 
        if (len < sizeof(*hdr) + sizeof(*key)) {
-               wpa_printf(MSG_DEBUG, "WPA: EAPOL frame too short to be a WPA "
-                          "EAPOL-Key (len %lu, expecting at least %lu)",
-                          (unsigned long) len,
-                          (unsigned long) sizeof(*hdr) + sizeof(*key));
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "WPA: EAPOL frame too short to be a WPA "
+                       "EAPOL-Key (len %lu, expecting at least %lu)",
+                       (unsigned long) len,
+                       (unsigned long) sizeof(*hdr) + sizeof(*key));
                return 0;
        }
 
@@ -1568,40 +1626,45 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
        key = (struct wpa_eapol_key *) (hdr + 1);
        plen = be_to_host16(hdr->length);
        data_len = plen + sizeof(*hdr);
-       wpa_printf(MSG_DEBUG, "IEEE 802.1X RX: version=%d type=%d length=%lu",
-                  hdr->version, hdr->type, (unsigned long) plen);
+       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+               "IEEE 802.1X RX: version=%d type=%d length=%lu",
+               hdr->version, hdr->type, (unsigned long) plen);
 
        if (hdr->version < EAPOL_VERSION) {
                /* TODO: backwards compatibility */
        }
        if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) {
-               wpa_printf(MSG_DEBUG, "WPA: EAPOL frame (type %u) discarded, "
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "WPA: EAPOL frame (type %u) discarded, "
                        "not a Key frame", hdr->type);
                ret = 0;
                goto out;
        }
        if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) {
-               wpa_printf(MSG_DEBUG, "WPA: EAPOL frame payload size %lu "
-                          "invalid (frame size %lu)",
-                          (unsigned long) plen, (unsigned long) len);
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "WPA: EAPOL frame payload size %lu "
+                       "invalid (frame size %lu)",
+                       (unsigned long) plen, (unsigned long) len);
                ret = 0;
                goto out;
        }
 
        if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN)
        {
-               wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key type (%d) unknown, "
-                          "discarded", key->type);
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "WPA: EAPOL-Key type (%d) unknown, discarded",
+                       key->type);
                ret = 0;
                goto out;
        }
-       wpa_eapol_key_dump(key);
+       wpa_eapol_key_dump(sm, key);
 
        eapol_sm_notify_lower_layer_success(sm->eapol, 0);
        wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", tmp, len);
        if (data_len < len) {
-               wpa_printf(MSG_DEBUG, "WPA: ignoring %lu bytes after the IEEE "
-                          "802.1X data", (unsigned long) len - data_len);
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "WPA: ignoring %lu bytes after the IEEE 802.1X data",
+                       (unsigned long) len - data_len);
        }
        key_info = WPA_GET_BE16(key->key_info);
        ver = key_info & WPA_KEY_INFO_TYPE_MASK;
@@ -1610,8 +1673,9 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
            ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
 #endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
            ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
-               wpa_printf(MSG_INFO, "WPA: Unsupported EAPOL-Key descriptor "
-                          "version %d.", ver);
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "WPA: Unsupported EAPOL-Key descriptor version %d",
+                       ver);
                goto out;
        }
 
@@ -1619,8 +1683,8 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
        if (wpa_key_mgmt_ft(sm->key_mgmt)) {
                /* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */
                if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
-                       wpa_printf(MSG_INFO, "FT: AP did not use "
-                                  "AES-128-CMAC.");
+                       wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                               "FT: AP did not use AES-128-CMAC");
                        goto out;
                }
        } else
@@ -1628,25 +1692,27 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
 #ifdef CONFIG_IEEE80211W
        if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
                if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
-                       wpa_printf(MSG_INFO, "WPA: AP did not use the "
-                                  "negotiated AES-128-CMAC.");
+                       wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                               "WPA: AP did not use the "
+                               "negotiated AES-128-CMAC");
                        goto out;
                }
        } else
 #endif /* CONFIG_IEEE80211W */
        if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
            ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
-               wpa_printf(MSG_INFO, "WPA: CCMP is used, but EAPOL-Key "
-                          "descriptor version (%d) is not 2.", ver);
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "WPA: CCMP is used, but EAPOL-Key "
+                       "descriptor version (%d) is not 2", ver);
                if (sm->group_cipher != WPA_CIPHER_CCMP &&
                    !(key_info & WPA_KEY_INFO_KEY_TYPE)) {
                        /* Earlier versions of IEEE 802.11i did not explicitly
                         * require version 2 descriptor for all EAPOL-Key
                         * packets, so allow group keys to use version 1 if
                         * CCMP is not used for them. */
-                       wpa_printf(MSG_INFO, "WPA: Backwards compatibility: "
-                                  "allow invalid version for non-CCMP group "
-                                  "keys");
+                       wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                               "WPA: Backwards compatibility: allow invalid "
+                               "version for non-CCMP group keys");
                } else
                        goto out;
        }
@@ -1661,9 +1727,9 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
                if (!peerkey->initiator && peerkey->replay_counter_set &&
                    os_memcmp(key->replay_counter, peerkey->replay_counter,
                              WPA_REPLAY_COUNTER_LEN) <= 0) {
-                       wpa_printf(MSG_WARNING, "RSN: EAPOL-Key Replay "
-                                  "Counter did not increase (STK) - dropping "
-                                  "packet");
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "RSN: EAPOL-Key Replay Counter did not "
+                               "increase (STK) - dropping packet");
                        goto out;
                } else if (peerkey->initiator) {
                        u8 _tmp[WPA_REPLAY_COUNTER_LEN];
@@ -1672,16 +1738,18 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
                        inc_byte_array(_tmp, WPA_REPLAY_COUNTER_LEN);
                        if (os_memcmp(_tmp, peerkey->replay_counter,
                                      WPA_REPLAY_COUNTER_LEN) != 0) {
-                               wpa_printf(MSG_DEBUG, "RSN: EAPOL-Key Replay "
-                                          "Counter did not match (STK) - "
-                                          "dropping packet");
+                               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                                       "RSN: EAPOL-Key Replay "
+                                       "Counter did not match (STK) - "
+                                       "dropping packet");
                                goto out;
                        }
                }
        }
 
        if (peerkey && peerkey->initiator && (key_info & WPA_KEY_INFO_ACK)) {
-               wpa_printf(MSG_INFO, "RSN: Ack bit in key_info from STK peer");
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "RSN: Ack bit in key_info from STK peer");
                goto out;
        }
 #endif /* CONFIG_PEERKEY */
@@ -1689,8 +1757,9 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
        if (!peerkey && sm->rx_replay_counter_set &&
            os_memcmp(key->replay_counter, sm->rx_replay_counter,
                      WPA_REPLAY_COUNTER_LEN) <= 0) {
-               wpa_printf(MSG_WARNING, "WPA: EAPOL-Key Replay Counter did not"
-                          " increase - dropping packet");
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "WPA: EAPOL-Key Replay Counter did not increase - "
+                       "dropping packet");
                goto out;
        }
 
@@ -1699,13 +1768,14 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
            && (peerkey == NULL || !peerkey->initiator)
 #endif /* CONFIG_PEERKEY */
                ) {
-               wpa_printf(MSG_INFO, "WPA: No Ack bit in key_info");
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "WPA: No Ack bit in key_info");
                goto out;
        }
 
        if (key_info & WPA_KEY_INFO_REQUEST) {
-               wpa_printf(MSG_INFO, "WPA: EAPOL-Key with Request bit - "
-                          "dropped");
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "WPA: EAPOL-Key with Request bit - dropped");
                goto out;
        }
 
@@ -1739,8 +1809,9 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
 
        if (key_info & WPA_KEY_INFO_KEY_TYPE) {
                if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) {
-                       wpa_printf(MSG_WARNING, "WPA: Ignored EAPOL-Key "
-                                  "(Pairwise) with non-zero key index");
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "WPA: Ignored EAPOL-Key (Pairwise) with "
+                               "non-zero key index");
                        goto out;
                }
                if (peerkey) {
@@ -1764,8 +1835,9 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
                        wpa_supplicant_process_1_of_2(sm, src_addr, key,
                                                      extra_len, ver);
                } else {
-                       wpa_printf(MSG_WARNING, "WPA: EAPOL-Key (Group) "
-                                  "without Mic bit - dropped");
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "WPA: EAPOL-Key (Group) without Mic bit - "
+                               "dropped");
                }
        }
 
@@ -1940,7 +2012,8 @@ static void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
        if (sm->cur_pmksa == entry ||
            (sm->pmk_len == entry->pmk_len &&
             os_memcmp(sm->pmk, entry->pmk, sm->pmk_len) == 0)) {
-               wpa_printf(MSG_DEBUG, "RSN: removed current PMKSA entry");
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "RSN: removed current PMKSA entry");
                sm->cur_pmksa = NULL;
 
                if (replace) {
@@ -1982,8 +2055,8 @@ struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
 
        sm->pmksa = pmksa_cache_init(wpa_sm_pmksa_free_cb, sm, sm);
        if (sm->pmksa == NULL) {
-               wpa_printf(MSG_ERROR, "RSN: PMKSA cache initialization "
-                          "failed");
+               wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+                       "RSN: PMKSA cache initialization failed");
                os_free(sm);
                return NULL;
        }
@@ -2030,7 +2103,8 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
        if (sm == NULL)
                return;
 
-       wpa_printf(MSG_DEBUG, "WPA: Association event - clear replay counter");
+       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+               "WPA: Association event - clear replay counter");
        os_memcpy(sm->bssid, bssid, ETH_ALEN);
        os_memset(sm->rx_replay_counter, 0, WPA_REPLAY_COUNTER_LEN);
        sm->rx_replay_counter_set = 0;
@@ -2059,10 +2133,14 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
                 * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if
                 * this is not part of a Fast BSS Transition.
                 */
-               wpa_printf(MSG_DEBUG, "WPA: Clear old PTK");
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PTK");
                sm->ptk_set = 0;
                sm->tptk_set = 0;
        }
+
+#ifdef CONFIG_TDLS
+       wpa_tdls_assoc(sm);
+#endif /* CONFIG_TDLS */
 }
 
 
@@ -2078,6 +2156,9 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
        rsn_preauth_deinit(sm);
        if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE)
                sm->dot11RSNA4WayHandshakeFailures++;
+#ifdef CONFIG_TDLS
+       wpa_tdls_disassoc(sm);
+#endif /* CONFIG_TDLS */
 }
 
 
@@ -2191,8 +2272,6 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
                sm->ssid_len = 0;
                sm->wpa_ptk_rekey = 0;
        }
-       if (config == NULL || config->network_ctx != sm->network_ctx)
-               pmksa_cache_notify_reconfig(sm->pmksa);
 }
 
 
@@ -2430,7 +2509,8 @@ int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
 
        os_free(sm->assoc_wpa_ie);
        if (ie == NULL || len == 0) {
-               wpa_printf(MSG_DEBUG, "WPA: clearing own WPA/RSN IE");
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "WPA: clearing own WPA/RSN IE");
                sm->assoc_wpa_ie = NULL;
                sm->assoc_wpa_ie_len = 0;
        } else {
@@ -2464,7 +2544,8 @@ int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
 
        os_free(sm->ap_wpa_ie);
        if (ie == NULL || len == 0) {
-               wpa_printf(MSG_DEBUG, "WPA: clearing AP WPA IE");
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "WPA: clearing AP WPA IE");
                sm->ap_wpa_ie = NULL;
                sm->ap_wpa_ie_len = 0;
        } else {
@@ -2498,7 +2579,8 @@ int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
 
        os_free(sm->ap_rsn_ie);
        if (ie == NULL || len == 0) {
-               wpa_printf(MSG_DEBUG, "WPA: clearing AP RSN IE");
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "WPA: clearing AP RSN IE");
                sm->ap_rsn_ie = NULL;
                sm->ap_rsn_ie_len = 0;
        } else {
@@ -2526,9 +2608,12 @@ int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
  */
 int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data)
 {
-       if (sm == NULL || sm->assoc_wpa_ie == NULL) {
-               wpa_printf(MSG_DEBUG, "WPA: No WPA/RSN IE available from "
-                          "association info");
+       if (sm == NULL)
+               return -1;
+
+       if (sm->assoc_wpa_ie == NULL) {
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "WPA: No WPA/RSN IE available from association info");
                return -1;
        }
        if (wpa_parse_wpa_ie(sm->assoc_wpa_ie, sm->assoc_wpa_ie_len, data))
@@ -2549,7 +2634,7 @@ int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len)
 
 void wpa_sm_drop_sa(struct wpa_sm *sm)
 {
-       wpa_printf(MSG_DEBUG, "WPA: Clear old PMK and PTK");
+       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK");
        sm->ptk_set = 0;
        sm->tptk_set = 0;
        os_memset(sm->pmk, 0, sizeof(sm->pmk));
@@ -2564,3 +2649,17 @@ int wpa_sm_has_ptk(struct wpa_sm *sm)
                return 0;
        return sm->ptk_set;
 }
+
+
+void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
+{
+       os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN);
+}
+
+
+void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
+{
+#ifndef CONFIG_NO_WPA2
+       pmksa_cache_flush(sm->pmksa, network_ctx);
+#endif /* CONFIG_NO_WPA2 */
+}
index f1a5554..4c1750f 100644 (file)
@@ -55,6 +55,19 @@ struct wpa_sm_ctx {
        int (*send_ft_action)(void *ctx, u8 action, const u8 *target_ap,
                              const u8 *ies, size_t ies_len);
        int (*mark_authenticated)(void *ctx, const u8 *target_ap);
+#ifdef CONFIG_TDLS
+       int (*tdls_get_capa)(void *ctx, int *tdls_supported,
+                            int *tdls_ext_setup);
+       int (*send_tdls_mgmt)(void *ctx, const u8 *dst,
+                             u8 action_code, u8 dialog_token,
+                             u16 status_code, const u8 *buf, size_t len);
+       int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
+       int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add,
+                               u16 capability, const u8 *supp_rates,
+                               size_t supp_rates_len);
+#endif /* CONFIG_TDLS */
+       void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
+                                 const u8 *replay_ctr);
 };
 
 
@@ -126,6 +139,10 @@ int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len);
 void wpa_sm_drop_sa(struct wpa_sm *sm);
 int wpa_sm_has_ptk(struct wpa_sm *sm);
 
+void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr);
+
+void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx);
+
 #else /* CONFIG_NO_WPA */
 
 static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
@@ -271,6 +288,16 @@ static inline int wpa_sm_has_ptk(struct wpa_sm *sm)
        return 0;
 }
 
+static inline void wpa_sm_update_replay_ctr(struct wpa_sm *sm,
+                                           const u8 *replay_ctr)
+{
+}
+
+static inline void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm,
+                                           void *network_ctx)
+{
+}
+
 #endif /* CONFIG_NO_WPA */
 
 #ifdef CONFIG_PEERKEY
@@ -330,4 +357,19 @@ wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
 
 #endif /* CONFIG_IEEE80211R */
 
+
+/* tdls.c */
+void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len);
+void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len);
+int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr);
+int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr);
+int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
+int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
+int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr);
+int wpa_tdls_init(struct wpa_sm *sm);
+void wpa_tdls_deinit(struct wpa_sm *sm);
+void wpa_tdls_enable(struct wpa_sm *sm, int enabled);
+void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr);
+int wpa_tdls_is_external_setup(struct wpa_sm *sm);
+
 #endif /* WPA_H */
index 23063bc..dbf5996 100644 (file)
 
 #include "common.h"
 #include "crypto/aes_wrap.h"
+#include "crypto/random.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "wpa.h"
 #include "wpa_i.h"
-#include "wpa_ie.h"
 
 #ifdef CONFIG_IEEE80211R
 
-struct wpa_ft_ies {
-       const u8 *mdie;
-       size_t mdie_len;
-       const u8 *ftie;
-       size_t ftie_len;
-       const u8 *r1kh_id;
-       const u8 *gtk;
-       size_t gtk_len;
-       const u8 *r0kh_id;
-       size_t r0kh_id_len;
-       const u8 *rsn;
-       size_t rsn_len;
-       const u8 *rsn_pmkid;
-       const u8 *tie;
-       size_t tie_len;
-       const u8 *igtk;
-       size_t igtk_len;
-       const u8 *ric;
-       size_t ric_len;
-};
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
-                           struct wpa_ft_ies *parse);
-
-
 int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
                      const struct wpa_eapol_key *key,
                      struct wpa_ptk *ptk, size_t ptk_len)
@@ -346,155 +321,6 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
 }
 
 
-static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
-                            struct wpa_ft_ies *parse)
-{
-       const u8 *end, *pos;
-
-       parse->ftie = ie;
-       parse->ftie_len = ie_len;
-
-       pos = ie + sizeof(struct rsn_ftie);
-       end = ie + ie_len;
-
-       while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
-               switch (pos[0]) {
-               case FTIE_SUBELEM_R1KH_ID:
-                       if (pos[1] != FT_R1KH_ID_LEN) {
-                               wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
-                                          "length in FTIE: %d", pos[1]);
-                               return -1;
-                       }
-                       parse->r1kh_id = pos + 2;
-                       break;
-               case FTIE_SUBELEM_GTK:
-                       parse->gtk = pos + 2;
-                       parse->gtk_len = pos[1];
-                       break;
-               case FTIE_SUBELEM_R0KH_ID:
-                       if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
-                               wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
-                                          "length in FTIE: %d", pos[1]);
-                               return -1;
-                       }
-                       parse->r0kh_id = pos + 2;
-                       parse->r0kh_id_len = pos[1];
-                       break;
-#ifdef CONFIG_IEEE80211W
-               case FTIE_SUBELEM_IGTK:
-                       parse->igtk = pos + 2;
-                       parse->igtk_len = pos[1];
-                       break;
-#endif /* CONFIG_IEEE80211W */
-               }
-
-               pos += 2 + pos[1];
-       }
-
-       return 0;
-}
-
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
-                           struct wpa_ft_ies *parse)
-{
-       const u8 *end, *pos;
-       struct wpa_ie_data data;
-       int ret;
-       const struct rsn_ftie *ftie;
-       int prot_ie_count = 0;
-
-       os_memset(parse, 0, sizeof(*parse));
-       if (ies == NULL)
-               return 0;
-
-       pos = ies;
-       end = ies + ies_len;
-       while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
-               switch (pos[0]) {
-               case WLAN_EID_RSN:
-                       parse->rsn = pos + 2;
-                       parse->rsn_len = pos[1];
-                       ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
-                                                  parse->rsn_len + 2,
-                                                  &data);
-                       if (ret < 0) {
-                               wpa_printf(MSG_DEBUG, "FT: Failed to parse "
-                                          "RSN IE: %d", ret);
-                               return -1;
-                       }
-                       if (data.num_pmkid == 1 && data.pmkid)
-                               parse->rsn_pmkid = data.pmkid;
-                       break;
-               case WLAN_EID_MOBILITY_DOMAIN:
-                       parse->mdie = pos + 2;
-                       parse->mdie_len = pos[1];
-                       break;
-               case WLAN_EID_FAST_BSS_TRANSITION:
-                       if (pos[1] < sizeof(*ftie))
-                               return -1;
-                       ftie = (const struct rsn_ftie *) (pos + 2);
-                       prot_ie_count = ftie->mic_control[1];
-                       if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
-                               return -1;
-                       break;
-               case WLAN_EID_TIMEOUT_INTERVAL:
-                       parse->tie = pos + 2;
-                       parse->tie_len = pos[1];
-                       break;
-               case WLAN_EID_RIC_DATA:
-                       if (parse->ric == NULL)
-                               parse->ric = pos;
-               }
-
-               pos += 2 + pos[1];
-       }
-
-       if (prot_ie_count == 0)
-               return 0; /* no MIC */
-
-       /*
-        * Check that the protected IE count matches with IEs included in the
-        * frame.
-        */
-       if (parse->rsn)
-               prot_ie_count--;
-       if (parse->mdie)
-               prot_ie_count--;
-       if (parse->ftie)
-               prot_ie_count--;
-       if (parse->tie)
-               prot_ie_count--;
-       if (prot_ie_count < 0) {
-               wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
-                          "the protected IE count");
-               return -1;
-       }
-
-       if (prot_ie_count == 0 && parse->ric) {
-               wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
-                          "included in protected IE count");
-               return -1;
-       }
-
-       /* Determine the end of the RIC IE(s) */
-       pos = parse->ric;
-       while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
-              prot_ie_count) {
-               prot_ie_count--;
-               pos += 2 + pos[1];
-       }
-       parse->ric_len = pos - parse->ric;
-       if (prot_ie_count) {
-               wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
-                          "frame", (int) prot_ie_count);
-               return -1;
-       }
-
-       return 0;
-}
-
-
 static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
 {
        int keylen;
@@ -540,7 +366,7 @@ int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie)
        size_t ft_ies_len;
 
        /* Generate a new SNonce */
-       if (os_get_random(sm->snonce, WPA_NONCE_LEN)) {
+       if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) {
                wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce");
                return -1;
        }
@@ -795,9 +621,8 @@ 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 (wpa_sm_set_key(sm, alg, (u8 *) "\xff\xff\xff\xff\xff\xff",
-                          keyidx, 0, gtk_elem + 3, rsc_len, gtk, keylen) <
-           0) {
+       if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0,
+                          gtk_elem + 3, rsc_len, gtk, keylen) < 0) {
                wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
                           "driver.");
                return -1;
@@ -848,9 +673,8 @@ static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
 
        wpa_hexdump_key(MSG_DEBUG, "FT: IGTK from Reassoc Resp", igtk,
                        WPA_IGTK_LEN);
-       if (wpa_sm_set_key(sm, WPA_ALG_IGTK, (u8 *) "\xff\xff\xff\xff\xff\xff",
-                          keyidx, 0, igtk_elem + 2, 6, igtk, WPA_IGTK_LEN) <
-           0) {
+       if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, keyidx, 0,
+                          igtk_elem + 2, 6, igtk, WPA_IGTK_LEN) < 0) {
                wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the "
                           "driver.");
                return -1;
@@ -951,8 +775,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
        }
 
        count = 3;
-       if (parse.tie)
-               count++;
+       if (parse.ric)
+               count += ieee802_11_ie_count(parse.ric, parse.ric_len);
        if (ftie->mic_control[1] != count) {
                wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
                           "Control: received %u expected %u",
@@ -1020,7 +844,7 @@ int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
                   MAC2STR(target_ap));
 
        /* Generate a new SNonce */
-       if (os_get_random(sm->snonce, WPA_NONCE_LEN)) {
+       if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) {
                wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce");
                return -1;
        }
index 618c090..39124c4 100644 (file)
@@ -18,6 +18,7 @@
 #include "utils/list.h"
 
 struct wpa_peerkey;
+struct wpa_tdls_peer;
 struct wpa_eapol_key;
 
 /**
@@ -43,6 +44,7 @@ struct wpa_sm {
 
        struct l2_packet_data *l2_preauth;
        struct l2_packet_data *l2_preauth_br;
+       struct l2_packet_data *l2_tdls;
        u8 preauth_bssid[ETH_ALEN]; /* current RSN pre-auth peer or
                                     * 00:00:00:00:00:00 if no pre-auth is
                                     * in progress */
@@ -92,6 +94,20 @@ struct wpa_sm {
 #ifdef CONFIG_PEERKEY
        struct wpa_peerkey *peerkey;
 #endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_TDLS
+       struct wpa_tdls_peer *tdls;
+       int tdls_prohibited;
+       int tdls_disabled;
+
+       /* The driver supports TDLS */
+       int tdls_supported;
+
+       /*
+        * The driver requires explicit discovery/setup/teardown frames sent
+        * to it via tdls_mgmt.
+        */
+       int tdls_external_setup;
+#endif /* CONFIG_TDLS */
 
 #ifdef CONFIG_IEEE80211R
        u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
@@ -237,6 +253,57 @@ static inline int wpa_sm_mark_authenticated(struct wpa_sm *sm,
        return -1;
 }
 
+static inline void wpa_sm_set_rekey_offload(struct wpa_sm *sm)
+{
+       if (!sm->ctx->set_rekey_offload)
+               return;
+       sm->ctx->set_rekey_offload(sm->ctx->ctx, sm->ptk.kek,
+                                  sm->ptk.kck, sm->rx_replay_counter);
+}
+
+#ifdef CONFIG_TDLS
+static inline int wpa_sm_tdls_get_capa(struct wpa_sm *sm,
+                                      int *tdls_supported,
+                                      int *tdls_ext_setup)
+{
+       if (sm->ctx->tdls_get_capa)
+               return sm->ctx->tdls_get_capa(sm->ctx->ctx, tdls_supported,
+                                             tdls_ext_setup);
+       return -1;
+}
+
+static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst,
+                                       u8 action_code, u8 dialog_token,
+                                       u16 status_code, const u8 *buf,
+                                       size_t len)
+{
+       if (sm->ctx->send_tdls_mgmt)
+               return sm->ctx->send_tdls_mgmt(sm->ctx->ctx, dst, action_code,
+                                              dialog_token, status_code,
+                                              buf, len);
+       return -1;
+}
+
+static inline int wpa_sm_tdls_oper(struct wpa_sm *sm, int oper,
+                                  const u8 *peer)
+{
+       if (sm->ctx->tdls_oper)
+               return sm->ctx->tdls_oper(sm->ctx->ctx, oper, peer);
+       return -1;
+}
+
+static inline int
+wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
+                       u16 capability, const u8 *supp_rates,
+                       size_t supp_rates_len)
+{
+       if (sm->ctx->tdls_peer_addset)
+               return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
+                                                capability, supp_rates,
+                                                supp_rates_len);
+       return -1;
+}
+#endif /* CONFIG_TDLS */
 
 void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
                        int ver, const u8 *dest, u16 proto,
@@ -256,4 +323,7 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
                      const struct wpa_eapol_key *key,
                      struct wpa_ptk *ptk, size_t ptk_len);
 
+void wpa_tdls_assoc(struct wpa_sm *sm);
+void wpa_tdls_disassoc(struct wpa_sm *sm);
+
 #endif /* WPA_I_H */
index f447223..cbbc54f 100644 (file)
 #include "wpa_ie.h"
 
 
-static int wpa_selector_to_bitfield(const u8 *s)
-{
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
-               return WPA_CIPHER_NONE;
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
-               return WPA_CIPHER_WEP40;
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
-               return WPA_CIPHER_TKIP;
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
-               return WPA_CIPHER_CCMP;
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
-               return WPA_CIPHER_WEP104;
-       return 0;
-}
-
-
-static int wpa_key_mgmt_to_bitfield(const u8 *s)
-{
-       if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
-               return WPA_KEY_MGMT_IEEE8021X;
-       if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
-               return WPA_KEY_MGMT_PSK;
-       if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
-               return WPA_KEY_MGMT_WPA_NONE;
-       return 0;
-}
-
-
-static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
-                               struct wpa_ie_data *data)
-{
-       const struct wpa_ie_hdr *hdr;
-       const u8 *pos;
-       int left;
-       int i, count;
-
-       os_memset(data, 0, sizeof(*data));
-       data->proto = WPA_PROTO_WPA;
-       data->pairwise_cipher = WPA_CIPHER_TKIP;
-       data->group_cipher = WPA_CIPHER_TKIP;
-       data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
-       data->capabilities = 0;
-       data->pmkid = NULL;
-       data->num_pmkid = 0;
-       data->mgmt_group_cipher = 0;
-
-       if (wpa_ie_len == 0) {
-               /* No WPA IE - fail silently */
-               return -1;
-       }
-
-       if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
-               wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
-                          __func__, (unsigned long) wpa_ie_len);
-               return -1;
-       }
-
-       hdr = (const struct wpa_ie_hdr *) wpa_ie;
-
-       if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
-           hdr->len != wpa_ie_len - 2 ||
-           RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
-           WPA_GET_LE16(hdr->version) != WPA_VERSION) {
-               wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
-                          __func__);
-               return -1;
-       }
-
-       pos = (const u8 *) (hdr + 1);
-       left = wpa_ie_len - sizeof(*hdr);
-
-       if (left >= WPA_SELECTOR_LEN) {
-               data->group_cipher = wpa_selector_to_bitfield(pos);
-               pos += WPA_SELECTOR_LEN;
-               left -= WPA_SELECTOR_LEN;
-       } else if (left > 0) {
-               wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
-                          __func__, left);
-               return -1;
-       }
-
-       if (left >= 2) {
-               data->pairwise_cipher = 0;
-               count = WPA_GET_LE16(pos);
-               pos += 2;
-               left -= 2;
-               if (count == 0 || left < count * WPA_SELECTOR_LEN) {
-                       wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
-                                  "count %u left %u", __func__, count, left);
-                       return -1;
-               }
-               for (i = 0; i < count; i++) {
-                       data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
-                       pos += WPA_SELECTOR_LEN;
-                       left -= WPA_SELECTOR_LEN;
-               }
-       } else if (left == 1) {
-               wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
-                          __func__);
-               return -1;
-       }
-
-       if (left >= 2) {
-               data->key_mgmt = 0;
-               count = WPA_GET_LE16(pos);
-               pos += 2;
-               left -= 2;
-               if (count == 0 || left < count * WPA_SELECTOR_LEN) {
-                       wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
-                                  "count %u left %u", __func__, count, left);
-                       return -1;
-               }
-               for (i = 0; i < count; i++) {
-                       data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
-                       pos += WPA_SELECTOR_LEN;
-                       left -= WPA_SELECTOR_LEN;
-               }
-       } else if (left == 1) {
-               wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
-                          __func__);
-               return -1;
-       }
-
-       if (left >= 2) {
-               data->capabilities = WPA_GET_LE16(pos);
-               pos += 2;
-               left -= 2;
-       }
-
-       if (left > 0) {
-               wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
-                          __func__, left);
-       }
-
-       return 0;
-}
-
-
 /**
  * wpa_parse_wpa_ie - Parse WPA/RSN IE
  * @wpa_ie: Pointer to WPA or RSN IE
@@ -535,7 +397,6 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
                        ie->rsn_ie_len = pos[1] + 2;
                        wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
                                    ie->rsn_ie, ie->rsn_ie_len);
-#ifdef CONFIG_IEEE80211R
                } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
                        ie->mdie = pos;
                        ie->mdie_len = pos[1] + 2;
@@ -562,7 +423,20 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
                                            "EAPOL-Key Key Data IE",
                                            pos, 2 + pos[1]);
                        }
-#endif /* CONFIG_IEEE80211R */
+               } else if (*pos == WLAN_EID_LINK_ID) {
+                       if (pos[1] >= 18) {
+                               ie->lnkid = pos;
+                               ie->lnkid_len = pos[1] + 2;
+                       }
+               } else if (*pos == WLAN_EID_EXT_CAPAB) {
+                       ie->ext_capab = pos;
+                       ie->ext_capab_len = pos[1] + 2;
+               } else if (*pos == WLAN_EID_SUPP_RATES) {
+                       ie->supp_rates = pos;
+                       ie->supp_rates_len = pos[1] + 2;
+               } else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
+                       ie->ext_supp_rates = pos;
+                       ie->ext_supp_rates_len = pos[1] + 2;
                } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
                        ret = wpa_parse_generic(pos, end, ie);
                        if (ret < 0)
index 94518d8..c13d94c 100644 (file)
@@ -15,6 +15,8 @@
 #ifndef WPA_IE_H
 #define WPA_IE_H
 
+struct wpa_sm;
+
 struct wpa_eapol_ie_parse {
        const u8 *wpa_ie;
        size_t wpa_ie_len;
@@ -39,14 +41,20 @@ struct wpa_eapol_ie_parse {
        const u8 *igtk;
        size_t igtk_len;
 #endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R
        const u8 *mdie;
        size_t mdie_len;
        const u8 *ftie;
        size_t ftie_len;
        const u8 *reassoc_deadline;
        const u8 *key_lifetime;
-#endif /* CONFIG_IEEE80211R */
+       const u8 *lnkid;
+       size_t lnkid_len;
+       const u8 *ext_capab;
+       size_t ext_capab_len;
+       const u8 *supp_rates;
+       size_t supp_rates_len;
+       const u8 *ext_supp_rates;
+       size_t ext_supp_rates_len;
 };
 
 int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
diff --git a/src/tls/.gitignore b/src/tls/.gitignore
deleted file mode 100644 (file)
index d43242d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-libtls.a
index a2da096..27cdfca 100644 (file)
@@ -11,6 +11,8 @@ include ../lib.rules
 
 CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
 CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+CFLAGS += -DCONFIG_TLSV11
+CFLAGS += -DCONFIG_TLSV12
 
 LIB_OBJS= \
        asn1.o \
index 1374264..7c9857f 100644 (file)
@@ -572,7 +572,7 @@ static int mp_mod (mp_int * a, mp_int * b, mp_int * c)
 
 /* this is a shell function that calls either the normal or Montgomery
  * exptmod functions.  Originally the call to the montgomery code was
- * embedded in the normal function but that wasted alot of stack space
+ * embedded in the normal function but that wasted a lot of stack space
  * for nothing (since 99% of the time the Montgomery code would be called)
  */
 static int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
@@ -2207,7 +2207,7 @@ static int mp_2expt (mp_int * a, int b)
   /* zero a as per default */
   mp_zero (a);
 
-  /* grow a to accomodate the single bit */
+  /* grow a to accommodate the single bit */
   if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) {
     return res;
   }
@@ -2319,7 +2319,7 @@ CLEANUP:
 }
 
 
-/* multiplies |a| * |b| and only computes upto digs digits of result
+/* multiplies |a| * |b| and only computes up to digs digits of result
  * HAC pp. 595, Algorithm 14.12  Modified so you can control how 
  * many digits of output are created.
  */
@@ -2678,7 +2678,7 @@ mp_montgomery_setup (mp_int * n, mp_digit * rho)
  *
  * Based on Algorithm 14.32 on pp.601 of HAC.
 */
-int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
+static int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
 {
   int     ix, res, olduse;
   mp_word W[MP_WARRAY];
@@ -2829,7 +2829,7 @@ static int mp_mul_2(mp_int * a, mp_int * b)
 {
   int     x, res, oldused;
 
-  /* grow to accomodate result */
+  /* grow to accommodate result */
   if (b->alloc < a->used + 1) {
     if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
       return res;
@@ -2891,8 +2891,8 @@ static int mp_mul_2(mp_int * a, mp_int * b)
 /*
  * shifts with subtractions when the result is greater than b.
  *
- * The method is slightly modified to shift B unconditionally upto just under
- * the leading bit of b.  This saves alot of multiple precision shifting.
+ * The method is slightly modified to shift B unconditionally up to just under
+ * the leading bit of b.  This saves a lot of multiple precision shifting.
  */
 static int mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
 {
index 4291b84..fd9e346 100644 (file)
@@ -32,7 +32,7 @@ struct pkcs5_params {
 };
 
 
-enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)
+static enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)
 {
        if (oid->len == 7 &&
            oid->oid[0] == 1 /* iso */ &&
index afb6031..d0da588 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * TLSv1 client (RFC 2246)
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * 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
@@ -67,7 +67,8 @@ int tls_derive_keys(struct tlsv1_client *conn,
                os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
                os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
                          TLS_RANDOM_LEN);
-               if (tls_prf(pre_master_secret, pre_master_secret_len,
+               if (tls_prf(conn->rl.tls_version,
+                           pre_master_secret, pre_master_secret_len,
                            "master secret", seed, 2 * TLS_RANDOM_LEN,
                            conn->master_secret, TLS_MASTER_SECRET_LEN)) {
                        wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
@@ -80,9 +81,11 @@ int tls_derive_keys(struct tlsv1_client *conn,
 
        os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
        os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
-       key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
-                            conn->rl.iv_size);
-       if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+       key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len);
+       if (conn->rl.tls_version == TLS_VERSION_1)
+               key_block_len += 2 * conn->rl.iv_size;
+       if (tls_prf(conn->rl.tls_version,
+                   conn->master_secret, TLS_MASTER_SECRET_LEN,
                    "key expansion", seed, 2 * TLS_RANDOM_LEN,
                    key_block, key_block_len)) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
@@ -107,12 +110,21 @@ int tls_derive_keys(struct tlsv1_client *conn,
        os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
        pos += conn->rl.key_material_len;
 
-       /* client_write_IV */
-       os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
-       pos += conn->rl.iv_size;
-       /* server_write_IV */
-       os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
-       pos += conn->rl.iv_size;
+       if (conn->rl.tls_version == TLS_VERSION_1) {
+               /* client_write_IV */
+               os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
+               pos += conn->rl.iv_size;
+               /* server_write_IV */
+               os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
+               pos += conn->rl.iv_size;
+       } else {
+               /*
+                * Use IV field to set the mask value for TLS v1.1. A fixed
+                * mask of zero is used per the RFC 4346, 6.2.3.2 CBC Block
+                * Cipher option 2a.
+                */
+               os_memset(conn->rl.write_iv, 0, conn->rl.iv_size);
+       }
 
        return 0;
 }
@@ -126,17 +138,23 @@ int tls_derive_keys(struct tlsv1_client *conn,
  * @out_len: Length of the output buffer.
  * @appl_data: Pointer to application data pointer, or %NULL if dropped
  * @appl_data_len: Pointer to variable that is set to appl_data length
+ * @need_more_data: Set to 1 if more data would be needed to complete
+ *     processing
  * Returns: Pointer to output data, %NULL on failure
  */
 u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
                            const u8 *in_data, size_t in_len,
                            size_t *out_len, u8 **appl_data,
-                           size_t *appl_data_len)
+                           size_t *appl_data_len, int *need_more_data)
 {
        const u8 *pos, *end;
-       u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
+       u8 *msg = NULL, *in_msg = NULL, *in_pos, *in_end, alert, ct;
        size_t in_msg_len;
        int no_appl_data;
+       int used;
+
+       if (need_more_data)
+               *need_more_data = 0;
 
        if (conn->state == CLIENT_HELLO) {
                if (in_len)
@@ -144,6 +162,19 @@ u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
                return tls_send_client_hello(conn, out_len);
        }
 
+       if (conn->partial_input) {
+               if (wpabuf_resize(&conn->partial_input, in_len) < 0) {
+                       wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+                                  "memory for pending record");
+                       tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                 TLS_ALERT_INTERNAL_ERROR);
+                       goto failed;
+               }
+               wpabuf_put_data(conn->partial_input, in_data, in_len);
+               in_data = wpabuf_head(conn->partial_input);
+               in_len = wpabuf_len(conn->partial_input);
+       }
+
        if (in_data == NULL || in_len == 0)
                return NULL;
 
@@ -156,13 +187,33 @@ u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
        /* Each received packet may include multiple records */
        while (pos < end) {
                in_msg_len = in_len;
-               if (tlsv1_record_receive(&conn->rl, pos, end - pos,
-                                        in_msg, &in_msg_len, &alert)) {
+               used = tlsv1_record_receive(&conn->rl, pos, end - pos,
+                                           in_msg, &in_msg_len, &alert);
+               if (used < 0) {
                        wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
                                   "record failed");
                        tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
                        goto failed;
                }
+               if (used == 0) {
+                       struct wpabuf *partial;
+                       wpa_printf(MSG_DEBUG, "TLSv1: Need more data");
+                       partial = wpabuf_alloc_copy(pos, end - pos);
+                       wpabuf_free(conn->partial_input);
+                       conn->partial_input = partial;
+                       if (conn->partial_input == NULL) {
+                               wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
+                                          "allocate memory for pending "
+                                          "record");
+                               tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                         TLS_ALERT_INTERNAL_ERROR);
+                               goto failed;
+                       }
+                       os_free(in_msg);
+                       if (need_more_data)
+                               *need_more_data = 1;
+                       return NULL;
+               }
                ct = pos[0];
 
                in_pos = in_msg;
@@ -180,7 +231,7 @@ u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
                        in_pos += in_msg_len;
                }
 
-               pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+               pos += used;
        }
 
        os_free(in_msg);
@@ -192,6 +243,8 @@ u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
 failed:
        os_free(in_msg);
        if (conn->alert_level) {
+               wpabuf_free(conn->partial_input);
+               conn->partial_input = NULL;
                conn->state = FAILED;
                os_free(msg);
                msg = tlsv1_client_send_alert(conn, conn->alert_level,
@@ -202,6 +255,11 @@ failed:
                *out_len = 0;
        }
 
+       if (need_more_data == NULL || !(*need_more_data)) {
+               wpabuf_free(conn->partial_input);
+               conn->partial_input = NULL;
+       }
+
        return msg;
 }
 
@@ -227,10 +285,8 @@ int tlsv1_client_encrypt(struct tlsv1_client *conn,
        wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
                        in_data, in_len);
 
-       os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len);
-
        if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
-                             out_data, out_len, in_len, &rlen) < 0) {
+                             out_data, out_len, in_data, in_len, &rlen) < 0) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
                tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
                          TLS_ALERT_INTERNAL_ERROR);
@@ -246,58 +302,116 @@ int tlsv1_client_encrypt(struct tlsv1_client *conn,
  * @conn: TLSv1 client connection data from tlsv1_client_init()
  * @in_data: Pointer to input buffer (encrypted TLS data)
  * @in_len: Input buffer length
- * @out_data: Pointer to output buffer (decrypted data from TLS tunnel)
- * @out_len: Maximum out_data length
- * Returns: Number of bytes written to out_data, -1 on failure
+ * @need_more_data: Set to 1 if more data would be needed to complete
+ *     processing
+ * Returns: Decrypted data or %NULL on failure
  *
  * This function is used after TLS handshake has been completed successfully to
  * receive data from the encrypted tunnel.
  */
-int tlsv1_client_decrypt(struct tlsv1_client *conn,
-                        const u8 *in_data, size_t in_len,
-                        u8 *out_data, size_t out_len)
+struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn,
+                                    const u8 *in_data, size_t in_len,
+                                    int *need_more_data)
 {
        const u8 *in_end, *pos;
-       int res;
-       u8 alert, *out_end, *out_pos;
+       int used;
+       u8 alert, *out_pos, ct;
        size_t olen;
+       struct wpabuf *buf = NULL;
+
+       if (need_more_data)
+               *need_more_data = 0;
+
+       if (conn->partial_input) {
+               if (wpabuf_resize(&conn->partial_input, in_len) < 0) {
+                       wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+                                  "memory for pending record");
+                       alert = TLS_ALERT_INTERNAL_ERROR;
+                       goto fail;
+               }
+               wpabuf_put_data(conn->partial_input, in_data, in_len);
+               in_data = wpabuf_head(conn->partial_input);
+               in_len = wpabuf_len(conn->partial_input);
+       }
 
        pos = in_data;
        in_end = in_data + in_len;
-       out_pos = out_data;
-       out_end = out_data + out_len;
 
        while (pos < in_end) {
-               if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
-                       wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
-                                  "0x%x", pos[0]);
-                       tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-                                 TLS_ALERT_UNEXPECTED_MESSAGE);
-                       return -1;
+               ct = pos[0];
+               if (wpabuf_resize(&buf, in_end - pos) < 0) {
+                       alert = TLS_ALERT_INTERNAL_ERROR;
+                       goto fail;
                }
-
-               olen = out_end - out_pos;
-               res = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
-                                          out_pos, &olen, &alert);
-               if (res < 0) {
+               out_pos = wpabuf_put(buf, 0);
+               olen = wpabuf_tailroom(buf);
+               used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
+                                           out_pos, &olen, &alert);
+               if (used < 0) {
                        wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
                                   "failed");
-                       tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
-                       return -1;
+                       goto fail;
                }
-               out_pos += olen;
-               if (out_pos > out_end) {
-                       wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
-                                  "for processing the received record");
-                       tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-                                 TLS_ALERT_INTERNAL_ERROR);
-                       return -1;
+               if (used == 0) {
+                       struct wpabuf *partial;
+                       wpa_printf(MSG_DEBUG, "TLSv1: Need more data");
+                       partial = wpabuf_alloc_copy(pos, in_end - pos);
+                       wpabuf_free(conn->partial_input);
+                       conn->partial_input = partial;
+                       if (conn->partial_input == NULL) {
+                               wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
+                                          "allocate memory for pending "
+                                          "record");
+                               alert = TLS_ALERT_INTERNAL_ERROR;
+                               goto fail;
+                       }
+                       if (need_more_data)
+                               *need_more_data = 1;
+                       return buf;
+               }
+
+               if (ct == TLS_CONTENT_TYPE_ALERT) {
+                       if (olen < 2) {
+                               wpa_printf(MSG_DEBUG, "TLSv1: Alert "
+                                          "underflow");
+                               alert = TLS_ALERT_DECODE_ERROR;
+                               goto fail;
+                       }
+                       wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
+                                  out_pos[0], out_pos[1]);
+                       if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
+                               /* Continue processing */
+                               pos += used;
+                               continue;
+                       }
+
+                       alert = out_pos[1];
+                       goto fail;
+               }
+
+               if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+                       wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
+                                  "0x%x when decrypting application data",
+                                  pos[0]);
+                       alert = TLS_ALERT_UNEXPECTED_MESSAGE;
+                       goto fail;
                }
 
-               pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+               wpabuf_put(buf, olen);
+
+               pos += used;
        }
 
-       return out_pos - out_data;
+       wpabuf_free(conn->partial_input);
+       conn->partial_input = NULL;
+       return buf;
+
+fail:
+       wpabuf_free(buf);
+       wpabuf_free(conn->partial_input);
+       conn->partial_input = NULL;
+       tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+       return NULL;
 }
 
 
@@ -352,14 +466,18 @@ 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;
        suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
        suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
        conn->num_cipher_suites = count;
 
+       conn->rl.tls_version = TLS_VERSION;
+
        return conn;
 }
 
@@ -378,6 +496,7 @@ void tlsv1_client_deinit(struct tlsv1_client *conn)
        os_free(conn->client_hello_ext);
        tlsv1_client_free_dh(conn);
        tlsv1_cred_free(conn->cred);
+       wpabuf_free(conn->partial_input);
        os_free(conn);
 }
 
@@ -421,7 +540,8 @@ int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
                          TLS_RANDOM_LEN);
        }
 
-       return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+       return tls_prf(conn->rl.tls_version,
+                      conn->master_secret, TLS_MASTER_SECRET_LEN,
                       label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
 }
 
@@ -453,15 +573,24 @@ int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
        case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
                cipher = "DES-CBC3-SHA";
                break;
+       case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+               cipher = "ADH-AES-128-SHA256";
+               break;
        case TLS_DH_anon_WITH_AES_128_CBC_SHA:
                cipher = "ADH-AES-128-SHA";
                break;
        case TLS_RSA_WITH_AES_256_CBC_SHA:
                cipher = "AES-256-SHA";
                break;
+       case TLS_RSA_WITH_AES_256_CBC_SHA256:
+               cipher = "AES-256-SHA256";
+               break;
        case TLS_RSA_WITH_AES_128_CBC_SHA:
                cipher = "AES-128-SHA";
                break;
+       case TLS_RSA_WITH_AES_128_CBC_SHA256:
+               cipher = "AES-128-SHA256";
+               break;
        default:
                return -1;
        }
@@ -613,8 +742,10 @@ int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers)
                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;
                suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
@@ -656,6 +787,12 @@ int tlsv1_client_set_cred(struct tlsv1_client *conn,
 }
 
 
+void tlsv1_client_set_time_checks(struct tlsv1_client *conn, int enabled)
+{
+       conn->disable_time_checks = !enabled;
+}
+
+
 void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
                                        tlsv1_client_session_ticket_cb cb,
                                        void *ctx)
index 16ad57d..ef5e694 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * TLSv1 client (RFC 2246)
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * 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
@@ -29,13 +29,13 @@ int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
 u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
                            const u8 *in_data, size_t in_len,
                            size_t *out_len, u8 **appl_data,
-                           size_t *appl_data_len);
+                           size_t *appl_data_len, int *need_more_data);
 int tlsv1_client_encrypt(struct tlsv1_client *conn,
                         const u8 *in_data, size_t in_len,
                         u8 *out_data, size_t out_len);
-int tlsv1_client_decrypt(struct tlsv1_client *conn,
-                        const u8 *in_data, size_t in_len,
-                        u8 *out_data, size_t out_len);
+struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn,
+                                    const u8 *in_data, size_t in_len,
+                                    int *need_more_data);
 int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
                            size_t buflen);
 int tlsv1_client_shutdown(struct tlsv1_client *conn);
@@ -47,6 +47,7 @@ int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn);
 int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers);
 int tlsv1_client_set_cred(struct tlsv1_client *conn,
                          struct tlsv1_credentials *cred);
+void tlsv1_client_set_time_checks(struct tlsv1_client *conn, int enabled);
 
 typedef int (*tlsv1_client_session_ticket_cb)
 (void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
index 7fe179f..92912ca 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * TLSv1 client - internal structures
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * 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
@@ -39,6 +39,7 @@ struct tlsv1_client {
        unsigned int session_resumed:1;
        unsigned int session_ticket_included:1;
        unsigned int use_session_ticket:1;
+       unsigned int disable_time_checks:1;
 
        struct crypto_public_key *server_rsa_key;
 
@@ -67,6 +68,8 @@ struct tlsv1_client {
 
        tlsv1_client_session_ticket_cb session_ticket_cb;
        void *session_ticket_cb_ctx;
+
+       struct wpabuf *partial_input;
 };
 
 
index ed3f260..eb0cbef 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * TLSv1 client - read handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * 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
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
+#include "crypto/sha256.h"
 #include "crypto/tls.h"
 #include "x509v3.h"
 #include "tlsv1_common.h"
@@ -38,6 +39,7 @@ static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
        const u8 *pos, *end;
        size_t left, len, i;
        u16 cipher_suite;
+       u16 tls_version;
 
        if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
                wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
@@ -79,15 +81,20 @@ static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
        /* ProtocolVersion server_version */
        if (end - pos < 2)
                goto decode_error;
-       if (WPA_GET_BE16(pos) != TLS_VERSION) {
+       tls_version = WPA_GET_BE16(pos);
+       if (!tls_version_ok(tls_version)) {
                wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
-                          "ServerHello");
+                          "ServerHello %u.%u", pos[0], pos[1]);
                tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
                          TLS_ALERT_PROTOCOL_VERSION);
                return -1;
        }
        pos += 2;
 
+       wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s",
+                  tls_version_str(tls_version));
+       conn->rl.tls_version = tls_version;
+
        /* Random random */
        if (end - pos < TLS_RANDOM_LEN)
                goto decode_error;
@@ -365,7 +372,8 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
 
        if (conn->cred &&
            x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
-                                           &reason) < 0) {
+                                           &reason, conn->disable_time_checks)
+           < 0) {
                int tls_reason;
                wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
                           "validation failed (reason=%d)", reason);
@@ -815,6 +823,21 @@ static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
        wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
                    pos, TLS_VERIFY_DATA_LEN);
 
+#ifdef CONFIG_TLSV12
+       if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+               hlen = SHA256_MAC_LEN;
+               if (conn->verify.sha256_server == NULL ||
+                   crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
+                   < 0) {
+                       tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                 TLS_ALERT_INTERNAL_ERROR);
+                       conn->verify.sha256_server = NULL;
+                       return -1;
+               }
+               conn->verify.sha256_server = NULL;
+       } else {
+#endif /* CONFIG_TLSV12 */
+
        hlen = MD5_MAC_LEN;
        if (conn->verify.md5_server == NULL ||
            crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
@@ -836,9 +859,15 @@ static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
                return -1;
        }
        conn->verify.sha1_server = NULL;
+       hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
+
+#ifdef CONFIG_TLSV12
+       }
+#endif /* CONFIG_TLSV12 */
 
-       if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-                   "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
+       if (tls_prf(conn->rl.tls_version,
+                   conn->master_secret, TLS_MASTER_SECRET_LEN,
+                   "server finished", hash, hlen,
                    verify_data, TLS_VERIFY_DATA_LEN)) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
                tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
index b47425f..35a238b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * TLSv1 client - write handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * 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
@@ -17,7 +17,9 @@
 #include "common.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
+#include "crypto/sha256.h"
 #include "crypto/tls.h"
+#include "crypto/random.h"
 #include "x509v3.h"
 #include "tlsv1_common.h"
 #include "tlsv1_record.h"
@@ -57,7 +59,7 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
 
        os_get_time(&now);
        WPA_PUT_BE32(conn->client_random, now.sec);
-       if (os_get_random(conn->client_random + 4, TLS_RANDOM_LEN - 4)) {
+       if (random_get_bytes(conn->client_random + 4, TLS_RANDOM_LEN - 4)) {
                wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
                           "client_random");
                return NULL;
@@ -115,7 +117,8 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
        tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
 
        if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-                             rhdr, end - rhdr, pos - hs_start, out_len) < 0) {
+                             rhdr, end - rhdr, hs_start, pos - hs_start,
+                             out_len) < 0) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
                tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
                          TLS_ALERT_INTERNAL_ERROR);
@@ -191,7 +194,8 @@ static int tls_write_client_certificate(struct tlsv1_client *conn,
        WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
        if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-                             rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+                             rhdr, end - rhdr, hs_start, pos - hs_start,
+                             &rlen) < 0) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
                tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
                          TLS_ALERT_INTERNAL_ERROR);
@@ -222,7 +226,7 @@ static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
                          TLS_ALERT_INTERNAL_ERROR);
                return -1;
        }
-       if (os_get_random(csecret, csecret_len)) {
+       if (random_get_bytes(csecret, csecret_len)) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
                           "data for Diffie-Hellman");
                tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -412,7 +416,8 @@ static int tls_write_client_key_exchange(struct tlsv1_client *conn,
        WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
        if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-                             rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+                             rhdr, end - rhdr, hs_start, pos - hs_start,
+                             &rlen) < 0) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
                tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
                          TLS_ALERT_INTERNAL_ERROR);
@@ -432,7 +437,7 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
 {
        u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
        size_t rlen, hlen, clen;
-       u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
+       u8 hash[100], *hpos;
        enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
 
        pos = *msgpos;
@@ -472,6 +477,40 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
 
        hpos = hash;
 
+#ifdef CONFIG_TLSV12
+       if (conn->rl.tls_version == TLS_VERSION_1_2) {
+               hlen = SHA256_MAC_LEN;
+               if (conn->verify.sha256_cert == NULL ||
+                   crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) <
+                   0) {
+                       conn->verify.sha256_cert = NULL;
+                       tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                 TLS_ALERT_INTERNAL_ERROR);
+                       return -1;
+               }
+               conn->verify.sha256_cert = NULL;
+
+               /*
+                * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+                *
+                * DigestInfo ::= SEQUENCE {
+                *   digestAlgorithm DigestAlgorithm,
+                *   digest OCTET STRING
+                * }
+                *
+                * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+                *
+                * DER encoded DigestInfo for SHA256 per RFC 3447:
+                * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
+                * H
+                */
+               os_memmove(hash + 19, hash, hlen);
+               hlen += 19;
+               os_memcpy(hash, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65"
+                         "\x03\x04\x02\x01\x05\x00\x04\x20", 19);
+       } else {
+#endif /* CONFIG_TLSV12 */
+
        if (alg == SIGN_ALG_RSA) {
                hlen = MD5_MAC_LEN;
                if (conn->verify.md5_cert == NULL ||
@@ -502,8 +541,29 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
        if (alg == SIGN_ALG_RSA)
                hlen += MD5_MAC_LEN;
 
+#ifdef CONFIG_TLSV12
+       }
+#endif /* CONFIG_TLSV12 */
+
        wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
 
+#ifdef CONFIG_TLSV12
+       if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+               /*
+                * RFC 5246, 4.7:
+                * TLS v1.2 adds explicit indication of the used signature and
+                * hash algorithms.
+                *
+                * struct {
+                *   HashAlgorithm hash;
+                *   SignatureAlgorithm signature;
+                * } SignatureAndHashAlgorithm;
+                */
+               *pos++ = TLS_HASH_ALG_SHA256;
+               *pos++ = TLS_SIGN_ALG_RSA;
+       }
+#endif /* CONFIG_TLSV12 */
+
        /*
         * RFC 2246, 4.7:
         * In digital signing, one-way hash functions are used as input for a
@@ -533,7 +593,8 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
        WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
        if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-                             rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+                             rhdr, end - rhdr, hs_start, pos - hs_start,
+                             &rlen) < 0) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
                tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
                          TLS_ALERT_INTERNAL_ERROR);
@@ -552,17 +613,16 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
 static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn,
                                               u8 **msgpos, u8 *end)
 {
-       u8 *pos, *rhdr;
        size_t rlen;
-
-       pos = *msgpos;
+       u8 payload[1];
 
        wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
-       rhdr = pos;
-       pos += TLS_RECORD_HEADER_LEN;
-       *pos = TLS_CHANGE_CIPHER_SPEC;
+
+       payload[0] = TLS_CHANGE_CIPHER_SPEC;
+
        if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
-                             rhdr, end - rhdr, 1, &rlen) < 0) {
+                             *msgpos, end - *msgpos, payload, sizeof(payload),
+                             &rlen) < 0) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
                tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
                          TLS_ALERT_INTERNAL_ERROR);
@@ -577,7 +637,7 @@ static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn,
                return -1;
        }
 
-       *msgpos = rhdr + rlen;
+       *msgpos += rlen;
 
        return 0;
 }
@@ -586,17 +646,30 @@ static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn,
 static int tls_write_client_finished(struct tlsv1_client *conn,
                                     u8 **msgpos, u8 *end)
 {
-       u8 *pos, *rhdr, *hs_start, *hs_length;
+       u8 *pos, *hs_start;
        size_t rlen, hlen;
-       u8 verify_data[TLS_VERIFY_DATA_LEN];
+       u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN];
        u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
 
-       pos = *msgpos;
-
        wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
 
        /* Encrypted Handshake Message: Finished */
 
+#ifdef CONFIG_TLSV12
+       if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+               hlen = SHA256_MAC_LEN;
+               if (conn->verify.sha256_client == NULL ||
+                   crypto_hash_finish(conn->verify.sha256_client, hash, &hlen)
+                   < 0) {
+                       tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                 TLS_ALERT_INTERNAL_ERROR);
+                       conn->verify.sha256_client = NULL;
+                       return -1;
+               }
+               conn->verify.sha256_client = NULL;
+       } else {
+#endif /* CONFIG_TLSV12 */
+
        hlen = MD5_MAC_LEN;
        if (conn->verify.md5_client == NULL ||
            crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
@@ -618,43 +691,44 @@ static int tls_write_client_finished(struct tlsv1_client *conn,
                return -1;
        }
        conn->verify.sha1_client = NULL;
+       hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
+
+#ifdef CONFIG_TLSV12
+       }
+#endif /* CONFIG_TLSV12 */
 
-       if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-                   "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
-                   verify_data, TLS_VERIFY_DATA_LEN)) {
+       if (tls_prf(conn->rl.tls_version,
+                   conn->master_secret, TLS_MASTER_SECRET_LEN,
+                   "client finished", hash, hlen,
+                   verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
                tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
                          TLS_ALERT_INTERNAL_ERROR);
                return -1;
        }
        wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
-                       verify_data, TLS_VERIFY_DATA_LEN);
+                       verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
 
-       rhdr = pos;
-       pos += TLS_RECORD_HEADER_LEN;
        /* Handshake */
-       hs_start = pos;
+       pos = hs_start = verify_data;
        /* HandshakeType msg_type */
        *pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
-       /* uint24 length (to be filled) */
-       hs_length = pos;
+       /* uint24 length */
+       WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN);
        pos += 3;
-       os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
-       pos += TLS_VERIFY_DATA_LEN;
-       WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+       pos += TLS_VERIFY_DATA_LEN; /* verify_data already in place */
        tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
 
        if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-                             rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+                             *msgpos, end - *msgpos, hs_start, pos - hs_start,
+                             &rlen) < 0) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
                tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
                          TLS_ALERT_INTERNAL_ERROR);
                return -1;
        }
 
-       pos = rhdr + rlen;
-
-       *msgpos = pos;
+       *msgpos += rlen;
 
        return 0;
 }
@@ -668,7 +742,7 @@ static u8 * tls_send_client_key_exchange(struct tlsv1_client *conn,
 
        *out_len = 0;
 
-       msglen = 1000;
+       msglen = 2000;
        if (conn->certificate_requested)
                msglen += tls_client_cert_chain_der_len(conn);
 
@@ -777,7 +851,8 @@ u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level,
        /* ContentType type */
        *pos++ = TLS_CONTENT_TYPE_ALERT;
        /* ProtocolVersion version */
-       WPA_PUT_BE16(pos, TLS_VERSION);
+       WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version :
+                    TLS_VERSION);
        pos += 2;
        /* uint16 length (to be filled) */
        length = pos;
index 2f9dd0f..871359a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * TLSv1 common routines
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * 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
@@ -15,6 +15,8 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
 #include "x509v3.h"
 #include "tlsv1_common.h"
 
@@ -50,7 +52,15 @@ static const struct tls_cipher_suite tls_cipher_suites[] = {
        { TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC,
          TLS_HASH_SHA },
        { TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon,
-         TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA }
+         TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA },
+       { TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_RSA,
+         TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
+       { TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_RSA,
+         TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 },
+       { TLS_DH_anon_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DH_anon,
+         TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
+       { TLS_DH_anon_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DH_anon,
+         TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 }
 };
 
 #define NUM_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
@@ -202,6 +212,19 @@ int tls_verify_hash_init(struct tls_verify_hash *verify)
                tls_verify_hash_free(verify);
                return -1;
        }
+#ifdef CONFIG_TLSV12
+       verify->sha256_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL,
+                                                0);
+       verify->sha256_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL,
+                                                0);
+       verify->sha256_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL,
+                                              0);
+       if (verify->sha256_client == NULL || verify->sha256_server == NULL ||
+           verify->sha256_cert == NULL) {
+               tls_verify_hash_free(verify);
+               return -1;
+       }
+#endif /* CONFIG_TLSV12 */
        return 0;
 }
 
@@ -221,6 +244,14 @@ void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,
                crypto_hash_update(verify->md5_cert, buf, len);
                crypto_hash_update(verify->sha1_cert, buf, len);
        }
+#ifdef CONFIG_TLSV12
+       if (verify->sha256_client)
+               crypto_hash_update(verify->sha256_client, buf, len);
+       if (verify->sha256_server)
+               crypto_hash_update(verify->sha256_server, buf, len);
+       if (verify->sha256_cert)
+               crypto_hash_update(verify->sha256_cert, buf, len);
+#endif /* CONFIG_TLSV12 */
 }
 
 
@@ -238,4 +269,60 @@ void tls_verify_hash_free(struct tls_verify_hash *verify)
        verify->sha1_client = NULL;
        verify->sha1_server = NULL;
        verify->sha1_cert = NULL;
+#ifdef CONFIG_TLSV12
+       crypto_hash_finish(verify->sha256_client, NULL, NULL);
+       crypto_hash_finish(verify->sha256_server, NULL, NULL);
+       crypto_hash_finish(verify->sha256_cert, NULL, NULL);
+       verify->sha256_client = NULL;
+       verify->sha256_server = NULL;
+       verify->sha256_cert = NULL;
+#endif /* CONFIG_TLSV12 */
+}
+
+
+int tls_version_ok(u16 ver)
+{
+       if (ver == TLS_VERSION_1)
+               return 1;
+#ifdef CONFIG_TLSV11
+       if (ver == TLS_VERSION_1_1)
+               return 1;
+#endif /* CONFIG_TLSV11 */
+#ifdef CONFIG_TLSV12
+       if (ver == TLS_VERSION_1_2)
+               return 1;
+#endif /* CONFIG_TLSV12 */
+
+       return 0;
+}
+
+
+const char * tls_version_str(u16 ver)
+{
+       switch (ver) {
+       case TLS_VERSION_1:
+               return "1.0";
+       case TLS_VERSION_1_1:
+               return "1.1";
+       case TLS_VERSION_1_2:
+               return "1.2";
+       }
+
+       return "?";
+}
+
+
+int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
+           const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+{
+#ifdef CONFIG_TLSV12
+       if (ver >= TLS_VERSION_1_2) {
+               tls_prf_sha256(secret, secret_len, label, seed, seed_len,
+                              out, outlen);
+               return 0;
+       }
+#endif /* CONFIG_TLSV12 */
+
+       return tls_prf_sha1_md5(secret, secret_len, label, seed, seed_len, out,
+                               outlen);
 }
index 763a4af..027daa4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * TLSv1 common definitions
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * 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
 
 #include "crypto/crypto.h"
 
-#define TLS_VERSION 0x0301 /* TLSv1 */
+#define TLS_VERSION_1 0x0301 /* TLSv1 */
+#define TLS_VERSION_1_1 0x0302 /* TLSv1.1 */
+#define TLS_VERSION_1_2 0x0303 /* TLSv1.2 */
+#ifdef CONFIG_TLSV12
+#define TLS_VERSION TLS_VERSION_1_2
+#else /* CONFIG_TLSV12 */
+#ifdef CONFIG_TLSV11
+#define TLS_VERSION TLS_VERSION_1_1
+#else /* CONFIG_TLSV11 */
+#define TLS_VERSION TLS_VERSION_1
+#endif /* CONFIG_TLSV11 */
+#endif /* CONFIG_TLSV12 */
 #define TLS_RANDOM_LEN 32
 #define TLS_PRE_MASTER_SECRET_LEN 48
 #define TLS_MASTER_SECRET_LEN 48
@@ -82,10 +93,42 @@ enum {
 #define TLS_DHE_DSS_WITH_AES_256_CBC_SHA       0x0038 /* RFC 3268 */
 #define TLS_DHE_RSA_WITH_AES_256_CBC_SHA       0x0039 /* RFC 3268 */
 #define TLS_DH_anon_WITH_AES_256_CBC_SHA       0x003A /* RFC 3268 */
+#define TLS_RSA_WITH_NULL_SHA256               0x003B /* RFC 5246 */
+#define TLS_RSA_WITH_AES_128_CBC_SHA256                0x003C /* RFC 5246 */
+#define TLS_RSA_WITH_AES_256_CBC_SHA256                0x003D /* RFC 5246 */
+#define TLS_DH_DSS_WITH_AES_128_CBC_SHA256     0x003E /* RFC 5246 */
+#define TLS_DH_RSA_WITH_AES_128_CBC_SHA256     0x003F /* RFC 5246 */
+#define TLS_DHE_DSS_WITH_AES_128_CBC_SHA256    0x0040 /* RFC 5246 */
+#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256    0x0067 /* RFC 5246 */
+#define TLS_DH_DSS_WITH_AES_256_CBC_SHA256     0x0068 /* RFC 5246 */
+#define TLS_DH_RSA_WITH_AES_256_CBC_SHA256     0x0069 /* RFC 5246 */
+#define TLS_DHE_DSS_WITH_AES_256_CBC_SHA256    0x006A /* RFC 5246 */
+#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256    0x006B /* RFC 5246 */
+#define TLS_DH_anon_WITH_AES_128_CBC_SHA256    0x006C /* RFC 5246 */
+#define TLS_DH_anon_WITH_AES_256_CBC_SHA256    0x006D /* RFC 5246 */
 
 /* CompressionMethod */
 #define TLS_COMPRESSION_NULL 0
 
+/* HashAlgorithm */
+enum {
+       TLS_HASH_ALG_NONE = 0,
+       TLS_HASH_ALG_MD5 = 1,
+       TLS_HASH_ALG_SHA1 = 2,
+       TLS_HASH_ALG_SHA224 = 3,
+       TLS_HASH_ALG_SHA256 = 4,
+       TLS_HASH_ALG_SHA384 = 5,
+       TLS_HASH_ALG_SHA512 = 6
+};
+
+/* SignatureAlgorithm */
+enum {
+       TLS_SIGN_ALG_ANONYMOUS = 0,
+       TLS_SIGN_ALG_RSA = 1,
+       TLS_SIGN_ALG_DSA = 2,
+       TLS_SIGN_ALG_ECDSA = 3,
+};
+
 /* AlertLevel */
 #define TLS_ALERT_LEVEL_WARNING 1
 #define TLS_ALERT_LEVEL_FATAL 2
@@ -169,7 +212,8 @@ typedef enum {
 typedef enum {
        TLS_HASH_NULL,
        TLS_HASH_MD5,
-       TLS_HASH_SHA
+       TLS_HASH_SHA,
+       TLS_HASH_SHA256
 } tls_hash;
 
 struct tls_cipher_suite {
@@ -197,10 +241,13 @@ struct tls_cipher_data {
 struct tls_verify_hash {
        struct crypto_hash *md5_client;
        struct crypto_hash *sha1_client;
+       struct crypto_hash *sha256_client;
        struct crypto_hash *md5_server;
        struct crypto_hash *sha1_server;
+       struct crypto_hash *sha256_server;
        struct crypto_hash *md5_cert;
        struct crypto_hash *sha1_cert;
+       struct crypto_hash *sha256_cert;
 };
 
 
@@ -212,5 +259,9 @@ int tls_verify_hash_init(struct tls_verify_hash *verify);
 void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,
                         size_t len);
 void tls_verify_hash_free(struct tls_verify_hash *verify);
+int tls_version_ok(u16 ver);
+const char * tls_version_str(u16 ver);
+int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
+           const u8 *seed, size_t seed_len, u8 *out, size_t outlen);
 
 #endif /* TLSV1_COMMON_H */
index aa467ef..d846480 100644 (file)
@@ -46,7 +46,7 @@ void tlsv1_cred_free(struct tlsv1_credentials *cred)
 static int tlsv1_add_cert_der(struct x509_certificate **chain,
                              const u8 *buf, size_t len)
 {
-       struct x509_certificate *cert;
+       struct x509_certificate *cert, *p;
        char name[128];
 
        cert = x509_certificate_parse(buf, len);
@@ -56,8 +56,20 @@ static int tlsv1_add_cert_der(struct x509_certificate **chain,
                return -1;
        }
 
-       cert->next = *chain;
-       *chain = cert;
+       p = *chain;
+       while (p && p->next)
+               p = p->next;
+       if (p && x509_name_compare(&cert->subject, &p->issuer) == 0) {
+               /*
+                * The new certificate is the issuer of the last certificate in
+                * the chain - add the new certificate to the end.
+                */
+               p->next = cert;
+       } else {
+               /* Add to the beginning of the chain */
+               cert->next = *chain;
+               *chain = cert;
+       }
 
        x509_name_string(&cert->subject, name, sizeof(name));
        wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
@@ -232,10 +244,17 @@ static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len)
                if (!end)
                        return NULL;
        } else {
+               const u8 *pos2;
                pos += os_strlen(pem_key_begin);
                end = search_tag(pem_key_end, pos, key + len - pos);
                if (!end)
                        return NULL;
+               pos2 = search_tag("Proc-Type: 4,ENCRYPTED", pos, end - pos);
+               if (pos2) {
+                       wpa_printf(MSG_DEBUG, "TLSv1: Unsupported private key "
+                                  "format (Proc-Type/DEK-Info)");
+                       return NULL;
+               }
        }
 
        der = base64_decode(pos, end - pos, &der_len);
index e811f0e..0314551 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * TLSv1 Record Protocol
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * 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
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
+#include "crypto/sha256.h"
 #include "tlsv1_common.h"
 #include "tlsv1_record.h"
 
@@ -52,6 +53,9 @@ int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
        } else if (suite->hash == TLS_HASH_SHA) {
                rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1;
                rl->hash_size = SHA1_MAC_LEN;
+       } else if (suite->hash == TLS_HASH_SHA256) {
+               rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA256;
+               rl->hash_size = SHA256_MAC_LEN;
        }
 
        data = tls_get_cipher_data(suite->cipher);
@@ -138,10 +142,10 @@ int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)
  * tlsv1_record_send - TLS record layer: Send a message
  * @rl: Pointer to TLS record layer data
  * @content_type: Content type (TLS_CONTENT_TYPE_*)
- * @buf: Buffer to send (with TLS_RECORD_HEADER_LEN octets reserved in the
- * beginning for record layer to fill in; payload filled in after this and
- * extra space in the end for HMAC).
+ * @buf: Buffer for the generated TLS message (needs to have extra space for
+ * header, IV (TLS v1.1), and HMAC)
  * @buf_size: Maximum buf size
+ * @payload: Payload to be sent
  * @payload_len: Length of the payload
  * @out_len: Buffer for returning the used buf length
  * Returns: 0 on success, -1 on failure
@@ -150,29 +154,62 @@ int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)
  * the data using the current write cipher.
  */
 int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
-                     size_t buf_size, size_t payload_len, size_t *out_len)
+                     size_t buf_size, const u8 *payload, size_t payload_len,
+                     size_t *out_len)
 {
-       u8 *pos, *ct_start, *length, *payload;
+       u8 *pos, *ct_start, *length, *cpayload;
        struct crypto_hash *hmac;
        size_t clen;
+       int explicit_iv;
 
        pos = buf;
+       if (pos + TLS_RECORD_HEADER_LEN > buf + buf_size)
+               return -1;
+
        /* ContentType type */
        ct_start = pos;
        *pos++ = content_type;
        /* ProtocolVersion version */
-       WPA_PUT_BE16(pos, TLS_VERSION);
+       WPA_PUT_BE16(pos, rl->tls_version);
        pos += 2;
        /* uint16 length */
        length = pos;
        WPA_PUT_BE16(length, payload_len);
        pos += 2;
 
-       /* opaque fragment[TLSPlaintext.length] */
-       payload = pos;
+       cpayload = pos;
+       explicit_iv = rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL &&
+               rl->iv_size && rl->tls_version >= TLS_VERSION_1_1;
+       if (explicit_iv) {
+               /* opaque IV[Cipherspec.block_length] */
+               if (pos + rl->iv_size > buf + buf_size)
+                       return -1;
+
+               /*
+                * Use random number R per the RFC 4346, 6.2.3.2 CBC Block
+                * Cipher option 2a.
+                */
+
+               if (os_get_random(pos, rl->iv_size))
+                       return -1;
+               pos += rl->iv_size;
+       }
+
+       /*
+        * opaque fragment[TLSPlaintext.length]
+        * (opaque content[TLSCompressed.length] in GenericBlockCipher)
+        */
+       if (pos + payload_len > buf + buf_size)
+               return -1;
+       os_memmove(pos, payload, payload_len);
        pos += payload_len;
 
        if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
+               /*
+                * MAC calculated over seq_num + TLSCompressed.type +
+                * TLSCompressed.version + TLSCompressed.length +
+                * TLSCompressed.fragment
+                */
                hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret,
                                        rl->hash_size);
                if (hmac == NULL) {
@@ -182,7 +219,8 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
                }
                crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN);
                /* type + version + length + fragment */
-               crypto_hash_update(hmac, ct_start, pos - ct_start);
+               crypto_hash_update(hmac, ct_start, TLS_RECORD_HEADER_LEN);
+               crypto_hash_update(hmac, payload, payload_len);
                clen = buf + buf_size - pos;
                if (clen < rl->hash_size) {
                        wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
@@ -200,7 +238,7 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
                            pos, clen);
                pos += clen;
                if (rl->iv_size) {
-                       size_t len = pos - payload;
+                       size_t len = pos - cpayload;
                        size_t pad;
                        pad = (len + 1) % rl->iv_size;
                        if (pad)
@@ -214,8 +252,8 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
                        pos += pad + 1;
                }
 
-               if (crypto_cipher_encrypt(rl->write_cbc, payload,
-                                         payload, pos - payload) < 0)
+               if (crypto_cipher_encrypt(rl->write_cbc, cpayload,
+                                         cpayload, pos - cpayload) < 0)
                        return -1;
        }
 
@@ -237,7 +275,8 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
  * @out_len: Set to maximum out_data length by caller; used to return the
  * length of the used data
  * @alert: Buffer for returning an alert value on failure
- * Returns: 0 on success, -1 on failure
+ * Returns: Number of bytes used from in_data on success, 0 if record was not
+ *     complete (more data needed), or -1 on failure
  *
  * This function decrypts the received message, verifies HMAC and TLS record
  * layer header.
@@ -250,40 +289,35 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
        u8 padlen;
        struct crypto_hash *hmac;
        u8 len[2], hash[100];
-
-       wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
-                   in_data, in_len);
+       int force_mac_error = 0;
+       u8 ct;
 
        if (in_len < TLS_RECORD_HEADER_LEN) {
-               wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)",
+               wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu) - "
+                          "need more data",
                           (unsigned long) in_len);
-               *alert = TLS_ALERT_DECODE_ERROR;
-               return -1;
+               wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
+                           in_data, in_len);
+               return 0;
        }
 
+       ct = in_data[0];
+       rlen = WPA_GET_BE16(in_data + 3);
        wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d "
-                  "length %d", in_data[0], in_data[1], in_data[2],
-                  WPA_GET_BE16(in_data + 3));
-
-       if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE &&
-           in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
-           in_data[0] != TLS_CONTENT_TYPE_ALERT &&
-           in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
-               wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x",
-                          in_data[0]);
-               *alert = TLS_ALERT_UNEXPECTED_MESSAGE;
-               return -1;
-       }
-
-       if (WPA_GET_BE16(in_data + 1) != TLS_VERSION) {
+                  "length %d", ct, in_data[1], in_data[2], (int) rlen);
+
+       /*
+        * TLS v1.0 and v1.1 RFCs were not exactly clear on the use of the
+        * protocol version in record layer. As such, accept any {03,xx} value
+        * to remain compatible with existing implementations.
+        */
+       if (in_data[1] != 0x03) {
                wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version "
-                          "%d.%d", in_data[1], in_data[2]);
+                          "%u.%u", in_data[1], in_data[2]);
                *alert = TLS_ALERT_PROTOCOL_VERSION;
                return -1;
        }
 
-       rlen = WPA_GET_BE16(in_data + 3);
-
        /* TLSCiphertext must not be more than 2^14+2048 bytes */
        if (TLS_RECORD_HEADER_LEN + rlen > 18432) {
                wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
@@ -299,7 +333,19 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
                wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included "
                           "(rlen=%lu > in_len=%lu)",
                           (unsigned long) rlen, (unsigned long) in_len);
-               *alert = TLS_ALERT_DECODE_ERROR;
+               return 0;
+       }
+
+       wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
+                   in_data, rlen);
+
+       if (ct != TLS_CONTENT_TYPE_HANDSHAKE &&
+           ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
+           ct != TLS_CONTENT_TYPE_ALERT &&
+           ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+               wpa_printf(MSG_DEBUG, "TLSv1: Ignore record with unknown "
+                          "content type 0x%x", ct);
+               *alert = TLS_ALERT_UNEXPECTED_MESSAGE;
                return -1;
        }
 
@@ -312,58 +358,86 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
                return -1;
        }
 
-       os_memcpy(out_data, in_data, in_len);
-       *out_len = in_len;
-
        if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
-               if (crypto_cipher_decrypt(rl->read_cbc, out_data,
+               size_t plen;
+               if (crypto_cipher_decrypt(rl->read_cbc, in_data,
                                          out_data, in_len) < 0) {
                        *alert = TLS_ALERT_DECRYPTION_FAILED;
                        return -1;
                }
+               plen = in_len;
+               wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted "
+                               "data", out_data, plen);
+
                if (rl->iv_size) {
-                       if (in_len == 0) {
+                       /*
+                        * TLS v1.0 defines different alert values for various
+                        * failures. That may information to aid in attacks, so
+                        * use the same bad_record_mac alert regardless of the
+                        * issues.
+                        *
+                        * In addition, instead of returning immediately on
+                        * error, run through the MAC check to make timing
+                        * attacks more difficult.
+                        */
+
+                       if (rl->tls_version >= TLS_VERSION_1_1) {
+                               /* Remove opaque IV[Cipherspec.block_length] */
+                               if (plen < rl->iv_size) {
+                                       wpa_printf(MSG_DEBUG, "TLSv1.1: Not "
+                                                  "enough room for IV");
+                                       force_mac_error = 1;
+                                       goto check_mac;
+                               }
+                               os_memmove(out_data, out_data + rl->iv_size,
+                                          plen - rl->iv_size);
+                               plen -= rl->iv_size;
+                       }
+
+                       /* Verify and remove padding */
+                       if (plen == 0) {
                                wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
                                           " (no pad)");
-                               *alert = TLS_ALERT_DECODE_ERROR;
-                               return -1;
+                               force_mac_error = 1;
+                               goto check_mac;
                        }
-                       padlen = out_data[in_len - 1];
-                       if (padlen >= in_len) {
+                       padlen = out_data[plen - 1];
+                       if (padlen >= plen) {
                                wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad "
-                                          "length (%u, in_len=%lu) in "
+                                          "length (%u, plen=%lu) in "
                                           "received record",
-                                          padlen, (unsigned long) in_len);
-                               *alert = TLS_ALERT_DECRYPTION_FAILED;
-                               return -1;
+                                          padlen, (unsigned long) plen);
+                               force_mac_error = 1;
+                               goto check_mac;
                        }
-                       for (i = in_len - padlen; i < in_len; i++) {
+                       for (i = plen - padlen - 1; i < plen - 1; i++) {
                                if (out_data[i] != padlen) {
                                        wpa_hexdump(MSG_DEBUG,
                                                    "TLSv1: Invalid pad in "
                                                    "received record",
-                                                   out_data + in_len - padlen,
-                                                   padlen);
-                                       *alert = TLS_ALERT_DECRYPTION_FAILED;
-                                       return -1;
+                                                   out_data + plen - padlen -
+                                                   1, padlen + 1);
+                                       force_mac_error = 1;
+                                       goto check_mac;
                                }
                        }
 
-                       *out_len -= padlen + 1;
-               }
+                       plen -= padlen + 1;
 
-               wpa_hexdump(MSG_MSGDUMP,
-                           "TLSv1: Record Layer - Decrypted data",
-                           out_data, in_len);
+                       wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - "
+                                       "Decrypted data with IV and padding "
+                                       "removed", out_data, plen);
+               }
 
-               if (*out_len < rl->hash_size) {
+       check_mac:
+               if (plen < rl->hash_size) {
                        wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
                                   "hash value");
-                       *alert = TLS_ALERT_INTERNAL_ERROR;
+                       *alert = TLS_ALERT_BAD_RECORD_MAC;
                        return -1;
                }
 
-               *out_len -= rl->hash_size;
+               plen -= rl->hash_size;
 
                hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret,
                                        rl->hash_size);
@@ -377,22 +451,30 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
                crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN);
                /* type + version + length + fragment */
                crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3);
-               WPA_PUT_BE16(len, *out_len);
+               WPA_PUT_BE16(len, plen);
                crypto_hash_update(hmac, len, 2);
-               crypto_hash_update(hmac, out_data, *out_len);
+               crypto_hash_update(hmac, out_data, plen);
                hlen = sizeof(hash);
                if (crypto_hash_finish(hmac, hash, &hlen) < 0) {
                        wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
                                   "to calculate HMAC");
+                       *alert = TLS_ALERT_INTERNAL_ERROR;
                        return -1;
                }
                if (hlen != rl->hash_size ||
-                   os_memcmp(hash, out_data + *out_len, hlen) != 0) {
+                   os_memcmp(hash, out_data + plen, hlen) != 0 ||
+                   force_mac_error) {
                        wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
-                                  "received message");
+                                  "received message (force_mac_error=%d)",
+                                  force_mac_error);
                        *alert = TLS_ALERT_BAD_RECORD_MAC;
                        return -1;
                }
+
+               *out_len = plen;
+       } else {
+               os_memcpy(out_data, in_data, in_len);
+               *out_len = in_len;
        }
 
        /* TLSCompressed must not be more than 2^14+1024 bytes */
@@ -405,5 +487,5 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
 
        inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN);
 
-       return 0;
+       return TLS_RECORD_HEADER_LEN + rlen;
 }
index 9c7c0a4..9eb9bfd 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * TLSv1 Record Protocol
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * 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
@@ -17,7 +17,7 @@
 
 #include "crypto/crypto.h"
 
-#define TLS_MAX_WRITE_MAC_SECRET_LEN 20
+#define TLS_MAX_WRITE_MAC_SECRET_LEN 32
 #define TLS_MAX_WRITE_KEY_LEN 32
 #define TLS_MAX_IV_LEN 16
 #define TLS_MAX_KEY_BLOCK_LEN (2 * (TLS_MAX_WRITE_MAC_SECRET_LEN + \
@@ -35,6 +35,8 @@ enum {
 };
 
 struct tlsv1_record_layer {
+       u16 tls_version;
+
        u8 write_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
        u8 read_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
        u8 write_key[TLS_MAX_WRITE_KEY_LEN];
@@ -66,7 +68,8 @@ int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
 int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl);
 int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl);
 int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
-                     size_t buf_size, size_t payload_len, size_t *out_len);
+                     size_t buf_size, const u8 *payload, size_t payload_len,
+                     size_t *out_len);
 int tlsv1_record_receive(struct tlsv1_record_layer *rl,
                         const u8 *in_data, size_t in_len,
                         u8 *out_data, size_t *out_len, u8 *alert);
index 6a61235..96e160c 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * TLSv1 server (RFC 2246)
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * 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
@@ -49,7 +49,8 @@ int tlsv1_server_derive_keys(struct tlsv1_server *conn,
                os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
                os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
                          TLS_RANDOM_LEN);
-               if (tls_prf(pre_master_secret, pre_master_secret_len,
+               if (tls_prf(conn->rl.tls_version,
+                           pre_master_secret, pre_master_secret_len,
                            "master secret", seed, 2 * TLS_RANDOM_LEN,
                            conn->master_secret, TLS_MASTER_SECRET_LEN)) {
                        wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
@@ -64,7 +65,8 @@ int tlsv1_server_derive_keys(struct tlsv1_server *conn,
        os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
        key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
                             conn->rl.iv_size);
-       if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+       if (tls_prf(conn->rl.tls_version,
+                   conn->master_secret, TLS_MASTER_SECRET_LEN,
                    "key expansion", seed, 2 * TLS_RANDOM_LEN,
                    key_block, key_block_len)) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
@@ -115,6 +117,7 @@ u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
        const u8 *pos, *end;
        u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
        size_t in_msg_len;
+       int used;
 
        if (in_data == NULL || in_len == 0) {
                wpa_printf(MSG_DEBUG, "TLSv1: No input data to server");
@@ -130,13 +133,21 @@ u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
        /* Each received packet may include multiple records */
        while (pos < end) {
                in_msg_len = in_len;
-               if (tlsv1_record_receive(&conn->rl, pos, end - pos,
-                                        in_msg, &in_msg_len, &alert)) {
+               used = tlsv1_record_receive(&conn->rl, pos, end - pos,
+                                           in_msg, &in_msg_len, &alert);
+               if (used < 0) {
                        wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
                                   "record failed");
                        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
                        goto failed;
                }
+               if (used == 0) {
+                       /* need more data */
+                       wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
+                                  "yet supported");
+                       tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+                       goto failed;
+               }
                ct = pos[0];
 
                in_pos = in_msg;
@@ -152,7 +163,7 @@ u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
                        in_pos += in_msg_len;
                }
 
-               pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+               pos += used;
        }
 
        os_free(in_msg);
@@ -201,10 +212,8 @@ int tlsv1_server_encrypt(struct tlsv1_server *conn,
        wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
                        in_data, in_len);
 
-       os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len);
-
        if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
-                             out_data, out_len, in_len, &rlen) < 0) {
+                             out_data, out_len, in_data, in_len, &rlen) < 0) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
                tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                                   TLS_ALERT_INTERNAL_ERROR);
@@ -232,8 +241,8 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
                         u8 *out_data, size_t out_len)
 {
        const u8 *in_end, *pos;
-       int res;
-       u8 alert, *out_end, *out_pos;
+       int used;
+       u8 alert, *out_end, *out_pos, ct;
        size_t olen;
 
        pos = in_data;
@@ -242,7 +251,46 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
        out_end = out_data + out_len;
 
        while (pos < in_end) {
-               if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+               ct = pos[0];
+               olen = out_end - out_pos;
+               used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
+                                           out_pos, &olen, &alert);
+               if (used < 0) {
+                       wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
+                                  "failed");
+                       tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+                       return -1;
+               }
+               if (used == 0) {
+                       /* need more data */
+                       wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
+                                  "yet supported");
+                       tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+                       return -1;
+               }
+
+               if (ct == TLS_CONTENT_TYPE_ALERT) {
+                       if (olen < 2) {
+                               wpa_printf(MSG_DEBUG, "TLSv1: Alert "
+                                          "underflow");
+                               tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                                  TLS_ALERT_DECODE_ERROR);
+                               return -1;
+                       }
+                       wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
+                                  out_pos[0], out_pos[1]);
+                       if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
+                               /* Continue processing */
+                               pos += used;
+                               continue;
+                       }
+
+                       tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                          out_pos[1]);
+                       return -1;
+               }
+
+               if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
                        wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
                                   "0x%x", pos[0]);
                        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -250,15 +298,6 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
                        return -1;
                }
 
-               olen = out_end - out_pos;
-               res = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
-                                          out_pos, &olen, &alert);
-               if (res < 0) {
-                       wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
-                                  "failed");
-                       tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
-                       return -1;
-               }
                out_pos += olen;
                if (out_pos > out_end) {
                        wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
@@ -268,7 +307,7 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
                        return -1;
                }
 
-               pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+               pos += used;
        }
 
        return out_pos - out_data;
@@ -412,7 +451,8 @@ int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
                          TLS_RANDOM_LEN);
        }
 
-       return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+       return tls_prf(conn->rl.tls_version,
+                      conn->master_secret, TLS_MASTER_SECRET_LEN,
                       label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
 }
 
index 00c536c..daa4353 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * TLSv1 server (RFC 2246)
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * 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
index 49e811f..443c028 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * TLSv1 server - read handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * 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
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
+#include "crypto/sha256.h"
 #include "crypto/tls.h"
 #include "x509v3.h"
 #include "tlsv1_common.h"
@@ -85,15 +86,30 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
        conn->client_version = WPA_GET_BE16(pos);
        wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d",
                   conn->client_version >> 8, conn->client_version & 0xff);
-       if (conn->client_version < TLS_VERSION) {
+       if (conn->client_version < TLS_VERSION_1) {
                wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
-                          "ClientHello");
+                          "ClientHello %u.%u",
+                          conn->client_version >> 8,
+                          conn->client_version & 0xff);
                tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                                   TLS_ALERT_PROTOCOL_VERSION);
                return -1;
        }
        pos += 2;
 
+       if (TLS_VERSION == TLS_VERSION_1)
+               conn->rl.tls_version = TLS_VERSION_1;
+#ifdef CONFIG_TLSV12
+       else if (conn->client_version >= TLS_VERSION_1_2)
+               conn->rl.tls_version = TLS_VERSION_1_2;
+#endif /* CONFIG_TLSV12 */
+       else if (conn->client_version > TLS_VERSION_1_1)
+               conn->rl.tls_version = TLS_VERSION_1_1;
+       else
+               conn->rl.tls_version = conn->client_version;
+       wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s",
+                  tls_version_str(conn->rl.tls_version));
+
        /* Random random */
        if (end - pos < TLS_RANDOM_LEN)
                goto decode_error;
@@ -424,7 +440,7 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
        }
 
        if (x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
-                                           &reason) < 0) {
+                                           &reason, 0) < 0) {
                int tls_reason;
                wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
                           "validation failed (reason=%d)", reason);
@@ -483,6 +499,14 @@ static int tls_process_client_key_exchange_rsa(
 
        encr_len = WPA_GET_BE16(pos);
        pos += 2;
+       if (pos + encr_len > end) {
+               wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientKeyExchange "
+                          "format: encr_len=%u left=%u",
+                          encr_len, (unsigned int) (end - pos));
+               tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                  TLS_ALERT_DECODE_ERROR);
+               return -1;
+       }
 
        outbuflen = outlen = end - pos;
        out = os_malloc(outlen >= TLS_PRE_MASTER_SECRET_LEN ?
@@ -512,21 +536,21 @@ static int tls_process_client_key_exchange_rsa(
         */
 
        if (crypto_private_key_decrypt_pkcs1_v15(conn->cred->key,
-                                                pos, end - pos,
+                                                pos, encr_len,
                                                 out, &outlen) < 0) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt "
-                          "PreMasterSecret (encr_len=%d outlen=%lu)",
-                          (int) (end - pos), (unsigned long) outlen);
+                          "PreMasterSecret (encr_len=%u outlen=%lu)",
+                          encr_len, (unsigned long) outlen);
                use_random = 1;
        }
 
-       if (outlen != TLS_PRE_MASTER_SECRET_LEN) {
+       if (!use_random && outlen != TLS_PRE_MASTER_SECRET_LEN) {
                wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret "
                           "length %lu", (unsigned long) outlen);
                use_random = 1;
        }
 
-       if (WPA_GET_BE16(out) != conn->client_version) {
+       if (!use_random && WPA_GET_BE16(out) != conn->client_version) {
                wpa_printf(MSG_DEBUG, "TLSv1: Client version in "
                           "ClientKeyExchange does not match with version in "
                           "ClientHello");
@@ -822,6 +846,47 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
 
        hpos = hash;
 
+#ifdef CONFIG_TLSV12
+       if (conn->rl.tls_version == TLS_VERSION_1_2) {
+               /*
+                * RFC 5246, 4.7:
+                * TLS v1.2 adds explicit indication of the used signature and
+                * hash algorithms.
+                *
+                * struct {
+                *   HashAlgorithm hash;
+                *   SignatureAlgorithm signature;
+                * } SignatureAndHashAlgorithm;
+                */
+               if (end - pos < 2) {
+                       tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                          TLS_ALERT_DECODE_ERROR);
+                       return -1;
+               }
+               if (pos[0] != TLS_HASH_ALG_SHA256 ||
+                   pos[1] != TLS_SIGN_ALG_RSA) {
+                       wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/"
+                                  "signature(%u) algorithm",
+                                  pos[0], pos[1]);
+                       tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                          TLS_ALERT_INTERNAL_ERROR);
+                       return -1;
+               }
+               pos += 2;
+
+               hlen = SHA256_MAC_LEN;
+               if (conn->verify.sha256_cert == NULL ||
+                   crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) <
+                   0) {
+                       conn->verify.sha256_cert = NULL;
+                       tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                          TLS_ALERT_INTERNAL_ERROR);
+                       return -1;
+               }
+               conn->verify.sha256_cert = NULL;
+       } else {
+#endif /* CONFIG_TLSV12 */
+
        if (alg == SIGN_ALG_RSA) {
                hlen = MD5_MAC_LEN;
                if (conn->verify.md5_cert == NULL ||
@@ -852,6 +917,10 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
        if (alg == SIGN_ALG_RSA)
                hlen += MD5_MAC_LEN;
 
+#ifdef CONFIG_TLSV12
+       }
+#endif /* CONFIG_TLSV12 */
+
        wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
 
        if (end - pos < 2) {
@@ -891,6 +960,41 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
        wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
                        buf, buflen);
 
+#ifdef CONFIG_TLSV12
+       if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+               /*
+                * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+                *
+                * DigestInfo ::= SEQUENCE {
+                *   digestAlgorithm DigestAlgorithm,
+                *   digest OCTET STRING
+                * }
+                *
+                * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+                *
+                * DER encoded DigestInfo for SHA256 per RFC 3447:
+                * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
+                * H
+                */
+               if (buflen >= 19 + 32 &&
+                   os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
+                             "\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
+               {
+                       wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = "
+                                  "SHA-256");
+                       os_memmove(buf, buf + 19, buflen - 19);
+                       buflen -= 19;
+               } else {
+                       wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized "
+                                  "DigestInfo");
+                       os_free(buf);
+                       tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                          TLS_ALERT_DECRYPT_ERROR);
+                       return -1;
+               }
+       }
+#endif /* CONFIG_TLSV12 */
+
        if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) {
                wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in "
                           "CertificateVerify - did not match with calculated "
@@ -1022,6 +1126,21 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
        wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
                    pos, TLS_VERIFY_DATA_LEN);
 
+#ifdef CONFIG_TLSV12
+       if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+               hlen = SHA256_MAC_LEN;
+               if (conn->verify.sha256_client == NULL ||
+                   crypto_hash_finish(conn->verify.sha256_client, hash, &hlen)
+                   < 0) {
+                       tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                          TLS_ALERT_INTERNAL_ERROR);
+                       conn->verify.sha256_client = NULL;
+                       return -1;
+               }
+               conn->verify.sha256_client = NULL;
+       } else {
+#endif /* CONFIG_TLSV12 */
+
        hlen = MD5_MAC_LEN;
        if (conn->verify.md5_client == NULL ||
            crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
@@ -1043,9 +1162,15 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
                return -1;
        }
        conn->verify.sha1_client = NULL;
+       hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
+
+#ifdef CONFIG_TLSV12
+       }
+#endif /* CONFIG_TLSV12 */
 
-       if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-                   "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
+       if (tls_prf(conn->rl.tls_version,
+                   conn->master_secret, TLS_MASTER_SECRET_LEN,
+                   "client finished", hash, hlen,
                    verify_data, TLS_VERIFY_DATA_LEN)) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
                tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
index 6d1df7f..0ca3b23 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * TLSv1 server - write handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * 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
@@ -17,7 +17,9 @@
 #include "common.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
+#include "crypto/sha256.h"
 #include "crypto/tls.h"
+#include "crypto/random.h"
 #include "x509v3.h"
 #include "tlsv1_common.h"
 #include "tlsv1_record.h"
@@ -58,7 +60,7 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
 
        os_get_time(&now);
        WPA_PUT_BE32(conn->server_random, now.sec);
-       if (os_get_random(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
+       if (random_get_bytes(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
                wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
                           "server_random");
                return -1;
@@ -67,7 +69,7 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
                    conn->server_random, TLS_RANDOM_LEN);
 
        conn->session_id_len = TLS_SESSION_ID_MAX_LEN;
-       if (os_get_random(conn->session_id, conn->session_id_len)) {
+       if (random_get_bytes(conn->session_id, conn->session_id_len)) {
                wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
                           "session_id");
                return -1;
@@ -86,7 +88,7 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
        pos += 3;
        /* body - ServerHello */
        /* ProtocolVersion server_version */
-       WPA_PUT_BE16(pos, TLS_VERSION);
+       WPA_PUT_BE16(pos, conn->rl.tls_version);
        pos += 2;
        /* Random random: uint32 gmt_unix_time, opaque random_bytes */
        os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN);
@@ -142,7 +144,8 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
        tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
 
        if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-                             rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+                             rhdr, end - rhdr, hs_start, pos - hs_start,
+                             &rlen) < 0) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
                tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                                   TLS_ALERT_INTERNAL_ERROR);
@@ -226,7 +229,8 @@ static int tls_write_server_certificate(struct tlsv1_server *conn,
        WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
        if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-                             rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+                             rhdr, end - rhdr, hs_start, pos - hs_start,
+                             &rlen) < 0) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
                tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                                   TLS_ALERT_INTERNAL_ERROR);
@@ -287,7 +291,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
                                   TLS_ALERT_INTERNAL_ERROR);
                return -1;
        }
-       if (os_get_random(conn->dh_secret, conn->dh_secret_len)) {
+       if (random_get_bytes(conn->dh_secret, conn->dh_secret_len)) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
                           "data for Diffie-Hellman");
                tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -417,7 +421,8 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
        WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
        if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-                             rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+                             rhdr, end - rhdr, hs_start, pos - hs_start,
+                             &rlen) < 0) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
                tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                                   TLS_ALERT_INTERNAL_ERROR);
@@ -482,7 +487,8 @@ static int tls_write_server_certificate_request(struct tlsv1_server *conn,
        WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
        if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-                             rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+                             rhdr, end - rhdr, hs_start, pos - hs_start,
+                             &rlen) < 0) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
                tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                                   TLS_ALERT_INTERNAL_ERROR);
@@ -501,40 +507,35 @@ static int tls_write_server_certificate_request(struct tlsv1_server *conn,
 static int tls_write_server_hello_done(struct tlsv1_server *conn,
                                       u8 **msgpos, u8 *end)
 {
-       u8 *pos, *rhdr, *hs_start, *hs_length;
+       u8 *pos;
        size_t rlen;
-
-       pos = *msgpos;
+       u8 payload[4];
 
        wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone");
-       rhdr = pos;
-       pos += TLS_RECORD_HEADER_LEN;
 
        /* opaque fragment[TLSPlaintext.length] */
 
        /* Handshake */
-       hs_start = pos;
+       pos = payload;
        /* HandshakeType msg_type */
        *pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE;
-       /* uint24 length (to be filled) */
-       hs_length = pos;
+       /* uint24 length */
+       WPA_PUT_BE24(pos, 0);
        pos += 3;
        /* body - ServerHelloDone (empty) */
 
-       WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-
        if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-                             rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+                             *msgpos, end - *msgpos, payload, pos - payload,
+                             &rlen) < 0) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
                tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                                   TLS_ALERT_INTERNAL_ERROR);
                return -1;
        }
-       pos = rhdr + rlen;
 
-       tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+       tls_verify_hash_add(&conn->verify, payload, pos - payload);
 
-       *msgpos = pos;
+       *msgpos += rlen;
 
        return 0;
 }
@@ -543,17 +544,16 @@ static int tls_write_server_hello_done(struct tlsv1_server *conn,
 static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
                                               u8 **msgpos, u8 *end)
 {
-       u8 *pos, *rhdr;
        size_t rlen;
-
-       pos = *msgpos;
+       u8 payload[1];
 
        wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
-       rhdr = pos;
-       pos += TLS_RECORD_HEADER_LEN;
-       *pos = TLS_CHANGE_CIPHER_SPEC;
+
+       payload[0] = TLS_CHANGE_CIPHER_SPEC;
+
        if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
-                             rhdr, end - rhdr, 1, &rlen) < 0) {
+                             *msgpos, end - *msgpos, payload, sizeof(payload),
+                             &rlen) < 0) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
                tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                                   TLS_ALERT_INTERNAL_ERROR);
@@ -568,7 +568,7 @@ static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
                return -1;
        }
 
-       *msgpos = rhdr + rlen;
+       *msgpos += rlen;
 
        return 0;
 }
@@ -577,9 +577,9 @@ static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
 static int tls_write_server_finished(struct tlsv1_server *conn,
                                     u8 **msgpos, u8 *end)
 {
-       u8 *pos, *rhdr, *hs_start, *hs_length;
+       u8 *pos, *hs_start;
        size_t rlen, hlen;
-       u8 verify_data[TLS_VERIFY_DATA_LEN];
+       u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN];
        u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
 
        pos = *msgpos;
@@ -588,6 +588,21 @@ static int tls_write_server_finished(struct tlsv1_server *conn,
 
        /* Encrypted Handshake Message: Finished */
 
+#ifdef CONFIG_TLSV12
+       if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+               hlen = SHA256_MAC_LEN;
+               if (conn->verify.sha256_server == NULL ||
+                   crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
+                   < 0) {
+                       conn->verify.sha256_server = NULL;
+                       tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                          TLS_ALERT_INTERNAL_ERROR);
+                       return -1;
+               }
+               conn->verify.sha256_server = NULL;
+       } else {
+#endif /* CONFIG_TLSV12 */
+
        hlen = MD5_MAC_LEN;
        if (conn->verify.md5_server == NULL ||
            crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
@@ -609,43 +624,44 @@ static int tls_write_server_finished(struct tlsv1_server *conn,
                return -1;
        }
        conn->verify.sha1_server = NULL;
+       hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
+
+#ifdef CONFIG_TLSV12
+       }
+#endif /* CONFIG_TLSV12 */
 
-       if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-                   "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
-                   verify_data, TLS_VERIFY_DATA_LEN)) {
+       if (tls_prf(conn->rl.tls_version,
+                   conn->master_secret, TLS_MASTER_SECRET_LEN,
+                   "server finished", hash, hlen,
+                   verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
                tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                                   TLS_ALERT_INTERNAL_ERROR);
                return -1;
        }
        wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
-                       verify_data, TLS_VERIFY_DATA_LEN);
+                       verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
 
-       rhdr = pos;
-       pos += TLS_RECORD_HEADER_LEN;
        /* Handshake */
-       hs_start = pos;
+       pos = hs_start = verify_data;
        /* HandshakeType msg_type */
        *pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
-       /* uint24 length (to be filled) */
-       hs_length = pos;
+       /* uint24 length */
+       WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN);
        pos += 3;
-       os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
        pos += TLS_VERIFY_DATA_LEN;
-       WPA_PUT_BE24(hs_length, pos - hs_length - 3);
        tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
 
        if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-                             rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+                             *msgpos, end - *msgpos, hs_start, pos - hs_start,
+                             &rlen) < 0) {
                wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
                tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                                   TLS_ALERT_INTERNAL_ERROR);
                return -1;
        }
 
-       pos = rhdr + rlen;
-
-       *msgpos = pos;
+       *msgpos += rlen;
 
        return 0;
 }
@@ -770,7 +786,8 @@ u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
        /* ContentType type */
        *pos++ = TLS_CONTENT_TYPE_ALERT;
        /* ProtocolVersion version */
-       WPA_PUT_BE16(pos, TLS_VERSION);
+       WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version :
+                    TLS_VERSION);
        pos += 2;
        /* uint16 length (to be filled) */
        length = pos;
index bc93df6..347f975 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * X.509v3 certificate parsing and processing (RFC 3280 profile)
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * 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
@@ -1834,7 +1834,7 @@ static int x509_valid_issuer(const struct x509_certificate *cert)
  */
 int x509_certificate_chain_validate(struct x509_certificate *trusted,
                                    struct x509_certificate *chain,
-                                   int *reason)
+                                   int *reason, int disable_time_checks)
 {
        long unsigned idx;
        int chain_trusted = 0;
@@ -1854,10 +1854,11 @@ int x509_certificate_chain_validate(struct x509_certificate *trusted,
                if (chain_trusted)
                        continue;
 
-               if ((unsigned long) now.sec <
-                   (unsigned long) cert->not_before ||
-                   (unsigned long) now.sec >
-                   (unsigned long) cert->not_after) {
+               if (!disable_time_checks &&
+                   ((unsigned long) now.sec <
+                    (unsigned long) cert->not_before ||
+                    (unsigned long) now.sec >
+                    (unsigned long) cert->not_after)) {
                        wpa_printf(MSG_INFO, "X509: Certificate not valid "
                                   "(now=%lu not_before=%lu not_after=%lu)",
                                   now.sec, cert->not_before, cert->not_after);
index 37292d7..3e2005b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * X.509v3 certificate parsing and processing
- * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ * 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
@@ -120,7 +120,7 @@ int x509_certificate_check_signature(struct x509_certificate *issuer,
                                     struct x509_certificate *cert);
 int x509_certificate_chain_validate(struct x509_certificate *trusted,
                                    struct x509_certificate *chain,
-                                   int *reason);
+                                   int *reason, int disable_time_checks);
 struct x509_certificate *
 x509_certificate_get_subject(struct x509_certificate *chain,
                             struct x509_name *name);
diff --git a/src/utils/.gitignore b/src/utils/.gitignore
deleted file mode 100644 (file)
index 833734f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-libutils.a
index 527cf3e..0f1f191 100644 (file)
@@ -28,6 +28,9 @@ LIB_OBJS += os_unix.o
 # Pick correct event loop implementation
 LIB_OBJS += eloop.o
 
+# Pick correct edit implementation
+LIB_OBJS += edit.o
+
 #LIB_OBJS += pcsc_funcs.o
 
 libutils.a: $(LIB_OBJS)
index 155bfce..fb1224b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Base64 encoding/decoding (RFC1341)
- * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
+ * 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
@@ -103,8 +103,9 @@ unsigned char * base64_encode(const unsigned char *src, size_t len,
 unsigned char * base64_decode(const unsigned char *src, size_t len,
                              size_t *out_len)
 {
-       unsigned char dtable[256], *out, *pos, in[4], block[4], tmp;
+       unsigned char dtable[256], *out, *pos, block[4], tmp;
        size_t i, count, olen;
+       int pad = 0;
 
        os_memset(dtable, 0x80, 256);
        for (i = 0; i < sizeof(base64_table) - 1; i++)
@@ -131,7 +132,8 @@ unsigned char * base64_decode(const unsigned char *src, size_t len,
                if (tmp == 0x80)
                        continue;
 
-               in[count] = src[i];
+               if (src[i] == '=')
+                       pad++;
                block[count] = tmp;
                count++;
                if (count == 4) {
@@ -139,16 +141,21 @@ unsigned char * base64_decode(const unsigned char *src, size_t len,
                        *pos++ = (block[1] << 4) | (block[2] >> 2);
                        *pos++ = (block[2] << 6) | block[3];
                        count = 0;
+                       if (pad) {
+                               if (pad == 1)
+                                       pos--;
+                               else if (pad == 2)
+                                       pos -= 2;
+                               else {
+                                       /* Invalid padding */
+                                       os_free(out);
+                                       return NULL;
+                               }
+                               break;
+                       }
                }
        }
 
-       if (pos > out) {
-               if (in[2] == '=')
-                       pos -= 2;
-               else if (in[3] == '=')
-                       pos--;
-       }
-
        *out_len = pos - out;
        return out;
 }
index 73312dd..b87a168 100644 (file)
@@ -13,7 +13,7 @@
  */
 
 #ifndef BASE64_H
-#define BASE64_h
+#define BASE64_H
 
 unsigned char * base64_encode(const unsigned char *src, size_t len,
                              size_t *out_len);
index dde3d3c..55d7123 100644 (file)
@@ -29,7 +29,7 @@ static int hex2num(char c)
 }
 
 
-static int hex2byte(const char *hex)
+int hex2byte(const char *hex)
 {
        int a, b;
        a = hex2num(*hex++);
@@ -69,6 +69,30 @@ int hwaddr_aton(const char *txt, u8 *addr)
        return 0;
 }
 
+/**
+ * hwaddr_compact_aton - Convert ASCII string to MAC address (no colon delimitors format)
+ * @txt: MAC address as a string (e.g., "001122334455")
+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
+ * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
+ */
+int hwaddr_compact_aton(const char *txt, u8 *addr)
+{
+       int i;
+
+       for (i = 0; i < 6; i++) {
+               int a, b;
+
+               a = hex2num(*txt++);
+               if (a < 0)
+                       return -1;
+               b = hex2num(*txt++);
+               if (b < 0)
+                       return -1;
+               *addr++ = (a << 4) | b;
+       }
+
+       return 0;
+}
 
 /**
  * hwaddr_aton2 - Convert ASCII string to MAC address (in any known format)
@@ -349,17 +373,25 @@ const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len)
                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 
+        * 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 = '_';
+       }
+#endif
        return ssid_txt;
 }
 
index f17bf69..14ab297 100644 (file)
@@ -320,6 +320,9 @@ static inline unsigned int wpa_swap_32(unsigned int v)
 #ifndef ETH_P_ALL
 #define ETH_P_ALL 0x0003
 #endif
+#ifndef ETH_P_80211_ENCAP
+#define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */
+#endif
 #ifndef ETH_P_PAE
 #define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
 #endif /* ETH_P_PAE */
@@ -402,6 +405,12 @@ void perror(const char *s);
 #ifndef MAC2STR
 #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
 #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+
+/*
+ * Compact form for string representation of MAC address
+ * To be used, e.g., for constructing dbus paths for P2P Devices
+ */
+#define COMPACT_MACSTR "%02x%02x%02x%02x%02x%02x"
 #endif
 
 #ifndef BIT
@@ -436,7 +445,9 @@ typedef u64 __bitwise le64;
 #endif /* __must_check */
 
 int hwaddr_aton(const char *txt, u8 *addr);
+int hwaddr_compact_aton(const char *txt, u8 *addr);
 int hwaddr_aton2(const char *txt, u8 *addr);
+int hex2byte(const char *hex);
 int hexstr2bin(const char *hex, u8 *buf, size_t len);
 void inc_byte_array(u8 *counter, size_t len);
 void wpa_get_ntp_timestamp(u8 *buf);
@@ -459,6 +470,13 @@ static inline int is_zero_ether_addr(const u8 *a)
        return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]);
 }
 
+static inline int is_broadcast_ether_addr(const u8 *a)
+{
+       return (a[0] & a[1] & a[2] & a[3] & a[4] & a[5]) == 0xff;
+}
+
+#define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff"
+
 #include "wpa_debug.h"
 
 
@@ -474,4 +492,11 @@ static inline int is_zero_ether_addr(const u8 *a)
 void * __hide_aliasing_typecast(void *foo);
 #define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a))
 
+#ifdef CONFIG_VALGRIND
+#include <valgrind/memcheck.h>
+#define WPA_MEM_DEFINED(ptr, len) VALGRIND_MAKE_MEM_DEFINED((ptr), (len))
+#else /* CONFIG_VALGRIND */
+#define WPA_MEM_DEFINED(ptr, len) do { } while (0)
+#endif /* CONFIG_VALGRIND */
+
 #endif /* COMMON_H */
diff --git a/src/utils/edit.c b/src/utils/edit.c
new file mode 100644 (file)
index 0000000..c5b17ac
--- /dev/null
@@ -0,0 +1,1178 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+#include <termios.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "list.h"
+#include "edit.h"
+
+#define CMD_BUF_LEN 256
+static char cmdbuf[CMD_BUF_LEN];
+static int cmdbuf_pos = 0;
+static int cmdbuf_len = 0;
+static char currbuf[CMD_BUF_LEN];
+static int currbuf_valid = 0;
+
+#define HISTORY_MAX 100
+
+struct edit_history {
+       struct dl_list list;
+       char str[1];
+};
+
+static struct dl_list history_list;
+static struct edit_history *history_curr;
+
+static void *edit_cb_ctx;
+static void (*edit_cmd_cb)(void *ctx, char *cmd);
+static void (*edit_eof_cb)(void *ctx);
+static char ** (*edit_completion_cb)(void *ctx, const char *cmd, int pos) =
+       NULL;
+
+static struct termios prevt, newt;
+
+
+#define CLEAR_END_LINE "\e[K"
+
+
+void edit_clear_line(void)
+{
+       int i;
+       putchar('\r');
+       for (i = 0; i < cmdbuf_len + 2; i++)
+               putchar(' ');
+}
+
+
+static void move_start(void)
+{
+       cmdbuf_pos = 0;
+       edit_redraw();
+}
+
+
+static void move_end(void)
+{
+       cmdbuf_pos = cmdbuf_len;
+       edit_redraw();
+}
+
+
+static void move_left(void)
+{
+       if (cmdbuf_pos > 0) {
+               cmdbuf_pos--;
+               edit_redraw();
+       }
+}
+
+
+static void move_right(void)
+{
+       if (cmdbuf_pos < cmdbuf_len) {
+               cmdbuf_pos++;
+               edit_redraw();
+       }
+}
+
+
+static void move_word_left(void)
+{
+       while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] == ' ')
+               cmdbuf_pos--;
+       while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] != ' ')
+               cmdbuf_pos--;
+       edit_redraw();
+}
+
+
+static void move_word_right(void)
+{
+       while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] == ' ')
+               cmdbuf_pos++;
+       while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] != ' ')
+               cmdbuf_pos++;
+       edit_redraw();
+}
+
+
+static void delete_left(void)
+{
+       if (cmdbuf_pos == 0)
+               return;
+
+       edit_clear_line();
+       os_memmove(cmdbuf + cmdbuf_pos - 1, cmdbuf + cmdbuf_pos,
+                  cmdbuf_len - cmdbuf_pos);
+       cmdbuf_pos--;
+       cmdbuf_len--;
+       edit_redraw();
+}
+
+
+static void delete_current(void)
+{
+       if (cmdbuf_pos == cmdbuf_len)
+               return;
+
+       edit_clear_line();
+       os_memmove(cmdbuf + cmdbuf_pos, cmdbuf + cmdbuf_pos + 1,
+                  cmdbuf_len - cmdbuf_pos);
+       cmdbuf_len--;
+       edit_redraw();
+}
+
+
+static void delete_word(void)
+{
+       int pos;
+
+       edit_clear_line();
+       pos = cmdbuf_pos;
+       while (pos > 0 && cmdbuf[pos - 1] == ' ')
+               pos--;
+       while (pos > 0 && cmdbuf[pos - 1] != ' ')
+               pos--;
+       os_memmove(cmdbuf + pos, cmdbuf + cmdbuf_pos, cmdbuf_len - cmdbuf_pos);
+       cmdbuf_len -= cmdbuf_pos - pos;
+       cmdbuf_pos = pos;
+       edit_redraw();
+}
+
+
+static void clear_left(void)
+{
+       if (cmdbuf_pos == 0)
+               return;
+
+       edit_clear_line();
+       os_memmove(cmdbuf, cmdbuf + cmdbuf_pos, cmdbuf_len - cmdbuf_pos);
+       cmdbuf_len -= cmdbuf_pos;
+       cmdbuf_pos = 0;
+       edit_redraw();
+}
+
+
+static void clear_right(void)
+{
+       if (cmdbuf_pos == cmdbuf_len)
+               return;
+
+       edit_clear_line();
+       cmdbuf_len = cmdbuf_pos;
+       edit_redraw();
+}
+
+
+static void history_add(const char *str)
+{
+       struct edit_history *h, *match = NULL, *last = NULL;
+       size_t len, count = 0;
+
+       if (str[0] == '\0')
+               return;
+
+       dl_list_for_each(h, &history_list, struct edit_history, list) {
+               if (os_strcmp(str, h->str) == 0) {
+                       match = h;
+                       break;
+               }
+               last = h;
+               count++;
+       }
+
+       if (match) {
+               dl_list_del(&h->list);
+               dl_list_add(&history_list, &h->list);
+               history_curr = h;
+               return;
+       }
+
+       if (count >= HISTORY_MAX && last) {
+               dl_list_del(&last->list);
+               os_free(last);
+       }
+
+       len = os_strlen(str);
+       h = os_zalloc(sizeof(*h) + len);
+       if (h == NULL)
+               return;
+       dl_list_add(&history_list, &h->list);
+       os_strlcpy(h->str, str, len + 1);
+       history_curr = h;
+}
+
+
+static void history_use(void)
+{
+       edit_clear_line();
+       cmdbuf_len = cmdbuf_pos = os_strlen(history_curr->str);
+       os_memcpy(cmdbuf, history_curr->str, cmdbuf_len);
+       edit_redraw();
+}
+
+
+static void history_prev(void)
+{
+       if (history_curr == NULL)
+               return;
+
+       if (history_curr ==
+           dl_list_first(&history_list, struct edit_history, list)) {
+               if (!currbuf_valid) {
+                       cmdbuf[cmdbuf_len] = '\0';
+                       os_memcpy(currbuf, cmdbuf, cmdbuf_len + 1);
+                       currbuf_valid = 1;
+                       history_use();
+                       return;
+               }
+       }
+
+       if (history_curr ==
+           dl_list_last(&history_list, struct edit_history, list))
+               return;
+
+       history_curr = dl_list_entry(history_curr->list.next,
+                                    struct edit_history, list);
+       history_use();
+}
+
+
+static void history_next(void)
+{
+       if (history_curr == NULL ||
+           history_curr ==
+           dl_list_first(&history_list, struct edit_history, list)) {
+               if (currbuf_valid) {
+                       currbuf_valid = 0;
+                       edit_clear_line();
+                       cmdbuf_len = cmdbuf_pos = os_strlen(currbuf);
+                       os_memcpy(cmdbuf, currbuf, cmdbuf_len);
+                       edit_redraw();
+               }
+               return;
+       }
+
+       history_curr = dl_list_entry(history_curr->list.prev,
+                                    struct edit_history, list);
+       history_use();
+}
+
+
+static void history_read(const char *fname)
+{
+       FILE *f;
+       char buf[CMD_BUF_LEN], *pos;
+
+       f = fopen(fname, "r");
+       if (f == NULL)
+               return;
+
+       while (fgets(buf, CMD_BUF_LEN, f)) {
+               for (pos = buf; *pos; pos++) {
+                       if (*pos == '\r' || *pos == '\n') {
+                               *pos = '\0';
+                               break;
+                       }
+               }
+               history_add(buf);
+       }
+
+       fclose(f);
+}
+
+
+static void history_write(const char *fname,
+                         int (*filter_cb)(void *ctx, const char *cmd))
+{
+       FILE *f;
+       struct edit_history *h;
+
+       f = fopen(fname, "w");
+       if (f == NULL)
+               return;
+
+       dl_list_for_each_reverse(h, &history_list, struct edit_history, list) {
+               if (filter_cb && filter_cb(edit_cb_ctx, h->str))
+                       continue;
+               fprintf(f, "%s\n", h->str);
+       }
+
+       fclose(f);
+}
+
+
+static void history_debug_dump(void)
+{
+       struct edit_history *h;
+       edit_clear_line();
+       printf("\r");
+       dl_list_for_each_reverse(h, &history_list, struct edit_history, list)
+               printf("%s%s\n", h == history_curr ? "[C]" : "", h->str);
+       if (currbuf_valid)
+               printf("{%s}\n", currbuf);
+       edit_redraw();
+}
+
+
+static void insert_char(int c)
+{
+       if (cmdbuf_len >= (int) sizeof(cmdbuf) - 1)
+               return;
+       if (cmdbuf_len == cmdbuf_pos) {
+               cmdbuf[cmdbuf_pos++] = c;
+               cmdbuf_len++;
+               putchar(c);
+               fflush(stdout);
+       } else {
+               os_memmove(cmdbuf + cmdbuf_pos + 1, cmdbuf + cmdbuf_pos,
+                          cmdbuf_len - cmdbuf_pos);
+               cmdbuf[cmdbuf_pos++] = c;
+               cmdbuf_len++;
+               edit_redraw();
+       }
+}
+
+
+static void process_cmd(void)
+{
+
+       if (cmdbuf_len == 0) {
+               printf("\n> ");
+               fflush(stdout);
+               return;
+       }
+       printf("\n");
+       cmdbuf[cmdbuf_len] = '\0';
+       history_add(cmdbuf);
+       cmdbuf_pos = 0;
+       cmdbuf_len = 0;
+       edit_cmd_cb(edit_cb_ctx, cmdbuf);
+       printf("> ");
+       fflush(stdout);
+}
+
+
+static void free_completions(char **c)
+{
+       int i;
+       if (c == NULL)
+               return;
+       for (i = 0; c[i]; i++)
+               os_free(c[i]);
+       os_free(c);
+}
+
+
+static int filter_strings(char **c, char *str, size_t len)
+{
+       int i, j;
+
+       for (i = 0, j = 0; c[j]; j++) {
+               if (os_strncasecmp(c[j], str, len) == 0) {
+                       if (i != j) {
+                               c[i] = c[j];
+                               c[j] = NULL;
+                       }
+                       i++;
+               } else {
+                       os_free(c[j]);
+                       c[j] = NULL;
+               }
+       }
+       c[i] = NULL;
+       return i;
+}
+
+
+static int common_len(const char *a, const char *b)
+{
+       int len = 0;
+       while (a[len] && a[len] == b[len])
+               len++;
+       return len;
+}
+
+
+static int max_common_length(char **c)
+{
+       int len, i;
+
+       len = os_strlen(c[0]);
+       for (i = 1; c[i]; i++) {
+               int same = common_len(c[0], c[i]);
+               if (same < len)
+                       len = same;
+       }
+
+       return len;
+}
+
+
+static int cmp_str(const void *a, const void *b)
+{
+       return os_strcmp(* (const char **) a, * (const char **) b);
+}
+
+static void complete(int list)
+{
+       char **c;
+       int i, len, count;
+       int start, end;
+       int room, plen, add_space;
+
+       if (edit_completion_cb == NULL)
+               return;
+
+       cmdbuf[cmdbuf_len] = '\0';
+       c = edit_completion_cb(edit_cb_ctx, cmdbuf, cmdbuf_pos);
+       if (c == NULL)
+               return;
+
+       end = cmdbuf_pos;
+       start = end;
+       while (start > 0 && cmdbuf[start - 1] != ' ')
+               start--;
+       plen = end - start;
+
+       count = filter_strings(c, &cmdbuf[start], plen);
+       if (count == 0) {
+               free_completions(c);
+               return;
+       }
+
+       len = max_common_length(c);
+       if (len <= plen && count > 1) {
+               if (list) {
+                       qsort(c, count, sizeof(char *), cmp_str);
+                       edit_clear_line();
+                       printf("\r");
+                       for (i = 0; c[i]; i++)
+                               printf("%s%s", i > 0 ? " " : "", c[i]);
+                       printf("\n");
+                       edit_redraw();
+               }
+               free_completions(c);
+               return;
+       }
+       len -= plen;
+
+       room = sizeof(cmdbuf) - 1 - cmdbuf_len;
+       if (room < len)
+               len = room;
+       add_space = count == 1 && len < room;
+
+       os_memmove(cmdbuf + cmdbuf_pos + len + add_space, cmdbuf + cmdbuf_pos,
+                  cmdbuf_len - cmdbuf_pos);
+       os_memcpy(&cmdbuf[cmdbuf_pos - plen], c[0], plen + len);
+       if (add_space)
+               cmdbuf[cmdbuf_pos + len] = ' ';
+
+       cmdbuf_pos += len + add_space;
+       cmdbuf_len += len + add_space;
+
+       edit_redraw();
+
+       free_completions(c);
+}
+
+
+enum edit_key_code {
+       EDIT_KEY_NONE = 256,
+       EDIT_KEY_TAB,
+       EDIT_KEY_UP,
+       EDIT_KEY_DOWN,
+       EDIT_KEY_RIGHT,
+       EDIT_KEY_LEFT,
+       EDIT_KEY_ENTER,
+       EDIT_KEY_BACKSPACE,
+       EDIT_KEY_INSERT,
+       EDIT_KEY_DELETE,
+       EDIT_KEY_HOME,
+       EDIT_KEY_END,
+       EDIT_KEY_PAGE_UP,
+       EDIT_KEY_PAGE_DOWN,
+       EDIT_KEY_F1,
+       EDIT_KEY_F2,
+       EDIT_KEY_F3,
+       EDIT_KEY_F4,
+       EDIT_KEY_F5,
+       EDIT_KEY_F6,
+       EDIT_KEY_F7,
+       EDIT_KEY_F8,
+       EDIT_KEY_F9,
+       EDIT_KEY_F10,
+       EDIT_KEY_F11,
+       EDIT_KEY_F12,
+       EDIT_KEY_CTRL_UP,
+       EDIT_KEY_CTRL_DOWN,
+       EDIT_KEY_CTRL_RIGHT,
+       EDIT_KEY_CTRL_LEFT,
+       EDIT_KEY_CTRL_A,
+       EDIT_KEY_CTRL_B,
+       EDIT_KEY_CTRL_D,
+       EDIT_KEY_CTRL_E,
+       EDIT_KEY_CTRL_F,
+       EDIT_KEY_CTRL_G,
+       EDIT_KEY_CTRL_H,
+       EDIT_KEY_CTRL_J,
+       EDIT_KEY_CTRL_K,
+       EDIT_KEY_CTRL_L,
+       EDIT_KEY_CTRL_N,
+       EDIT_KEY_CTRL_O,
+       EDIT_KEY_CTRL_P,
+       EDIT_KEY_CTRL_R,
+       EDIT_KEY_CTRL_T,
+       EDIT_KEY_CTRL_U,
+       EDIT_KEY_CTRL_V,
+       EDIT_KEY_CTRL_W,
+       EDIT_KEY_ALT_UP,
+       EDIT_KEY_ALT_DOWN,
+       EDIT_KEY_ALT_RIGHT,
+       EDIT_KEY_ALT_LEFT,
+       EDIT_KEY_SHIFT_UP,
+       EDIT_KEY_SHIFT_DOWN,
+       EDIT_KEY_SHIFT_RIGHT,
+       EDIT_KEY_SHIFT_LEFT,
+       EDIT_KEY_ALT_SHIFT_UP,
+       EDIT_KEY_ALT_SHIFT_DOWN,
+       EDIT_KEY_ALT_SHIFT_RIGHT,
+       EDIT_KEY_ALT_SHIFT_LEFT,
+       EDIT_KEY_EOF
+};
+
+static void show_esc_buf(const char *esc_buf, char c, int i)
+{
+       edit_clear_line();
+       printf("\rESC buffer '%s' c='%c' [%d]\n", esc_buf, c, i);
+       edit_redraw();
+}
+
+
+static enum edit_key_code esc_seq_to_key1_no(char last)
+{
+       switch (last) {
+       case 'A':
+               return EDIT_KEY_UP;
+       case 'B':
+               return EDIT_KEY_DOWN;
+       case 'C':
+               return EDIT_KEY_RIGHT;
+       case 'D':
+               return EDIT_KEY_LEFT;
+       default:
+               return EDIT_KEY_NONE;
+       }
+}
+
+
+static enum edit_key_code esc_seq_to_key1_shift(char last)
+{
+       switch (last) {
+       case 'A':
+               return EDIT_KEY_SHIFT_UP;
+       case 'B':
+               return EDIT_KEY_SHIFT_DOWN;
+       case 'C':
+               return EDIT_KEY_SHIFT_RIGHT;
+       case 'D':
+               return EDIT_KEY_SHIFT_LEFT;
+       default:
+               return EDIT_KEY_NONE;
+       }
+}
+
+
+static enum edit_key_code esc_seq_to_key1_alt(char last)
+{
+       switch (last) {
+       case 'A':
+               return EDIT_KEY_ALT_UP;
+       case 'B':
+               return EDIT_KEY_ALT_DOWN;
+       case 'C':
+               return EDIT_KEY_ALT_RIGHT;
+       case 'D':
+               return EDIT_KEY_ALT_LEFT;
+       default:
+               return EDIT_KEY_NONE;
+       }
+}
+
+
+static enum edit_key_code esc_seq_to_key1_alt_shift(char last)
+{
+       switch (last) {
+       case 'A':
+               return EDIT_KEY_ALT_SHIFT_UP;
+       case 'B':
+               return EDIT_KEY_ALT_SHIFT_DOWN;
+       case 'C':
+               return EDIT_KEY_ALT_SHIFT_RIGHT;
+       case 'D':
+               return EDIT_KEY_ALT_SHIFT_LEFT;
+       default:
+               return EDIT_KEY_NONE;
+       }
+}
+
+
+static enum edit_key_code esc_seq_to_key1_ctrl(char last)
+{
+       switch (last) {
+       case 'A':
+               return EDIT_KEY_CTRL_UP;
+       case 'B':
+               return EDIT_KEY_CTRL_DOWN;
+       case 'C':
+               return EDIT_KEY_CTRL_RIGHT;
+       case 'D':
+               return EDIT_KEY_CTRL_LEFT;
+       default:
+               return EDIT_KEY_NONE;
+       }
+}
+
+
+static enum edit_key_code esc_seq_to_key1(int param1, int param2, char last)
+{
+       /* ESC-[<param1>;<param2><last> */
+
+       if (param1 < 0 && param2 < 0)
+               return esc_seq_to_key1_no(last);
+
+       if (param1 == 1 && param2 == 2)
+               return esc_seq_to_key1_shift(last);
+
+       if (param1 == 1 && param2 == 3)
+               return esc_seq_to_key1_alt(last);
+
+       if (param1 == 1 && param2 == 4)
+               return esc_seq_to_key1_alt_shift(last);
+
+       if (param1 == 1 && param2 == 5)
+               return esc_seq_to_key1_ctrl(last);
+
+       if (param2 < 0) {
+               if (last != '~')
+                       return EDIT_KEY_NONE;
+               switch (param1) {
+               case 2:
+                       return EDIT_KEY_INSERT;
+               case 3:
+                       return EDIT_KEY_DELETE;
+               case 5:
+                       return EDIT_KEY_PAGE_UP;
+               case 6:
+                       return EDIT_KEY_PAGE_DOWN;
+               case 15:
+                       return EDIT_KEY_F5;
+               case 17:
+                       return EDIT_KEY_F6;
+               case 18:
+                       return EDIT_KEY_F7;
+               case 19:
+                       return EDIT_KEY_F8;
+               case 20:
+                       return EDIT_KEY_F9;
+               case 21:
+                       return EDIT_KEY_F10;
+               case 23:
+                       return EDIT_KEY_F11;
+               case 24:
+                       return EDIT_KEY_F12;
+               }
+       }
+
+       return EDIT_KEY_NONE;
+}
+
+
+static enum edit_key_code esc_seq_to_key2(int param1, int param2, char last)
+{
+       /* ESC-O<param1>;<param2><last> */
+
+       if (param1 >= 0 || param2 >= 0)
+               return EDIT_KEY_NONE;
+
+       switch (last) {
+       case 'F':
+               return EDIT_KEY_END;
+       case 'H':
+               return EDIT_KEY_HOME;
+       case 'P':
+               return EDIT_KEY_F1;
+       case 'Q':
+               return EDIT_KEY_F2;
+       case 'R':
+               return EDIT_KEY_F3;
+       case 'S':
+               return EDIT_KEY_F4;
+       default:
+               return EDIT_KEY_NONE;
+       }
+}
+
+
+static enum edit_key_code esc_seq_to_key(char *seq)
+{
+       char last, *pos;
+       int param1 = -1, param2 = -1;
+       enum edit_key_code ret = EDIT_KEY_NONE;
+
+       last = '\0';
+       for (pos = seq; *pos; pos++)
+               last = *pos;
+
+       if (seq[1] >= '0' && seq[1] <= '9') {
+               param1 = atoi(&seq[1]);
+               pos = os_strchr(seq, ';');
+               if (pos)
+                       param2 = atoi(pos + 1);
+       }
+
+       if (seq[0] == '[')
+               ret = esc_seq_to_key1(param1, param2, last);
+       else if (seq[0] == 'O')
+               ret = esc_seq_to_key2(param1, param2, last);
+
+       if (ret != EDIT_KEY_NONE)
+               return ret;
+
+       edit_clear_line();
+       printf("\rUnknown escape sequence '%s'\n", seq);
+       edit_redraw();
+       return EDIT_KEY_NONE;
+}
+
+
+static enum edit_key_code edit_read_key(int sock)
+{
+       int c;
+       unsigned char buf[1];
+       int res;
+       static int esc = -1;
+       static char esc_buf[7];
+
+       res = read(sock, buf, 1);
+       if (res < 0)
+               perror("read");
+       if (res <= 0)
+               return EDIT_KEY_EOF;
+
+       c = buf[0];
+
+       if (esc >= 0) {
+               if (c == 27 /* ESC */) {
+                       esc = 0;
+                       return EDIT_KEY_NONE;
+               }
+
+               if (esc == 6) {
+                       show_esc_buf(esc_buf, c, 0);
+                       esc = -1;
+               } else {
+                       esc_buf[esc++] = c;
+                       esc_buf[esc] = '\0';
+               }
+       }
+
+       if (esc == 1) {
+               if (esc_buf[0] != '[' && esc_buf[0] != 'O') {
+                       show_esc_buf(esc_buf, c, 1);
+                       esc = -1;
+                       return EDIT_KEY_NONE;
+               } else
+                       return EDIT_KEY_NONE; /* Escape sequence continues */
+       }
+
+       if (esc > 1) {
+               if ((c >= '0' && c <= '9') || c == ';')
+                       return EDIT_KEY_NONE; /* Escape sequence continues */
+
+               if (c == '~' || (c >= 'A' && c <= 'Z')) {
+                       esc = -1;
+                       return esc_seq_to_key(esc_buf);
+               }
+
+               show_esc_buf(esc_buf, c, 2);
+               esc = -1;
+               return EDIT_KEY_NONE;
+       }
+
+       switch (c) {
+       case 1:
+               return EDIT_KEY_CTRL_A;
+       case 2:
+               return EDIT_KEY_CTRL_B;
+       case 4:
+               return EDIT_KEY_CTRL_D;
+       case 5:
+               return EDIT_KEY_CTRL_E;
+       case 6:
+               return EDIT_KEY_CTRL_F;
+       case 7:
+               return EDIT_KEY_CTRL_G;
+       case 8:
+               return EDIT_KEY_CTRL_H;
+       case 9:
+               return EDIT_KEY_TAB;
+       case 10:
+               return EDIT_KEY_CTRL_J;
+       case 13: /* CR */
+               return EDIT_KEY_ENTER;
+       case 11:
+               return EDIT_KEY_CTRL_K;
+       case 12:
+               return EDIT_KEY_CTRL_L;
+       case 14:
+               return EDIT_KEY_CTRL_N;
+       case 15:
+               return EDIT_KEY_CTRL_O;
+       case 16:
+               return EDIT_KEY_CTRL_P;
+       case 18:
+               return EDIT_KEY_CTRL_R;
+       case 20:
+               return EDIT_KEY_CTRL_T;
+       case 21:
+               return EDIT_KEY_CTRL_U;
+       case 22:
+               return EDIT_KEY_CTRL_V;
+       case 23:
+               return EDIT_KEY_CTRL_W;
+       case 27: /* ESC */
+               esc = 0;
+               return EDIT_KEY_NONE;
+       case 127:
+               return EDIT_KEY_BACKSPACE;
+       default:
+               return c;
+       }
+}
+
+
+static char search_buf[21];
+static int search_skip;
+
+static char * search_find(void)
+{
+       struct edit_history *h;
+       size_t len = os_strlen(search_buf);
+       int skip = search_skip;
+
+       if (len == 0)
+               return NULL;
+
+       dl_list_for_each(h, &history_list, struct edit_history, list) {
+               if (os_strstr(h->str, search_buf)) {
+                       if (skip == 0)
+                               return h->str;
+                       skip--;
+               }
+       }
+
+       search_skip = 0;
+       return NULL;
+}
+
+
+static void search_redraw(void)
+{
+       char *match = search_find();
+       printf("\rsearch '%s': %s" CLEAR_END_LINE,
+              search_buf, match ? match : "");
+       printf("\rsearch '%s", search_buf);
+       fflush(stdout);
+}
+
+
+static void search_start(void)
+{
+       edit_clear_line();
+       search_buf[0] = '\0';
+       search_skip = 0;
+       search_redraw();
+}
+
+
+static void search_clear(void)
+{
+       search_redraw();
+       printf("\r" CLEAR_END_LINE);
+}
+
+
+static void search_stop(void)
+{
+       char *match = search_find();
+       search_buf[0] = '\0';
+       search_clear();
+       if (match) {
+               os_strlcpy(cmdbuf, match, CMD_BUF_LEN);
+               cmdbuf_len = os_strlen(cmdbuf);
+               cmdbuf_pos = cmdbuf_len;
+       }
+       edit_redraw();
+}
+
+
+static void search_cancel(void)
+{
+       search_buf[0] = '\0';
+       search_clear();
+       edit_redraw();
+}
+
+
+static void search_backspace(void)
+{
+       size_t len;
+       len = os_strlen(search_buf);
+       if (len == 0)
+               return;
+       search_buf[len - 1] = '\0';
+       search_skip = 0;
+       search_redraw();
+}
+
+
+static void search_next(void)
+{
+       search_skip++;
+       search_find();
+       search_redraw();
+}
+
+
+static void search_char(char c)
+{
+       size_t len;
+       len = os_strlen(search_buf);
+       if (len == sizeof(search_buf) - 1)
+               return;
+       search_buf[len] = c;
+       search_buf[len + 1] = '\0';
+       search_skip = 0;
+       search_redraw();
+}
+
+
+static enum edit_key_code search_key(enum edit_key_code c)
+{
+       switch (c) {
+       case EDIT_KEY_ENTER:
+       case EDIT_KEY_CTRL_J:
+       case EDIT_KEY_LEFT:
+       case EDIT_KEY_RIGHT:
+       case EDIT_KEY_HOME:
+       case EDIT_KEY_END:
+       case EDIT_KEY_CTRL_A:
+       case EDIT_KEY_CTRL_E:
+               search_stop();
+               return c;
+       case EDIT_KEY_DOWN:
+       case EDIT_KEY_UP:
+               search_cancel();
+               return EDIT_KEY_EOF;
+       case EDIT_KEY_CTRL_H:
+       case EDIT_KEY_BACKSPACE:
+               search_backspace();
+               break;
+       case EDIT_KEY_CTRL_R:
+               search_next();
+               break;
+       default:
+               if (c >= 32 && c <= 255)
+                       search_char(c);
+               break;
+       }
+
+       return EDIT_KEY_NONE;
+}
+
+
+static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
+{
+       static int last_tab = 0;
+       static int search = 0;
+       enum edit_key_code c;
+
+       c = edit_read_key(sock);
+
+       if (search) {
+               c = search_key(c);
+               if (c == EDIT_KEY_NONE)
+                       return;
+               search = 0;
+               if (c == EDIT_KEY_EOF)
+                       return;
+       }
+
+       if (c != EDIT_KEY_TAB && c != EDIT_KEY_NONE)
+               last_tab = 0;
+
+       switch (c) {
+       case EDIT_KEY_NONE:
+               break;
+       case EDIT_KEY_EOF:
+               edit_eof_cb(edit_cb_ctx);
+               break;
+       case EDIT_KEY_TAB:
+               complete(last_tab);
+               last_tab = 1;
+               break;
+       case EDIT_KEY_UP:
+       case EDIT_KEY_CTRL_P:
+               history_prev();
+               break;
+       case EDIT_KEY_DOWN:
+       case EDIT_KEY_CTRL_N:
+               history_next();
+               break;
+       case EDIT_KEY_RIGHT:
+       case EDIT_KEY_CTRL_F:
+               move_right();
+               break;
+       case EDIT_KEY_LEFT:
+       case EDIT_KEY_CTRL_B:
+               move_left();
+               break;
+       case EDIT_KEY_CTRL_RIGHT:
+               move_word_right();
+               break;
+       case EDIT_KEY_CTRL_LEFT:
+               move_word_left();
+               break;
+       case EDIT_KEY_DELETE:
+               delete_current();
+               break;
+       case EDIT_KEY_END:
+               move_end();
+               break;
+       case EDIT_KEY_HOME:
+       case EDIT_KEY_CTRL_A:
+               move_start();
+               break;
+       case EDIT_KEY_F2:
+               history_debug_dump();
+               break;
+       case EDIT_KEY_CTRL_D:
+               if (cmdbuf_len > 0) {
+                       delete_current();
+                       return;
+               }
+               printf("\n");
+               edit_eof_cb(edit_cb_ctx);
+               break;
+       case EDIT_KEY_CTRL_E:
+               move_end();
+               break;
+       case EDIT_KEY_CTRL_H:
+       case EDIT_KEY_BACKSPACE:
+               delete_left();
+               break;
+       case EDIT_KEY_ENTER:
+       case EDIT_KEY_CTRL_J:
+               process_cmd();
+               break;
+       case EDIT_KEY_CTRL_K:
+               clear_right();
+               break;
+       case EDIT_KEY_CTRL_L:
+               edit_clear_line();
+               edit_redraw();
+               break;
+       case EDIT_KEY_CTRL_R:
+               search = 1;
+               search_start();
+               break;
+       case EDIT_KEY_CTRL_U:
+               clear_left();
+               break;
+       case EDIT_KEY_CTRL_W:
+               delete_word();
+               break;
+       default:
+               if (c >= 32 && c <= 255)
+                       insert_char(c);
+               break;
+       }
+}
+
+
+int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
+             void (*eof_cb)(void *ctx),
+             char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
+             void *ctx, const char *history_file)
+{
+       currbuf[0] = '\0';
+       dl_list_init(&history_list);
+       history_curr = NULL;
+       if (history_file)
+               history_read(history_file);
+
+       edit_cb_ctx = ctx;
+       edit_cmd_cb = cmd_cb;
+       edit_eof_cb = eof_cb;
+       edit_completion_cb = completion_cb;
+
+       tcgetattr(STDIN_FILENO, &prevt);
+       newt = prevt;
+       newt.c_lflag &= ~(ICANON | ECHO);
+       tcsetattr(STDIN_FILENO, TCSANOW, &newt);
+
+       eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
+
+       printf("> ");
+       fflush(stdout);
+
+       return 0;
+}
+
+
+void edit_deinit(const char *history_file,
+                int (*filter_cb)(void *ctx, const char *cmd))
+{
+       struct edit_history *h;
+       if (history_file)
+               history_write(history_file, filter_cb);
+       while ((h = dl_list_first(&history_list, struct edit_history, list))) {
+               dl_list_del(&h->list);
+               os_free(h);
+       }
+       edit_clear_line();
+       putchar('\r');
+       fflush(stdout);
+       eloop_unregister_read_sock(STDIN_FILENO);
+       tcsetattr(STDIN_FILENO, TCSANOW, &prevt);
+}
+
+
+void edit_redraw(void)
+{
+       char tmp;
+       cmdbuf[cmdbuf_len] = '\0';
+       printf("\r> %s", cmdbuf);
+       if (cmdbuf_pos != cmdbuf_len) {
+               tmp = cmdbuf[cmdbuf_pos];
+               cmdbuf[cmdbuf_pos] = '\0';
+               printf("\r> %s", cmdbuf);
+               cmdbuf[cmdbuf_pos] = tmp;
+       }
+       fflush(stdout);
+}
diff --git a/src/utils/edit.h b/src/utils/edit.h
new file mode 100644 (file)
index 0000000..fc4474b
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+#ifndef EDIT_H
+#define EDIT_H
+
+int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
+             void (*eof_cb)(void *ctx),
+             char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
+             void *ctx, const char *history_file);
+void edit_deinit(const char *history_file,
+                int (*filter_cb)(void *ctx, const char *cmd));
+void edit_clear_line(void);
+void edit_redraw(void);
+
+#endif /* EDIT_H */
diff --git a/src/utils/edit_readline.c b/src/utils/edit_readline.c
new file mode 100644 (file)
index 0000000..1fef7b9
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "edit.h"
+
+
+static void *edit_cb_ctx;
+static void (*edit_cmd_cb)(void *ctx, char *cmd);
+static void (*edit_eof_cb)(void *ctx);
+static char ** (*edit_completion_cb)(void *ctx, const char *cmd, int pos) =
+       NULL;
+
+static char **pending_completions = NULL;
+
+
+static void readline_free_completions(void)
+{
+       int i;
+       if (pending_completions == NULL)
+               return;
+       for (i = 0; pending_completions[i]; i++)
+               os_free(pending_completions[i]);
+       os_free(pending_completions);
+       pending_completions = NULL;
+}
+
+
+static char * readline_completion_func(const char *text, int state)
+{
+       static int pos = 0;
+       static size_t len = 0;
+
+       if (pending_completions == NULL) {
+               rl_attempted_completion_over = 1;
+               return NULL;
+       }
+
+       if (state == 0) {
+               pos = 0;
+               len = os_strlen(text);
+       }
+       for (; pending_completions[pos]; pos++) {
+               if (strncmp(pending_completions[pos], text, len) == 0)
+                       return strdup(pending_completions[pos++]);
+       }
+
+       rl_attempted_completion_over = 1;
+       return NULL;
+}
+
+
+static char ** readline_completion(const char *text, int start, int end)
+{
+       readline_free_completions();
+       if (edit_completion_cb)
+               pending_completions = edit_completion_cb(edit_cb_ctx,
+                                                        rl_line_buffer, end);
+       return rl_completion_matches(text, readline_completion_func);
+}
+
+
+static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
+{
+       rl_callback_read_char();
+}
+
+
+static void trunc_nl(char *str)
+{
+       char *pos = str;
+       while (*pos != '\0') {
+               if (*pos == '\n') {
+                       *pos = '\0';
+                       break;
+               }
+               pos++;
+       }
+}
+
+
+static void readline_cmd_handler(char *cmd)
+{
+       if (cmd && *cmd) {
+               HIST_ENTRY *h;
+               while (next_history())
+                       ;
+               h = previous_history();
+               if (h == NULL || os_strcmp(cmd, h->line) != 0)
+                       add_history(cmd);
+               next_history();
+       }
+       if (cmd == NULL) {
+               edit_eof_cb(edit_cb_ctx);
+               return;
+       }
+       trunc_nl(cmd);
+       edit_cmd_cb(edit_cb_ctx, cmd);
+}
+
+
+int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
+             void (*eof_cb)(void *ctx),
+             char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
+             void *ctx, const char *history_file)
+{
+       edit_cb_ctx = ctx;
+       edit_cmd_cb = cmd_cb;
+       edit_eof_cb = eof_cb;
+       edit_completion_cb = completion_cb;
+
+       rl_attempted_completion_function = readline_completion;
+       if (history_file) {
+               read_history(history_file);
+               stifle_history(100);
+       }
+
+       eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
+
+       rl_callback_handler_install("> ", readline_cmd_handler);
+
+       return 0;
+}
+
+
+void edit_deinit(const char *history_file,
+                int (*filter_cb)(void *ctx, const char *cmd))
+{
+       rl_callback_handler_remove();
+       readline_free_completions();
+
+       eloop_unregister_read_sock(STDIN_FILENO);
+
+       if (history_file) {
+               /* Save command history, excluding lines that may contain
+                * passwords. */
+               HIST_ENTRY *h;
+               history_set_pos(0);
+               while ((h = current_history())) {
+                       char *p = h->line;
+                       while (*p == ' ' || *p == '\t')
+                               p++;
+                       if (filter_cb && filter_cb(edit_cb_ctx, p)) {
+                               h = remove_history(where_history());
+                               if (h) {
+                                       os_free(h->line);
+                                       free(h->data);
+                                       os_free(h);
+                               } else
+                                       next_history();
+                       } else
+                               next_history();
+               }
+               write_history(history_file);
+       }
+}
+
+
+void edit_clear_line(void)
+{
+}
+
+
+void edit_redraw(void)
+{
+       rl_on_new_line();
+       rl_redisplay();
+}
diff --git a/src/utils/edit_simple.c b/src/utils/edit_simple.c
new file mode 100644 (file)
index 0000000..61fb24e
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "edit.h"
+
+
+#define CMD_BUF_LEN 256
+static char cmdbuf[CMD_BUF_LEN];
+static int cmdbuf_pos = 0;
+
+static void *edit_cb_ctx;
+static void (*edit_cmd_cb)(void *ctx, char *cmd);
+static void (*edit_eof_cb)(void *ctx);
+
+
+static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
+{
+       int c;
+       unsigned char buf[1];
+       int res;
+
+       res = read(sock, buf, 1);
+       if (res < 0)
+               perror("read");
+       if (res <= 0) {
+               edit_eof_cb(edit_cb_ctx);
+               return;
+       }
+       c = buf[0];
+
+       if (c == '\r' || c == '\n') {
+               cmdbuf[cmdbuf_pos] = '\0';
+               cmdbuf_pos = 0;
+               edit_cmd_cb(edit_cb_ctx, cmdbuf);
+               printf("> ");
+               fflush(stdout);
+               return;
+       }
+
+       if (c >= 32 && c <= 255) {
+               if (cmdbuf_pos < (int) sizeof(cmdbuf) - 1) {
+                       cmdbuf[cmdbuf_pos++] = c;
+               }
+       }
+}
+
+
+int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
+             void (*eof_cb)(void *ctx),
+             char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
+             void *ctx, const char *history_file)
+{
+       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);
+
+       printf("> ");
+       fflush(stdout);
+
+       return 0;
+}
+
+
+void edit_deinit(const char *history_file,
+                int (*filter_cb)(void *ctx, const char *cmd))
+{
+       eloop_unregister_read_sock(STDIN_FILENO);
+}
+
+
+void edit_clear_line(void)
+{
+}
+
+
+void edit_redraw(void)
+{
+       cmdbuf[cmdbuf_pos] = '\0';
+       printf("\r> %s", cmdbuf);
+}
index 4b61598..b550c63 100644 (file)
@@ -300,6 +300,7 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs,
                           void *eloop_data, void *user_data)
 {
        struct eloop_timeout *timeout, *tmp;
+       os_time_t now_sec;
 
        timeout = os_zalloc(sizeof(*timeout));
        if (timeout == NULL)
@@ -308,7 +309,18 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs,
                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++;
index 1228f24..a656bf8 100644 (file)
@@ -144,7 +144,7 @@ void eloop_unregister_sock(int sock, eloop_event_type type);
  * Returns: 0 on success, -1 on failure
  *
  * Register an event handler for the given event. This function is used to
- * register eloop implementation specific events which are mainly targetted for
+ * register eloop implementation specific events which are mainly targeted for
  * operating system specific code (driver interface and l2_packet) since the
  * portable code will not be able to use such an OS-specific call. The handler
  * function will be called whenever the event is triggered. The handler
index 94cc72d..c726ece 100644 (file)
@@ -243,12 +243,24 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs,
                           void *eloop_data, void *user_data)
 {
        struct eloop_timeout *timeout, *tmp, *prev;
+       os_time_t now_sec;
 
        timeout = os_malloc(sizeof(*timeout));
        if (timeout == NULL)
                return -1;
        os_get_time(&timeout->time);
+       now_sec = timeout->time.sec;
        timeout->time.sec += secs;
+       if (timeout->time.sec < now_sec) {
+               /*
+                * Integer overflow - assume long enough timeout to be assumed
+                * to be infinite, i.e., the timeout would never happen.
+                */
+               wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
+                          "ever happen - ignore it", secs);
+               os_free(timeout);
+               return 0;
+       }
        timeout->time.usec += usecs;
        while (timeout->time.usec >= 1000000) {
                timeout->time.sec++;
index 63b5c23..cf2a42b 100644 (file)
@@ -34,7 +34,6 @@
 #include <errno.h>
 #endif /* _WIN32_WCE */
 #include <ctype.h>
-#include <time.h>
 
 #ifndef CONFIG_TI_COMPILER
 #ifndef _MSC_VER
index ed7c022..c8dccee 100644 (file)
@@ -75,6 +75,10 @@ static inline unsigned int dl_list_len(struct dl_list *list)
        (dl_list_empty((list)) ? NULL : \
         dl_list_entry((list)->next, type, member))
 
+#define dl_list_last(list, type, member) \
+       (dl_list_empty((list)) ? NULL : \
+        dl_list_entry((list)->prev, type, member))
+
 #define dl_list_for_each(item, list, type, member) \
        for (item = dl_list_entry((list)->next, type, member); \
             &item->member != (list); \
@@ -86,4 +90,12 @@ static inline unsigned int dl_list_len(struct dl_list *list)
             &item->member != (list); \
             item = n, n = dl_list_entry(n->member.next, type, member))
 
+#define dl_list_for_each_reverse(item, list, type, member) \
+       for (item = dl_list_entry((list)->prev, type, member); \
+            &item->member != (list); \
+            item = dl_list_entry(item->member.prev, type, member))
+
+#define DEFINE_DL_LIST(name) \
+       struct dl_list name = { &(name), &(name) }
+
 #endif /* LIST_H */
index f4723d8..f69478a 100644 (file)
@@ -70,6 +70,16 @@ int os_get_time(struct os_time *t);
 int os_mktime(int year, int month, int day, int hour, int min, int sec,
              os_time_t *t);
 
+struct os_tm {
+       int sec; /* 0..59 or 60 for leap seconds */
+       int min; /* 0..59 */
+       int hour; /* 0..23 */
+       int day; /* 1..31 */
+       int month; /* 1..12 */
+       int year; /* Four digit year */
+};
+
+int os_gmtime(os_time_t t, struct os_tm *tm);
 
 /**
  * os_daemonize - Run in the background (detach from the controlling terminal)
index 5260e23..8024a30 100644 (file)
@@ -70,6 +70,24 @@ int os_mktime(int year, int month, int day, int hour, int min, int sec,
 }
 
 
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+       struct tm *tm2;
+       time_t t2 = t;
+
+       tm2 = gmtime(&t2);
+       if (tm2 == NULL)
+               return -1;
+       tm->sec = tm2->tm_sec;
+       tm->min = tm2->tm_min;
+       tm->hour = tm2->tm_hour;
+       tm->day = tm2->tm_mday;
+       tm->month = tm2->tm_mon + 1;
+       tm->year = tm2->tm_year + 1900;
+       return 0;
+}
+
+
 int os_daemonize(const char *pid_file)
 {
        if (daemon(0, 0)) {
index bab8f17..3fbb777 100644 (file)
@@ -38,6 +38,11 @@ int os_mktime(int year, int month, int day, int hour, int min, int sec,
        return -1;
 }
 
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+       return -1;
+}
+
 
 int os_daemonize(const char *pid_file)
 {
index 6f58fa4..9b16b33 100644 (file)
 
 #include "includes.h"
 
+#include <time.h>
+
+#ifdef ANDROID
+#include <linux/capability.h>
+#include <linux/prctl.h>
+#include <private/android_filesystem_config.h>
+#endif /* ANDROID */
+
 #include "os.h"
 
 #ifdef WPA_TRACE
 
 #include "common.h"
-#include "list.h"
 #include "wpa_debug.h"
 #include "trace.h"
+#include "list.h"
 
 static struct dl_list alloc_list;
 
@@ -98,6 +106,24 @@ int os_mktime(int year, int month, int day, int hour, int min, int sec,
 }
 
 
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+       struct tm *tm2;
+       time_t t2 = t;
+
+       tm2 = gmtime(&t2);
+       if (tm2 == NULL)
+               return -1;
+       tm->sec = tm2->tm_sec;
+       tm->min = tm2->tm_min;
+       tm->hour = tm2->tm_hour;
+       tm->day = tm2->tm_mday;
+       tm->month = tm2->tm_mon + 1;
+       tm->year = tm2->tm_year + 1900;
+       return 0;
+}
+
+
 #ifdef __APPLE__
 #include <fcntl.h>
 static int os_daemon(int nochdir, int noclose)
@@ -135,9 +161,9 @@ static int os_daemon(int nochdir, int noclose)
 
 int os_daemonize(const char *pid_file)
 {
-#ifdef __uClinux__
+#if defined(__uClinux__) || defined(__sun__)
        return -1;
-#else /* __uClinux__ */
+#else /* defined(__uClinux__) || defined(__sun__) */
        if (os_daemon(0, 0)) {
                perror("daemon");
                return -1;
@@ -152,7 +178,7 @@ int os_daemonize(const char *pid_file)
        }
 
        return -0;
-#endif /* __uClinux__ */
+#endif /* defined(__uClinux__) || defined(__sun__) */
 }
 
 
@@ -232,6 +258,30 @@ char * os_rel2abs_path(const char *rel_path)
 
 int os_program_init(void)
 {
+#ifdef ANDROID
+       /*
+        * We ignore errors here since errors are normal if we
+        * are already running as non-root.
+        */
+       gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE };
+       struct __user_cap_header_struct header;
+       struct __user_cap_data_struct cap;
+
+       setgroups(sizeof(groups)/sizeof(groups[0]), groups);
+
+       prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+
+       setgid(AID_WIFI);
+       setuid(AID_WIFI);
+
+       header.version = _LINUX_CAPABILITY_VERSION;
+       header.pid = 0;
+       cap.effective = cap.permitted =
+               (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
+       cap.inheritable = 0;
+       capset(&header, &cap);
+#endif /* ANDROID */
+
 #ifdef WPA_TRACE
        dl_list_init(&alloc_list);
 #endif /* WPA_TRACE */
@@ -285,14 +335,21 @@ char * os_readfile(const char *name, size_t *len)
 {
        FILE *f;
        char *buf;
+       long pos;
 
        f = fopen(name, "rb");
        if (f == NULL)
                return NULL;
 
-       fseek(f, 0, SEEK_END);
-       *len = ftell(f);
-       fseek(f, 0, SEEK_SET);
+       if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) {
+               fclose(f);
+               return NULL;
+       }
+       *len = pos;
+       if (fseek(f, 0, SEEK_SET) < 0) {
+               fclose(f);
+               return NULL;
+       }
 
        buf = os_malloc(*len);
        if (buf == NULL) {
index 0740964..51bd545 100644 (file)
@@ -13,6 +13,7 @@
  */
 
 #include "includes.h"
+#include <time.h>
 #include <winsock2.h>
 #include <wincrypt.h>
 
@@ -92,6 +93,24 @@ int os_mktime(int year, int month, int day, int hour, int min, int sec,
 }
 
 
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+       struct tm *tm2;
+       time_t t2 = t;
+
+       tm2 = gmtime(&t2);
+       if (tm2 == NULL)
+               return -1;
+       tm->sec = tm2->tm_sec;
+       tm->min = tm2->tm_min;
+       tm->hour = tm2->tm_hour;
+       tm->day = tm2->tm_mday;
+       tm->month = tm2->tm_mon + 1;
+       tm->year = tm2->tm_year + 1900;
+       return 0;
+}
+
+
 int os_daemonize(const char *pid_file)
 {
        /* TODO */
index bf9f04a..c36193e 100644 (file)
@@ -812,7 +812,7 @@ static int scard_get_record_len(struct scard_data *scard, unsigned char recnum,
        wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response",
                    buf, blen);
 
-       if (blen < 2 || buf[0] != 0x6c) {
+       if (blen < 2 || (buf[0] != 0x6c && buf[0] != 0x67)) {
                wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file "
                           "length determination");
                return -1;
index 508264c..137288f 100644 (file)
@@ -238,5 +238,6 @@ enum ieee80211_radiotap_type {
                                                 * retries */
 #define IEEE80211_RADIOTAP_F_TX_CTS    0x0002  /* used cts 'protection' */
 #define IEEE80211_RADIOTAP_F_TX_RTS    0x0004  /* used rts/cts handshake */
+#define IEEE80211_RADIOTAP_F_TX_NOACK  0x0008  /* don't expect an ACK */
 
 #endif                         /* IEEE80211_RADIOTAP_H */
index 92a798a..2e0e872 100644 (file)
@@ -1,3 +1,18 @@
+/*
+ * Radiotap parser
+ *
+ * Copyright 2007              Andy Green <andy@warmcat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
 #ifndef __RADIOTAP_ITER_H
 #define __RADIOTAP_ITER_H
 
index 7084c12..aa7295c 100644 (file)
@@ -23,35 +23,73 @@ static int wpa_debug_syslog = 0;
 #endif /* CONFIG_DEBUG_SYSLOG */
 
 
-#ifdef CONFIG_DEBUG_FILE
-static FILE *out_file = NULL;
-#endif /* CONFIG_DEBUG_FILE */
 int wpa_debug_level = MSG_INFO;
 int wpa_debug_show_keys = 0;
 int wpa_debug_timestamp = 0;
 
 
+#ifdef CONFIG_ANDROID_LOG
+
+#include <android/log.h>
+
+#ifndef ANDROID_LOG_NAME
+#define ANDROID_LOG_NAME       "wpa_supplicant"
+#endif /* ANDROID_LOG_NAME */
+
+void android_printf(int level, char *format, ...)
+{
+       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);
+       }
+}
+
+#else /* 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 
+        * 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 = localtime ( &tv.sec);
-       strftime(time_string,sizeof(time_string), "%Y-%m-%d %H:%M:%S",ptm);
+       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,
@@ -59,13 +97,33 @@ void wpa_debug_print_timestamp(void)
        } else
 #endif /* CONFIG_DEBUG_FILE */
        printf("%s.%06u: ", time_string, (unsigned int) tv.usec);
+#else
+       struct os_time tv;
+
+       if (!wpa_debug_timestamp)
+               return;
+
+       os_get_time(&tv);
+#ifdef CONFIG_DEBUG_FILE
+       if (out_file) {
+               fprintf(out_file, "%ld.%06u: ", (long) tv.sec,
+                       (unsigned int) tv.usec);
+       } else
+#endif /* CONFIG_DEBUG_FILE */
+       printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
+
+#endif
 }
 
 
 #ifdef CONFIG_DEBUG_SYSLOG
+#ifndef LOG_HOSTAPD
+#define LOG_HOSTAPD LOG_DAEMON
+#endif /* LOG_HOSTAPD */
+
 void wpa_debug_open_syslog(void)
 {
-       openlog("wpa_supplicant", LOG_PID | LOG_NDELAY, LOG_DAEMON);
+       openlog("wpa_supplicant", LOG_PID | LOG_NDELAY, LOG_HOSTAPD);
        wpa_debug_syslog++;
 }
 
@@ -95,6 +153,77 @@ 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
+
+static char *__wpa_strdup_vprintf(const char *format, va_list va)
+{
+       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;
+}
+
+static void __wpa_log_update_file_revision(int rev)
+{
+       int next_log_rev = 0;
+       char *log_file = NULL;
+       char *next_log_file = NULL;
+
+       next_log_rev = rev + 1;
+
+       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);
+
+       if (next_log_rev >= MAX_LOG_COUNT)
+               remove(next_log_file);
+
+       if (access(next_log_file, F_OK) == 0)
+               __wpa_log_update_file_revision(next_log_rev);
+
+       if (rename(log_file, next_log_file) != 0)
+               remove(log_file);
+
+       os_free(log_file);
+       os_free(next_log_file);
+}
+
+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);
+
+       if (rename(out_file_name, backup) != 0)
+               remove(out_file_name);
+
+       os_free(backup);
+}
+#endif /* TIZEN_EXT */
+#endif /* CONFIG_DEBUG_FILE */
+
 /**
  * wpa_printf - conditional printf
  * @level: priority level (MSG_*) of the message
@@ -120,6 +249,24 @@ 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 {
@@ -284,17 +431,52 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
 }
 
 
+#ifdef CONFIG_DEBUG_FILE
+static char *last_path = NULL;
+#endif /* CONFIG_DEBUG_FILE */
+
+int wpa_debug_reopen_file(void)
+{
+#ifdef CONFIG_DEBUG_FILE
+       int rv;
+       if (last_path) {
+               char *tmp = os_strdup(last_path);
+               wpa_debug_close_file();
+               rv = wpa_debug_open_file(tmp);
+               os_free(tmp);
+       } else {
+               wpa_printf(MSG_ERROR, "Last-path was not set, cannot "
+                          "re-open log file.");
+               rv = -1;
+       }
+       return rv;
+#else /* CONFIG_DEBUG_FILE */
+       return 0;
+#endif /* CONFIG_DEBUG_FILE */
+}
+
+
 int wpa_debug_open_file(const char *path)
 {
 #ifdef CONFIG_DEBUG_FILE
        if (!path)
                return 0;
+
+       if (last_path == NULL || os_strcmp(last_path, path) != 0) {
+               /* Save our path to enable re-open */
+               os_free(last_path);
+               last_path = os_strdup(path);
+       }
+
        out_file = fopen(path, "a");
        if (out_file == NULL) {
                wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open "
                           "output file, using standard output");
                return -1;
        }
+#if defined TIZEN_EXT
+       out_file_name = os_strdup(path);
+#endif
 #ifndef _WIN32
        setvbuf(out_file, NULL, _IOLBF, 0);
 #endif /* _WIN32 */
@@ -310,11 +492,20 @@ void wpa_debug_close_file(void)
                return;
        fclose(out_file);
        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;
@@ -325,12 +516,21 @@ void wpa_msg_register_cb(wpa_msg_cb_func func)
 }
 
 
+static wpa_msg_get_ifname_func wpa_msg_ifname_cb = NULL;
+
+void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func)
+{
+       wpa_msg_ifname_cb = func;
+}
+
+
 void wpa_msg(void *ctx, int level, const char *fmt, ...)
 {
        va_list ap;
        char *buf;
        const int buflen = 2048;
        int len;
+       char prefix[130];
 
        buf = os_malloc(buflen);
        if (buf == NULL) {
@@ -339,9 +539,19 @@ void wpa_msg(void *ctx, int level, const char *fmt, ...)
                return;
        }
        va_start(ap, fmt);
+       prefix[0] = '\0';
+       if (wpa_msg_ifname_cb) {
+               const char *ifname = wpa_msg_ifname_cb(ctx);
+               if (ifname) {
+                       int res = os_snprintf(prefix, sizeof(prefix), "%s: ",
+                                             ifname);
+                       if (res < 0 || res >= (int) sizeof(prefix))
+                               prefix[0] = '\0';
+               }
+       }
        len = vsnprintf(buf, buflen, fmt, ap);
        va_end(ap);
-       wpa_printf(level, "%s", buf);
+       wpa_printf(level, "%s%s", prefix, buf);
        if (wpa_msg_cb)
                wpa_msg_cb(ctx, level, buf, len);
        os_free(buf);
index 6e5e79e..64ada57 100644 (file)
 /* Debugging function - conditional printf and hex dump. Driver wrappers can
  * use these for debugging purposes. */
 
-enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };
+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
 
@@ -34,10 +62,17 @@ enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };
 #define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0)
 #define wpa_debug_open_file(p) do { } while (0)
 #define wpa_debug_close_file() do { } while (0)
+#define wpa_dbg(args...) do { } while (0)
+
+static inline int wpa_debug_reopen_file(void)
+{
+       return 0;
+}
 
 #else /* CONFIG_NO_STDOUT_DEBUG */
 
 int wpa_debug_open_file(const char *path);
+int wpa_debug_reopen_file(void);
 void wpa_debug_close_file(void);
 
 /**
@@ -79,7 +114,8 @@ void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len);
 static inline void wpa_hexdump_buf(int level, const char *title,
                                   const struct wpabuf *buf)
 {
-       wpa_hexdump(level, title, wpabuf_head(buf), wpabuf_len(buf));
+       wpa_hexdump(level, title, buf ? wpabuf_head(buf) : NULL,
+                   buf ? wpabuf_len(buf) : 0);
 }
 
 /**
@@ -100,7 +136,8 @@ void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len);
 static inline void wpa_hexdump_buf_key(int level, const char *title,
                                       const struct wpabuf *buf)
 {
-       wpa_hexdump_key(level, title, wpabuf_head(buf), wpabuf_len(buf));
+       wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : NULL,
+                       buf ? wpabuf_len(buf) : 0);
 }
 
 /**
@@ -136,13 +173,24 @@ void wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
 void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
                           size_t len);
 
+/*
+ * wpa_dbg() behaves like wpa_msg(), but it can be removed from build to reduce
+ * binary size. As such, it should be used with debugging messages that are not
+ * needed in the control interface while wpa_msg() has to be used for anything
+ * that needs to shown to control interface monitors.
+ */
+#define wpa_dbg(args...) wpa_msg(args)
+
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
+#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_register_cb(f) do { } while (0)
+#define wpa_msg_register_ifname_cb(f) do { } while (0)
 #else /* CONFIG_NO_WPA_MSG */
 /**
  * wpa_msg - Conditional printf for default target and ctrl_iface monitors
@@ -183,8 +231,11 @@ typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt,
  * @func: Callback function (%NULL to unregister)
  */
 void wpa_msg_register_cb(wpa_msg_cb_func func);
-#endif /* CONFIG_NO_WPA_MSG */
 
+typedef const char * (*wpa_msg_get_ifname_func)(void *ctx);
+void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func);
+
+#endif /* CONFIG_NO_WPA_MSG */
 
 #ifdef CONFIG_NO_HOSTAPD_LOGGER
 #define hostapd_logger(args...) do { } while (0)
index a150455..cccfcc8 100644 (file)
@@ -117,6 +117,12 @@ static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data)
        WPA_PUT_LE16(pos, data);
 }
 
+static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data)
+{
+       u8 *pos = wpabuf_put(buf, 4);
+       WPA_PUT_LE32(pos, data);
+}
+
 static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data)
 {
        u8 *pos = wpabuf_put(buf, 2);
index fea2a04..9b53b80 100644 (file)
@@ -21,7 +21,7 @@
 #include "http_client.h"
 
 
-#define HTTP_CLIENT_TIMEOUT 30
+#define HTTP_CLIENT_TIMEOUT_SEC 30
 
 
 struct http_client {
@@ -42,7 +42,7 @@ struct http_client {
 static void http_client_timeout(void *eloop_data, void *user_ctx)
 {
        struct http_client *c = eloop_data;
-       wpa_printf(MSG_DEBUG, "HTTP: Timeout");
+       wpa_printf(MSG_DEBUG, "HTTP: Timeout (c=%p)", c);
        c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT);
 }
 
@@ -52,6 +52,9 @@ static void http_client_got_response(struct httpread *handle, void *cookie,
 {
        struct http_client *c = cookie;
 
+       wpa_printf(MSG_DEBUG, "HTTP: httpread callback: handle=%p cookie=%p "
+                  "e=%d", handle, cookie, e);
+
        eloop_cancel_timeout(http_client_timeout, c, NULL);
        switch (e) {
        case HTTPREAD_EVENT_FILE_READY:
@@ -122,7 +125,7 @@ static void http_client_tx_ready(int sock, void *eloop_ctx, void *sock_ctx)
        c->req = NULL;
 
        c->hread = httpread_create(c->sd, http_client_got_response, c,
-                                  c->max_response, HTTP_CLIENT_TIMEOUT);
+                                  c->max_response, HTTP_CLIENT_TIMEOUT_SEC);
        if (c->hread == NULL) {
                c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED);
                return;
@@ -181,8 +184,8 @@ struct http_client * http_client_addr(struct sockaddr_in *dst,
                return NULL;
        }
 
-       if (eloop_register_timeout(HTTP_CLIENT_TIMEOUT, 0, http_client_timeout,
-                                  c, NULL)) {
+       if (eloop_register_timeout(HTTP_CLIENT_TIMEOUT_SEC, 0,
+                                  http_client_timeout, c, NULL)) {
                http_client_free(c);
                return NULL;
        }
index b1b1e2b..a9958ee 100644 (file)
@@ -75,8 +75,8 @@
  * Note that angle brackets present in the original data must have been encoded
  * as &lt; and &gt; so they will not trouble us.
  */
-static int xml_next_tag(const char *in, const char **out,
-                       const char **out_tagname, const char **end)
+int xml_next_tag(const char *in, const char **out,
+                const char **out_tagname, const char **end)
 {
        while (*in && *in != '<')
                in++;
index 62dbe60..616af3d 100644 (file)
@@ -16,6 +16,8 @@
 void xml_data_encode(struct wpabuf *buf, const char *data, int len);
 void xml_add_tagged_data(struct wpabuf *buf, const char *tag,
                         const char *data);
+int xml_next_tag(const char *in, const char **out,
+                const char **out_tagname, const char **end);
 char * xml_get_first_item(const char *doc, const char *item);
 struct wpabuf * xml_get_base64_item(const char *data, const char *name,
                                    enum http_reply_code *ret);
index 619af15..2ba3d4b 100644 (file)
 #include "wps_dev_attr.h"
 
 
+#ifdef CONFIG_WPS_TESTING
+int wps_version_number = 0x20;
+int wps_testing_dummy_cred = 0;
+#endif /* CONFIG_WPS_TESTING */
+
+
 /**
  * wps_init - Initialize WPS Registration protocol data
  * @cfg: WPS configuration
@@ -46,7 +52,7 @@ struct wps_data * wps_init(const struct wps_config *cfg)
        }
        if (cfg->pin) {
                data->dev_pw_id = data->wps->oob_dev_pw_id == 0 ?
-                       DEV_PW_DEFAULT : data->wps->oob_dev_pw_id;
+                       cfg->dev_pw_id : data->wps->oob_dev_pw_id;
                data->dev_password = os_malloc(cfg->pin_len);
                if (data->dev_password == NULL) {
                        os_free(data);
@@ -61,12 +67,11 @@ struct wps_data * wps_init(const struct wps_config *cfg)
                /* Use special PIN '00000000' for PBC */
                data->dev_pw_id = DEV_PW_PUSHBUTTON;
                os_free(data->dev_password);
-               data->dev_password = os_malloc(8);
+               data->dev_password = (u8 *) os_strdup("00000000");
                if (data->dev_password == NULL) {
                        os_free(data);
                        return NULL;
                }
-               os_memset(data->dev_password, '0', 8);
                data->dev_password_len = 8;
        }
 
@@ -103,8 +108,11 @@ struct wps_data * wps_init(const struct wps_config *cfg)
 
        if (cfg->peer_addr)
                os_memcpy(data->peer_dev.mac_addr, cfg->peer_addr, ETH_ALEN);
+       if (cfg->p2p_dev_addr)
+               os_memcpy(data->p2p_dev_addr, cfg->p2p_dev_addr, ETH_ALEN);
 
        data->use_psk_key = cfg->use_psk_key;
+       data->pbc_in_m1 = cfg->pbc_in_m1;
 
        return data;
 }
@@ -201,19 +209,19 @@ int wps_is_selected_pbc_registrar(const struct wpabuf *msg)
            WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON)
                return 0;
 
+#ifdef CONFIG_WPS_STRICT
+       if (!attr.sel_reg_config_methods ||
+           !(WPA_GET_BE16(attr.sel_reg_config_methods) &
+             WPS_CONFIG_PUSHBUTTON))
+               return 0;
+#endif /* CONFIG_WPS_STRICT */
+
        return 1;
 }
 
 
-/**
- * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN
- * @msg: WPS IE contents from Beacon or Probe Response frame
- * Returns: 1 if PIN Registrar is active, 0 if not
- */
-int wps_is_selected_pin_registrar(const struct wpabuf *msg)
+static int is_selected_pin_registrar(struct wps_parse_attr *attr)
 {
-       struct wps_parse_attr attr;
-
        /*
         * In theory, this could also verify that attr.sel_reg_config_methods
         * includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD,
@@ -222,21 +230,112 @@ int wps_is_selected_pin_registrar(const struct wpabuf *msg)
         * Device Password ID here.
         */
 
-       if (wps_parse_msg(msg, &attr) < 0)
+       if (!attr->selected_registrar || *attr->selected_registrar == 0)
                return 0;
 
-       if (!attr.selected_registrar || *attr.selected_registrar == 0)
+       if (attr->dev_password_id != NULL &&
+           WPA_GET_BE16(attr->dev_password_id) == DEV_PW_PUSHBUTTON)
                return 0;
 
-       if (attr.dev_password_id != NULL &&
-           WPA_GET_BE16(attr.dev_password_id) == DEV_PW_PUSHBUTTON)
+#ifdef CONFIG_WPS_STRICT
+       if (!attr->sel_reg_config_methods ||
+           !(WPA_GET_BE16(attr->sel_reg_config_methods) &
+             (WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD)))
                return 0;
+#endif /* CONFIG_WPS_STRICT */
 
        return 1;
 }
 
 
 /**
+ * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN
+ * @msg: WPS IE contents from Beacon or Probe Response frame
+ * Returns: 1 if PIN Registrar is active, 0 if not
+ */
+int wps_is_selected_pin_registrar(const struct wpabuf *msg)
+{
+       struct wps_parse_attr attr;
+
+       if (wps_parse_msg(msg, &attr) < 0)
+               return 0;
+
+       return is_selected_pin_registrar(&attr);
+}
+
+
+/**
+ * wps_is_addr_authorized - Check whether WPS IE authorizes MAC address
+ * @msg: WPS IE contents from Beacon or Probe Response frame
+ * @addr: MAC address to search for
+ * @ver1_compat: Whether to use version 1 compatibility mode
+ * Returns: 1 if address is authorized, 0 if not
+ */
+int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
+                          int ver1_compat)
+{
+       struct wps_parse_attr attr;
+       unsigned int i;
+       const u8 *pos;
+       const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+       if (wps_parse_msg(msg, &attr) < 0)
+               return 0;
+
+       if (!attr.version2 && ver1_compat) {
+               /*
+                * Version 1.0 AP - AuthorizedMACs not used, so revert back to
+                * old mechanism of using SelectedRegistrar.
+                */
+               return is_selected_pin_registrar(&attr);
+       }
+
+       if (!attr.authorized_macs)
+               return 0;
+
+       pos = attr.authorized_macs;
+       for (i = 0; i < attr.authorized_macs_len / ETH_ALEN; i++) {
+               if (os_memcmp(pos, addr, ETH_ALEN) == 0 ||
+                   os_memcmp(pos, bcast, ETH_ALEN) == 0)
+                       return 1;
+               pos += ETH_ALEN;
+       }
+
+       return 0;
+}
+
+
+/**
+ * wps_ap_priority_compar - Prioritize WPS IE from two APs
+ * @wps_a: WPS IE contents from Beacon or Probe Response frame
+ * @wps_b: WPS IE contents from Beacon or Probe Response frame
+ * Returns: 1 if wps_b is considered more likely selection for WPS
+ * provisioning, -1 if wps_a is considered more like, or 0 if no preference
+ */
+int wps_ap_priority_compar(const struct wpabuf *wps_a,
+                          const struct wpabuf *wps_b)
+{
+       struct wps_parse_attr attr_a, attr_b;
+       int sel_a, sel_b;
+
+       if (wps_a == NULL || wps_parse_msg(wps_a, &attr_a) < 0)
+               return 1;
+       if (wps_b == NULL || wps_parse_msg(wps_b, &attr_b) < 0)
+               return -1;
+
+       sel_a = attr_a.selected_registrar && *attr_a.selected_registrar != 0;
+       sel_b = attr_b.selected_registrar && *attr_b.selected_registrar != 0;
+
+       if (sel_a && !sel_b)
+               return -1;
+       if (!sel_a && sel_b)
+               return 1;
+
+       return 0;
+}
+
+
+/**
  * wps_get_uuid_e - Get UUID-E from WPS IE
  * @msg: WPS IE contents from Beacon or Probe Response frame
  * Returns: Pointer to UUID-E or %NULL if not included
@@ -255,6 +354,19 @@ const u8 * wps_get_uuid_e(const struct wpabuf *msg)
 
 
 /**
+ * wps_is_20 - Check whether WPS attributes claim support for WPS 2.0
+ */
+int wps_is_20(const struct wpabuf *msg)
+{
+       struct wps_parse_attr attr;
+
+       if (msg == NULL || wps_parse_msg(msg, &attr) < 0)
+               return 0;
+       return attr.version2 != NULL;
+}
+
+
+/**
  * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request
  * @req_type: Value for Request Type attribute
  * Returns: WPS IE or %NULL on failure
@@ -277,7 +389,8 @@ struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type)
        wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
 
        if (wps_build_version(ie) ||
-           wps_build_req_type(ie, req_type)) {
+           wps_build_req_type(ie, req_type) ||
+           wps_build_wfa_ext(ie, 0, NULL, 0)) {
                wpabuf_free(ie);
                return NULL;
        }
@@ -310,7 +423,8 @@ struct wpabuf * wps_build_assoc_resp_ie(void)
        wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
 
        if (wps_build_version(ie) ||
-           wps_build_resp_type(ie, WPS_RESP_AP)) {
+           wps_build_resp_type(ie, WPS_RESP_AP) ||
+           wps_build_wfa_ext(ie, 0, NULL, 0)) {
                wpabuf_free(ie);
                return NULL;
        }
@@ -327,58 +441,60 @@ struct wpabuf * wps_build_assoc_resp_ie(void)
  * @dev: Device attributes
  * @uuid: Own UUID
  * @req_type: Value for Request Type attribute
+ * @num_req_dev_types: Number of requested device types
+ * @req_dev_types: Requested device types (8 * num_req_dev_types octets) or
+ *     %NULL if none
  * Returns: WPS IE or %NULL on failure
  *
  * The caller is responsible for freeing the buffer.
  */
 struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
                                       const u8 *uuid,
-                                      enum wps_request_type req_type)
+                                      enum wps_request_type req_type,
+                                      unsigned int num_req_dev_types,
+                                      const u8 *req_dev_types)
 {
        struct wpabuf *ie;
-       u8 *len;
-       u16 methods;
 
        wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request");
 
-       ie = wpabuf_alloc(200);
+       ie = wpabuf_alloc(500);
        if (ie == NULL)
                return NULL;
 
-       wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
-       len = wpabuf_put(ie, 1);
-       wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
-
-       if (pbc)
-               methods = WPS_CONFIG_PUSHBUTTON;
-       else {
-               methods = WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY |
-                       WPS_CONFIG_KEYPAD;
-#ifdef CONFIG_WPS_UFD
-               methods |= WPS_CONFIG_USBA;
-#endif /* CONFIG_WPS_UFD */
-#ifdef CONFIG_WPS_NFC
-               methods |= WPS_CONFIG_NFC_INTERFACE;
-#endif /* CONFIG_WPS_NFC */
-       }
-
        if (wps_build_version(ie) ||
            wps_build_req_type(ie, req_type) ||
-           wps_build_config_methods(ie, methods) ||
+           wps_build_config_methods(ie, dev->config_methods) ||
            wps_build_uuid_e(ie, uuid) ||
            wps_build_primary_dev_type(dev, ie) ||
            wps_build_rf_bands(dev, ie) ||
            wps_build_assoc_state(NULL, ie) ||
            wps_build_config_error(ie, WPS_CFG_NO_ERROR) ||
            wps_build_dev_password_id(ie, pbc ? DEV_PW_PUSHBUTTON :
-                                     DEV_PW_DEFAULT)) {
+                                     DEV_PW_DEFAULT) ||
+#ifdef CONFIG_WPS2
+           wps_build_manufacturer(dev, ie) ||
+           wps_build_model_name(dev, ie) ||
+           wps_build_model_number(dev, ie) ||
+           wps_build_dev_name(dev, ie) ||
+           wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0) ||
+#endif /* CONFIG_WPS2 */
+           wps_build_req_dev_type(dev, ie, num_req_dev_types, req_dev_types)
+           ||
+           wps_build_secondary_dev_type(dev, ie)
+               ) {
                wpabuf_free(ie);
                return NULL;
        }
 
-       *len = wpabuf_len(ie) - 2;
+#ifndef CONFIG_WPS2
+       if (dev->p2p && wps_build_dev_name(dev, ie)) {
+               wpabuf_free(ie);
+               return NULL;
+       }
+#endif /* CONFIG_WPS2 */
 
-       return ie;
+       return wps_ie_encapsulate(ie);
 }
 
 
index 1fd1e52..4986881 100644 (file)
@@ -63,6 +63,13 @@ struct wps_credential {
 
 #define WPS_DEV_TYPE_LEN 8
 #define WPS_DEV_TYPE_BUFSIZE 21
+#define WPS_SEC_DEV_TYPE_MAX_LEN 128
+/* maximum number of advertised WPS vendor extension attributes */
+#define MAX_WPS_VENDOR_EXTENSIONS 10
+/* maximum size of WPS Vendor extension attribute */
+#define WPS_MAX_VENDOR_EXT_LEN 1024
+/* maximum number of parsed WPS vendor extension attributes */
+#define MAX_WPS_PARSE_VENDOR_EXT 10
 
 /**
  * struct wps_device_data - WPS Device Data
@@ -73,8 +80,11 @@ struct wps_credential {
  * @model_number: Model Number (0..32 octets encoded in UTF-8)
  * @serial_number: Serial Number (0..32 octets encoded in UTF-8)
  * @pri_dev_type: Primary Device Type
+ * @sec_dev_type: Array of secondary device types
+ * @num_sec_dev_type: Number of secondary device types
  * @os_version: OS Version
  * @rf_bands: RF bands (WPS_RF_24GHZ, WPS_RF_50GHZ flags)
+ * @p2p: Whether the device is a P2P device
  */
 struct wps_device_data {
        u8 mac_addr[ETH_ALEN];
@@ -84,8 +94,15 @@ struct wps_device_data {
        char *model_number;
        char *serial_number;
        u8 pri_dev_type[WPS_DEV_TYPE_LEN];
+#define WPS_SEC_DEVICE_TYPES 5
+       u8 sec_dev_type[WPS_SEC_DEVICE_TYPES][WPS_DEV_TYPE_LEN];
+       u8 num_sec_dev_types;
        u32 os_version;
        u8 rf_bands;
+       u16 config_methods;
+       struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+
+       int p2p;
 };
 
 struct oob_conf_data {
@@ -156,6 +173,29 @@ struct wps_config {
         * struct wpa_context::psk.
         */
        int use_psk_key;
+
+       /**
+        * dev_pw_id - Device Password ID for Enrollee when PIN is used
+        */
+       u16 dev_pw_id;
+
+       /**
+        * p2p_dev_addr - P2P Device Address from (Re)Association Request
+        *
+        * On AP/GO, this is set to the P2P Device Address of the associating
+        * P2P client if a P2P IE is included in the (Re)Association Request
+        * frame and the P2P Device Address is included. Otherwise, this is set
+        * to %NULL to indicate the station does not have a P2P Device Address.
+        */
+       const u8 *p2p_dev_addr;
+
+       /**
+        * pbc_in_m1 - Do not remove PushButton config method in M1 (AP)
+        *
+        * This can be used to enable a workaround to allow Windows 7 to use
+        * PBC with the AP.
+        */
+       int pbc_in_m1;
 };
 
 struct wps_data * wps_init(const struct wps_config *cfg);
@@ -195,13 +235,20 @@ struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code);
 
 int wps_is_selected_pbc_registrar(const struct wpabuf *msg);
 int wps_is_selected_pin_registrar(const struct wpabuf *msg);
+int wps_ap_priority_compar(const struct wpabuf *wps_a,
+                          const struct wpabuf *wps_b);
+int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
+                          int ver1_compat);
 const u8 * wps_get_uuid_e(const struct wpabuf *msg);
+int wps_is_20(const struct wpabuf *msg);
 
 struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type);
 struct wpabuf * wps_build_assoc_resp_ie(void);
 struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
                                       const u8 *uuid,
-                                      enum wps_request_type req_type);
+                                      enum wps_request_type req_type,
+                                      unsigned int num_req_dev_types,
+                                      const u8 *req_dev_types);
 
 
 /**
@@ -340,6 +387,11 @@ struct wps_registrar_config {
         * static_wep_only - Whether the BSS supports only static WEP
         */
        int static_wep_only;
+
+       /**
+        * dualband - Whether this is a concurrent dualband AP
+        */
+       int dualband;
 };
 
 
@@ -395,7 +447,17 @@ enum wps_event {
        /**
         * WPS_EV_ER_ENROLLEE_REMOVE - ER: Enrollee removed
         */
-       WPS_EV_ER_ENROLLEE_REMOVE
+       WPS_EV_ER_ENROLLEE_REMOVE,
+
+       /**
+        * WPS_EV_ER_AP_SETTINGS - ER: AP Settings learned
+        */
+       WPS_EV_ER_AP_SETTINGS,
+
+       /**
+        * WPS_EV_ER_SET_SELECTED_REGISTRAR - ER: SetSelectedRegistrar event
+        */
+       WPS_EV_ER_SET_SELECTED_REGISTRAR
 };
 
 /**
@@ -428,6 +490,8 @@ union wps_event_data {
         */
        struct wps_event_fail {
                int msg;
+               u16 config_error;
+               u16 error_indication;
        } fail;
 
        struct wps_event_pwd_auth_fail {
@@ -464,6 +528,23 @@ union wps_event_data {
                const char *model_number;
                const char *serial_number;
        } enrollee;
+
+       struct wps_event_er_ap_settings {
+               const u8 *uuid;
+               const struct wps_credential *cred;
+       } ap_settings;
+
+       struct wps_event_er_set_selected_registrar {
+               const u8 *uuid;
+               int sel_reg;
+               u16 dev_passwd_id;
+               u16 sel_reg_config_methods;
+               enum {
+                       WPS_ER_SET_SEL_REG_START,
+                       WPS_ER_SET_SEL_REG_DONE,
+                       WPS_ER_SET_SEL_REG_FAILED
+               } state;
+       } set_sel_reg;
 };
 
 /**
@@ -695,16 +776,26 @@ struct wps_registrar *
 wps_registrar_init(struct wps_context *wps,
                   const struct wps_registrar_config *cfg);
 void wps_registrar_deinit(struct wps_registrar *reg);
-int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
-                         const u8 *pin, size_t pin_len, int timeout);
+int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,
+                         const u8 *uuid, const u8 *pin, size_t pin_len,
+                         int timeout);
 int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid);
+int wps_registrar_wps_cancel(struct wps_registrar *reg);
 int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid);
-int wps_registrar_button_pushed(struct wps_registrar *reg);
+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_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
-                               const struct wpabuf *wps_data);
+                               const struct wpabuf *wps_data,
+                               int p2p_wildcard);
 int wps_registrar_update_ie(struct wps_registrar *reg);
 int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr,
                           char *buf, size_t buflen);
+int wps_registrar_config_ap(struct wps_registrar *reg,
+                           struct wps_credential *cred);
+
+int wps_build_credential_wrap(struct wpabuf *msg,
+                             const struct wps_credential *cred);
 
 unsigned int wps_pin_checksum(unsigned int pin);
 unsigned int wps_pin_valid(unsigned int pin);
@@ -718,7 +809,8 @@ int wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev,
                    int registrar);
 int wps_attr_text(struct wpabuf *data, char *buf, char *end);
 
-struct wps_er * wps_er_init(struct wps_context *wps, const char *ifname);
+struct wps_er * wps_er_init(struct wps_context *wps, const char *ifname,
+                           const char *filter);
 void wps_er_refresh(struct wps_er *er);
 void wps_er_deinit(struct wps_er *er, void (*cb)(void *ctx), void *ctx);
 void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
@@ -726,6 +818,10 @@ 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_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
                 size_t pin_len);
+int wps_er_set_config(struct wps_er *er, const u8 *uuid,
+                     const struct wps_credential *cred);
+int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin,
+                 size_t pin_len, const struct wps_credential *cred);
 
 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,
@@ -733,4 +829,150 @@ char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
 void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid);
 u16 wps_config_methods_str2bin(const char *str);
 
+#ifdef CONFIG_WPS_STRICT
+int wps_validate_beacon(const struct wpabuf *wps_ie);
+int wps_validate_beacon_probe_resp(const struct wpabuf *wps_ie, int probe,
+                                  const u8 *addr);
+int wps_validate_probe_req(const struct wpabuf *wps_ie, const u8 *addr);
+int wps_validate_assoc_req(const struct wpabuf *wps_ie);
+int wps_validate_assoc_resp(const struct wpabuf *wps_ie);
+int wps_validate_m1(const struct wpabuf *tlvs);
+int wps_validate_m2(const struct wpabuf *tlvs);
+int wps_validate_m2d(const struct wpabuf *tlvs);
+int wps_validate_m3(const struct wpabuf *tlvs);
+int wps_validate_m4(const struct wpabuf *tlvs);
+int wps_validate_m4_encr(const struct wpabuf *tlvs, int wps2);
+int wps_validate_m5(const struct wpabuf *tlvs);
+int wps_validate_m5_encr(const struct wpabuf *tlvs, int wps2);
+int wps_validate_m6(const struct wpabuf *tlvs);
+int wps_validate_m6_encr(const struct wpabuf *tlvs, int wps2);
+int wps_validate_m7(const struct wpabuf *tlvs);
+int wps_validate_m7_encr(const struct wpabuf *tlvs, int ap, int wps2);
+int wps_validate_m8(const struct wpabuf *tlvs);
+int wps_validate_m8_encr(const struct wpabuf *tlvs, int ap, int wps2);
+int wps_validate_wsc_ack(const struct wpabuf *tlvs);
+int wps_validate_wsc_nack(const struct wpabuf *tlvs);
+int wps_validate_wsc_done(const struct wpabuf *tlvs);
+int wps_validate_upnp_set_selected_registrar(const struct wpabuf *tlvs);
+#else /* CONFIG_WPS_STRICT */
+static inline int wps_validate_beacon(const struct wpabuf *wps_ie){
+       return 0;
+}
+
+static inline int wps_validate_beacon_probe_resp(const struct wpabuf *wps_ie,
+                                                int probe, const u8 *addr)
+{
+       return 0;
+}
+
+static inline int wps_validate_probe_req(const struct wpabuf *wps_ie,
+                                        const u8 *addr)
+{
+       return 0;
+}
+
+static inline int wps_validate_assoc_req(const struct wpabuf *wps_ie)
+{
+       return 0;
+}
+
+static inline int wps_validate_assoc_resp(const struct wpabuf *wps_ie)
+{
+       return 0;
+}
+
+static inline int wps_validate_m1(const struct wpabuf *tlvs)
+{
+       return 0;
+}
+
+static inline int wps_validate_m2(const struct wpabuf *tlvs)
+{
+       return 0;
+}
+
+static inline int wps_validate_m2d(const struct wpabuf *tlvs)
+{
+       return 0;
+}
+
+static inline int wps_validate_m3(const struct wpabuf *tlvs)
+{
+       return 0;
+}
+
+static inline int wps_validate_m4(const struct wpabuf *tlvs)
+{
+       return 0;
+}
+
+static inline int wps_validate_m4_encr(const struct wpabuf *tlvs, int wps2)
+{
+       return 0;
+}
+
+static inline int wps_validate_m5(const struct wpabuf *tlvs)
+{
+       return 0;
+}
+
+static inline int wps_validate_m5_encr(const struct wpabuf *tlvs, int wps2)
+{
+       return 0;
+}
+
+static inline int wps_validate_m6(const struct wpabuf *tlvs)
+{
+       return 0;
+}
+
+static inline int wps_validate_m6_encr(const struct wpabuf *tlvs, int wps2)
+{
+       return 0;
+}
+
+static inline int wps_validate_m7(const struct wpabuf *tlvs)
+{
+       return 0;
+}
+
+static inline int wps_validate_m7_encr(const struct wpabuf *tlvs, int ap,
+                                      int wps2)
+{
+       return 0;
+}
+
+static inline int wps_validate_m8(const struct wpabuf *tlvs)
+{
+       return 0;
+}
+
+static inline int wps_validate_m8_encr(const struct wpabuf *tlvs, int ap,
+                                      int wps2)
+{
+       return 0;
+}
+
+static inline int wps_validate_wsc_ack(const struct wpabuf *tlvs)
+{
+       return 0;
+}
+
+static inline int wps_validate_wsc_nack(const struct wpabuf *tlvs)
+{
+       return 0;
+}
+
+static inline int wps_validate_wsc_done(const struct wpabuf *tlvs)
+{
+       return 0;
+}
+
+static inline int wps_validate_upnp_set_selected_registrar(
+       const struct wpabuf *tlvs)
+{
+       return 0;
+}
+#endif /* CONFIG_WPS_STRICT */
+
 #endif /* WPS_H */
index 9da556a..d2ca31a 100644 (file)
@@ -19,6 +19,8 @@
 #include "crypto/crypto.h"
 #include "crypto/dh_group5.h"
 #include "crypto/sha256.h"
+#include "crypto/random.h"
+#include "common/ieee802_11_defs.h"
 #include "wps_i.h"
 
 
@@ -47,6 +49,8 @@ int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
                wpabuf_free(pubkey);
                return -1;
        }
+       wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey);
+       wpa_hexdump_buf(MSG_DEBUG, "WPS: DH own Public Key", pubkey);
 
        wpabuf_put_be16(msg, ATTR_PUBLIC_KEY);
        wpabuf_put_be16(msg, wpabuf_len(pubkey));
@@ -156,10 +160,65 @@ int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg)
 
 int wps_build_version(struct wpabuf *msg)
 {
-       wpa_printf(MSG_DEBUG, "WPS:  * Version");
+       /*
+        * Note: This attribute is deprecated and set to hardcoded 0x10 for
+        * backwards compatibility reasons. The real version negotiation is
+        * done with Version2.
+        */
+       wpa_printf(MSG_DEBUG, "WPS:  * Version (hardcoded 0x10)");
        wpabuf_put_be16(msg, ATTR_VERSION);
        wpabuf_put_be16(msg, 1);
+       wpabuf_put_u8(msg, 0x10);
+       return 0;
+}
+
+
+int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
+                     const u8 *auth_macs, size_t auth_macs_count)
+{
+#ifdef CONFIG_WPS2
+       u8 *len;
+
+       wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
+       len = wpabuf_put(msg, 2); /* to be filled */
+       wpabuf_put_be24(msg, WPS_VENDOR_ID_WFA);
+
+       wpa_printf(MSG_DEBUG, "WPS:  * Version2 (0x%x)", WPS_VERSION);
+       wpabuf_put_u8(msg, WFA_ELEM_VERSION2);
+       wpabuf_put_u8(msg, 1);
        wpabuf_put_u8(msg, WPS_VERSION);
+
+       if (req_to_enroll) {
+               wpa_printf(MSG_DEBUG, "WPS:  * Request to Enroll (1)");
+               wpabuf_put_u8(msg, WFA_ELEM_REQUEST_TO_ENROLL);
+               wpabuf_put_u8(msg, 1);
+               wpabuf_put_u8(msg, 1);
+       }
+
+       if (auth_macs && auth_macs_count) {
+               size_t i;
+               wpa_printf(MSG_DEBUG, "WPS:  * AuthorizedMACs (count=%d)",
+                          (int) auth_macs_count);
+               wpabuf_put_u8(msg, WFA_ELEM_AUTHORIZEDMACS);
+               wpabuf_put_u8(msg, auth_macs_count * ETH_ALEN);
+               wpabuf_put_data(msg, auth_macs, auth_macs_count * ETH_ALEN);
+               for (i = 0; i < auth_macs_count; i++)
+                       wpa_printf(MSG_DEBUG, "WPS:    AuthorizedMAC: " MACSTR,
+                                  MAC2STR(&auth_macs[i * ETH_ALEN]));
+       }
+
+       WPA_PUT_BE16(len, (u8 *) wpabuf_put(msg, 0) - len - 2);
+#endif /* CONFIG_WPS2 */
+
+#ifdef CONFIG_WPS_TESTING
+       if (WPS_VERSION > 0x20) {
+               wpa_printf(MSG_DEBUG, "WPS:  * Extensibility Testing - extra "
+                          "attribute");
+               wpabuf_put_be16(msg, ATTR_EXTENSIBILITY_TEST);
+               wpabuf_put_be16(msg, 1);
+               wpabuf_put_u8(msg, 42);
+       }
+#endif /* CONFIG_WPS_TESTING */
        return 0;
 }
 
@@ -196,20 +255,28 @@ int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg)
 
 int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg)
 {
+       u16 auth_types = WPS_AUTH_TYPES;
+#ifdef CONFIG_WPS2
+       auth_types &= ~WPS_AUTH_SHARED;
+#endif /* CONFIG_WPS2 */
        wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type Flags");
        wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS);
        wpabuf_put_be16(msg, 2);
-       wpabuf_put_be16(msg, WPS_AUTH_TYPES);
+       wpabuf_put_be16(msg, auth_types);
        return 0;
 }
 
 
 int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg)
 {
+       u16 encr_types = WPS_ENCR_TYPES;
+#ifdef CONFIG_WPS2
+       encr_types &= ~WPS_ENCR_WEP;
+#endif /* CONFIG_WPS2 */
        wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type Flags");
        wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS);
        wpabuf_put_be16(msg, 2);
-       wpabuf_put_be16(msg, WPS_ENCR_TYPES);
+       wpabuf_put_be16(msg, encr_types);
        return 0;
 }
 
@@ -266,7 +333,7 @@ int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
        wpabuf_put_be16(msg, block_size + wpabuf_len(plain));
 
        iv = wpabuf_put(msg, block_size);
-       if (os_get_random(iv, block_size) < 0)
+       if (random_get_bytes(iv, block_size) < 0)
                return -1;
 
        data = wpabuf_put(msg, 0);
@@ -299,7 +366,8 @@ int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps)
        }
        wps->oob_dev_pw_id |= 0x0010;
 
-       if (os_get_random(dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN) < 0) {
+       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;
@@ -320,3 +388,35 @@ int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps)
        return 0;
 }
 #endif /* CONFIG_WPS_OOB */
+
+
+/* Encapsulate WPS IE data with one (or more, if needed) IE headers */
+struct wpabuf * wps_ie_encapsulate(struct wpabuf *data)
+{
+       struct wpabuf *ie;
+       const u8 *pos, *end;
+
+       ie = wpabuf_alloc(wpabuf_len(data) + 100);
+       if (ie == NULL) {
+               wpabuf_free(data);
+               return NULL;
+       }
+
+       pos = wpabuf_head(data);
+       end = pos + wpabuf_len(data);
+
+       while (end > pos) {
+               size_t frag_len = end - pos;
+               if (frag_len > 251)
+                       frag_len = 251;
+               wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+               wpabuf_put_u8(ie, 4 + frag_len);
+               wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
+               wpabuf_put_data(ie, pos, frag_len);
+               pos += frag_len;
+       }
+
+       wpabuf_free(data);
+
+       return ie;
+}
index 30b0e79..55b5573 100644 (file)
 #include "common.h"
 #include "wps_i.h"
 
+#ifndef CONFIG_WPS_STRICT
 #define WPS_WORKAROUNDS
+#endif /* CONFIG_WPS_STRICT */
+
+
+static int wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr *attr,
+                                         u8 id, u8 len, const u8 *pos)
+{
+       wpa_printf(MSG_EXCESSIVE, "WPS: WFA subelement id=%u len=%u",
+                  id, len);
+       switch (id) {
+       case WFA_ELEM_VERSION2:
+               if (len != 1) {
+                       wpa_printf(MSG_DEBUG, "WPS: Invalid Version2 length "
+                                  "%u", len);
+                       return -1;
+               }
+               attr->version2 = pos;
+               break;
+       case WFA_ELEM_AUTHORIZEDMACS:
+               attr->authorized_macs = pos;
+               attr->authorized_macs_len = len;
+               break;
+       case WFA_ELEM_NETWORK_KEY_SHAREABLE:
+               if (len != 1) {
+                       wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key "
+                                  "Shareable length %u", len);
+                       return -1;
+               }
+               attr->network_key_shareable = pos;
+               break;
+       case WFA_ELEM_REQUEST_TO_ENROLL:
+               if (len != 1) {
+                       wpa_printf(MSG_DEBUG, "WPS: Invalid Request to Enroll "
+                                  "length %u", len);
+                       return -1;
+               }
+               attr->request_to_enroll = pos;
+               break;
+       case WFA_ELEM_SETTINGS_DELAY_TIME:
+               if (len != 1) {
+                       wpa_printf(MSG_DEBUG, "WPS: Invalid Settings Delay "
+                                  "Time length %u", len);
+                       return -1;
+               }
+               attr->settings_delay_time = pos;
+               break;
+       default:
+               wpa_printf(MSG_MSGDUMP, "WPS: Skipped unknown WFA Vendor "
+                          "Extension subelement %u", id);
+               break;
+       }
+
+       return 0;
+}
+
+
+static int wps_parse_vendor_ext_wfa(struct wps_parse_attr *attr, const u8 *pos,
+                                   u16 len)
+{
+       const u8 *end = pos + len;
+       u8 id, elen;
+
+       while (pos + 2 < end) {
+               id = *pos++;
+               elen = *pos++;
+               if (pos + elen > end)
+                       break;
+               if (wps_set_vendor_ext_wfa_subelem(attr, id, elen, pos) < 0)
+                       return -1;
+               pos += elen;
+       }
+
+       return 0;
+}
+
+
+static int wps_parse_vendor_ext(struct wps_parse_attr *attr, const u8 *pos,
+                               u16 len)
+{
+       u32 vendor_id;
+
+       if (len < 3) {
+               wpa_printf(MSG_DEBUG, "WPS: Skip invalid Vendor Extension");
+               return 0;
+       }
+
+       vendor_id = WPA_GET_BE24(pos);
+       switch (vendor_id) {
+       case WPS_VENDOR_ID_WFA:
+               return wps_parse_vendor_ext_wfa(attr, pos + 3, len - 3);
+       }
+
+       /* Handle unknown vendor extensions */
+
+       wpa_printf(MSG_MSGDUMP, "WPS: Unknown Vendor Extension (Vendor ID %u)",
+                  vendor_id);
+
+       if (len > WPS_MAX_VENDOR_EXT_LEN) {
+               wpa_printf(MSG_DEBUG, "WPS: Too long Vendor Extension (%u)",
+                          len);
+               return -1;
+       }
+
+       if (attr->num_vendor_ext >= MAX_WPS_PARSE_VENDOR_EXT) {
+               wpa_printf(MSG_DEBUG, "WPS: Skipped Vendor Extension "
+                          "attribute (max %d vendor extensions)",
+                          MAX_WPS_PARSE_VENDOR_EXT);
+               return -1;
+       }
+       attr->vendor_ext[attr->num_vendor_ext] = pos;
+       attr->vendor_ext_len[attr->num_vendor_ext] = len;
+       attr->num_vendor_ext++;
+
+       return 0;
+}
 
 
 static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
@@ -399,6 +514,35 @@ static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
                }
                attr->ap_setup_locked = pos;
                break;
+       case ATTR_REQUESTED_DEV_TYPE:
+               if (len != WPS_DEV_TYPE_LEN) {
+                       wpa_printf(MSG_DEBUG, "WPS: Invalid Requested Device "
+                                  "Type length %u", len);
+                       return -1;
+               }
+               if (attr->num_req_dev_type >= MAX_REQ_DEV_TYPE_COUNT) {
+                       wpa_printf(MSG_DEBUG, "WPS: Skipped Requested Device "
+                                  "Type attribute (max %u types)",
+                                  MAX_REQ_DEV_TYPE_COUNT);
+                       break;
+               }
+               attr->req_dev_type[attr->num_req_dev_type] = pos;
+               attr->num_req_dev_type++;
+               break;
+       case ATTR_SECONDARY_DEV_TYPE_LIST:
+               if (len > WPS_SEC_DEV_TYPE_MAX_LEN ||
+                   (len % WPS_DEV_TYPE_LEN) > 0) {
+                       wpa_printf(MSG_DEBUG, "WPS: Invalid Secondary Device "
+                                  "Type length %u", len);
+                       return -1;
+               }
+               attr->sec_dev_type_list = pos;
+               attr->sec_dev_type_list_len = len;
+               break;
+       case ATTR_VENDOR_EXT:
+               if (wps_parse_vendor_ext(attr, pos, len) < 0)
+                       return -1;
+               break;
        default:
                wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
                           "len=%u", type, len);
@@ -413,6 +557,9 @@ int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
 {
        const u8 *pos, *end;
        u16 type, len;
+#ifdef WPS_WORKAROUNDS
+       u16 prev_type = 0;
+#endif /* WPS_WORKAROUNDS */
 
        os_memset(attr, 0, sizeof(*attr));
        pos = wpabuf_head(msg);
@@ -430,10 +577,28 @@ int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
                pos += 2;
                len = WPA_GET_BE16(pos);
                pos += 2;
-               wpa_printf(MSG_MSGDUMP, "WPS: attr type=0x%x len=%u",
+               wpa_printf(MSG_EXCESSIVE, "WPS: attr type=0x%x len=%u",
                           type, len);
                if (len > end - pos) {
                        wpa_printf(MSG_DEBUG, "WPS: Attribute overflow");
+                       wpa_hexdump_buf(MSG_MSGDUMP, "WPS: Message data", msg);
+#ifdef WPS_WORKAROUNDS
+                       /*
+                        * Some deployed APs seem to have a bug in encoding of
+                        * Network Key attribute in the Credential attribute
+                        * where they add an extra octet after the Network Key
+                        * attribute at least when open network is being
+                        * provisioned.
+                        */
+                       if ((type & 0xff00) != 0x1000 &&
+                           prev_type == ATTR_NETWORK_KEY) {
+                               wpa_printf(MSG_DEBUG, "WPS: Workaround - try "
+                                          "to skip unexpected octet after "
+                                          "Network Key");
+                               pos -= 3;
+                               continue;
+                       }
+#endif /* WPS_WORKAROUNDS */
                        return -1;
                }
 
@@ -459,6 +624,9 @@ int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
                if (wps_set_attr(attr, type, pos, len) < 0)
                        return -1;
 
+#ifdef WPS_WORKAROUNDS
+               prev_type = type;
+#endif /* WPS_WORKAROUNDS */
                pos += len;
        }
 
index 4751bbc..07e087d 100644 (file)
@@ -264,11 +264,18 @@ static int wps_process_cred_802_1x_enabled(struct wps_credential *cred,
 }
 
 
-static void wps_workaround_cred_key(struct wps_credential *cred)
+static int wps_workaround_cred_key(struct wps_credential *cred)
 {
        if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) &&
            cred->key_len > 8 && cred->key_len < 64 &&
            cred->key[cred->key_len - 1] == 0) {
+#ifdef CONFIG_WPS_STRICT
+               wpa_printf(MSG_INFO, "WPS: WPA/WPA2-Personal passphrase uses "
+                          "forbidden NULL termination");
+               wpa_hexdump_ascii_key(MSG_INFO, "WPS: Network Key",
+                                     cred->key, cred->key_len);
+               return -1;
+#else /* CONFIG_WPS_STRICT */
                /*
                 * A deployed external registrar is known to encode ASCII
                 * passphrases incorrectly. Remove the extra NULL termination
@@ -277,7 +284,9 @@ static void wps_workaround_cred_key(struct wps_credential *cred)
                wpa_printf(MSG_DEBUG, "WPS: Workaround - remove NULL "
                           "termination from ASCII passphrase");
                cred->key_len--;
+#endif /* CONFIG_WPS_STRICT */
        }
+       return 0;
 }
 
 
@@ -303,9 +312,7 @@ int wps_process_cred(struct wps_parse_attr *attr,
            wps_process_cred_802_1x_enabled(cred, attr->dot1x_enabled))
                return -1;
 
-       wps_workaround_cred_key(cred);
-
-       return 0;
+       return wps_workaround_cred_key(cred);
 }
 
 
@@ -324,7 +331,5 @@ int wps_process_ap_settings(struct wps_parse_attr *attr,
            wps_process_cred_mac_addr(cred, attr->mac_addr))
                return -1;
 
-       wps_workaround_cred_key(cred);
-
-       return 0;
+       return wps_workaround_cred_key(cred);
 }
index 6ef14db..505837b 100644 (file)
@@ -20,8 +20,8 @@
 #include "crypto/dh_group5.h"
 #include "crypto/sha1.h"
 #include "crypto/sha256.h"
+#include "crypto/random.h"
 #include "wps_i.h"
-#include "wps_dev_attr.h"
 
 
 void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
@@ -81,6 +81,8 @@ int wps_derive_keys(struct wps_data *wps)
                return -1;
        }
 
+       wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey);
+       wpa_hexdump_buf(MSG_DEBUG, "WPS: DH peer Public Key", pubkey);
        dh_shared = dh5_derive_shared(wps->dh_ctx, pubkey, wps->dh_privkey);
        dh5_free(wps->dh_ctx);
        wps->dh_ctx = NULL;
@@ -241,7 +243,7 @@ unsigned int wps_generate_pin(void)
        unsigned int val;
 
        /* Generate seven random digits for the PIN */
-       if (os_get_random((unsigned char *) &val, sizeof(val)) < 0) {
+       if (random_get_bytes((unsigned char *) &val, sizeof(val)) < 0) {
                struct os_time now;
                os_get_time(&now);
                val = os_random() ^ now.sec ^ now.usec;
@@ -253,7 +255,8 @@ unsigned int wps_generate_pin(void)
 }
 
 
-void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg)
+void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
+                   u16 config_error, u16 error_indication)
 {
        union wps_event_data data;
 
@@ -262,6 +265,8 @@ void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg)
 
        os_memset(&data, 0, sizeof(data));
        data.fail.msg = msg;
+       data.fail.config_error = config_error;
+       data.fail.error_indication = error_indication;
        wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data);
 }
 
@@ -325,7 +330,9 @@ static struct wpabuf * wps_get_oob_cred(struct wps_context *wps)
        data.wps = wps;
        data.auth_type = wps->auth_types;
        data.encr_type = wps->encr_types;
-       if (wps_build_version(plain) || wps_build_cred(&data, plain)) {
+       if (wps_build_version(plain) ||
+           wps_build_cred(&data, plain) ||
+           wps_build_wfa_ext(plain, 0, NULL, 0)) {
                wpabuf_free(plain);
                return NULL;
        }
@@ -356,7 +363,8 @@ static struct wpabuf * wps_get_oob_dev_pwd(struct wps_context *wps)
        }
 
        if (wps_build_version(data) ||
-           wps_build_oob_dev_password(data, wps)) {
+           wps_build_oob_dev_password(data, wps) ||
+           wps_build_wfa_ext(data, 0, NULL, 0)) {
                wpa_printf(MSG_ERROR, "WPS: Build OOB device password "
                           "attribute error");
                wpabuf_free(data);
@@ -604,6 +612,9 @@ u16 wps_config_methods_str2bin(const char *str)
        if (str == NULL) {
                /* Default to enabling methods based on build configuration */
                methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
+#ifdef CONFIG_WPS2
+               methods |= WPS_CONFIG_VIRT_DISPLAY;
+#endif /* CONFIG_WPS2 */
 #ifdef CONFIG_WPS_UFD
                methods |= WPS_CONFIG_USBA;
 #endif /* CONFIG_WPS_UFD */
@@ -629,7 +640,64 @@ u16 wps_config_methods_str2bin(const char *str)
                        methods |= WPS_CONFIG_PUSHBUTTON;
                if (os_strstr(str, "keypad"))
                        methods |= WPS_CONFIG_KEYPAD;
+#ifdef CONFIG_WPS2
+               if (os_strstr(str, "virtual_display"))
+                       methods |= WPS_CONFIG_VIRT_DISPLAY;
+               if (os_strstr(str, "physical_display"))
+                       methods |= WPS_CONFIG_PHY_DISPLAY;
+               if (os_strstr(str, "virtual_push_button"))
+                       methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
+               if (os_strstr(str, "physical_push_button"))
+                       methods |= WPS_CONFIG_PHY_PUSHBUTTON;
+#endif /* CONFIG_WPS2 */
        }
 
        return methods;
 }
+
+
+struct wpabuf * wps_build_wsc_ack(struct wps_data *wps)
+{
+       struct wpabuf *msg;
+
+       wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_ACK");
+
+       msg = wpabuf_alloc(1000);
+       if (msg == NULL)
+               return NULL;
+
+       if (wps_build_version(msg) ||
+           wps_build_msg_type(msg, WPS_WSC_ACK) ||
+           wps_build_enrollee_nonce(wps, msg) ||
+           wps_build_registrar_nonce(wps, msg) ||
+           wps_build_wfa_ext(msg, 0, NULL, 0)) {
+               wpabuf_free(msg);
+               return NULL;
+       }
+
+       return msg;
+}
+
+
+struct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
+{
+       struct wpabuf *msg;
+
+       wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_NACK");
+
+       msg = wpabuf_alloc(1000);
+       if (msg == NULL)
+               return NULL;
+
+       if (wps_build_version(msg) ||
+           wps_build_msg_type(msg, WPS_WSC_NACK) ||
+           wps_build_enrollee_nonce(wps, msg) ||
+           wps_build_registrar_nonce(wps, msg) ||
+           wps_build_config_error(msg, wps->config_error) ||
+           wps_build_wfa_ext(msg, 0, NULL, 0)) {
+               wpabuf_free(msg);
+               return NULL;
+       }
+
+       return msg;
+}
index 750ca41..43311f3 100644 (file)
 #ifndef WPS_DEFS_H
 #define WPS_DEFS_H
 
+#ifdef CONFIG_WPS_TESTING
+
+extern int wps_version_number;
+extern int wps_testing_dummy_cred;
+#define WPS_VERSION wps_version_number
+
+#else /* CONFIG_WPS_TESTING */
+
+#ifdef CONFIG_WPS2
+#define WPS_VERSION 0x20
+#else /* CONFIG_WPS2 */
 #define WPS_VERSION 0x10
+#endif /* CONFIG_WPS2 */
+
+#endif /* CONFIG_WPS_TESTING */
 
 /* Diffie-Hellman 1536-bit MODP Group; RFC 3526, Group 5 */
 #define WPS_DH_GROUP 5
@@ -124,7 +138,20 @@ enum wps_attribute {
        ATTR_KEY_PROVIDED_AUTO = 0x1061,
        ATTR_802_1X_ENABLED = 0x1062,
        ATTR_APPSESSIONKEY = 0x1063,
-       ATTR_WEPTRANSMITKEY = 0x1064
+       ATTR_WEPTRANSMITKEY = 0x1064,
+       ATTR_REQUESTED_DEV_TYPE = 0x106a,
+       ATTR_EXTENSIBILITY_TEST = 0x10fa /* _NOT_ defined in the spec */
+};
+
+#define WPS_VENDOR_ID_WFA 14122
+
+/* WFA Vendor Extension subelements */
+enum {
+       WFA_ELEM_VERSION2 = 0x00,
+       WFA_ELEM_AUTHORIZEDMACS = 0x01,
+       WFA_ELEM_NETWORK_KEY_SHAREABLE = 0x02,
+       WFA_ELEM_REQUEST_TO_ENROLL = 0x03,
+       WFA_ELEM_SETTINGS_DELAY_TIME = 0x04
 };
 
 /* Device Password ID */
@@ -197,6 +224,14 @@ enum wps_config_error {
        WPS_CFG_DEV_PASSWORD_AUTH_FAILURE = 18
 };
 
+/* Vendor specific Error Indication for WPS event messages */
+enum wps_error_indication {
+       WPS_EI_NO_ERROR,
+       WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED,
+       WPS_EI_SECURITY_WEP_PROHIBITED,
+       NUM_WPS_EI_VALUES
+};
+
 /* RF Bands */
 #define WPS_RF_24GHZ 0x01
 #define WPS_RF_50GHZ 0x02
@@ -211,6 +246,12 @@ enum wps_config_error {
 #define WPS_CONFIG_NFC_INTERFACE 0x0040
 #define WPS_CONFIG_PUSHBUTTON 0x0080
 #define WPS_CONFIG_KEYPAD 0x0100
+#ifdef CONFIG_WPS2
+#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280
+#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480
+#define WPS_CONFIG_VIRT_DISPLAY 0x2008
+#define WPS_CONFIG_PHY_DISPLAY 0x4008
+#endif /* CONFIG_WPS2 */
 
 /* Connection Type Flags */
 #define WPS_CONN_ESS 0x01
@@ -290,4 +331,6 @@ enum wps_response_type {
 /* Walk Time for push button configuration (in seconds) */
 #define WPS_PBC_WALK_TIME 120
 
+#define WPS_MAX_AUTHORIZED_MACS 5
+
 #endif /* WPS_DEFS_H */
index 090bfa2..f2fb03a 100644 (file)
 #include "wps_dev_attr.h"
 
 
-static int wps_build_manufacturer(struct wps_device_data *dev,
-                                 struct wpabuf *msg)
+int wps_build_manufacturer(struct wps_device_data *dev, struct wpabuf *msg)
 {
        size_t len;
        wpa_printf(MSG_DEBUG, "WPS:  * Manufacturer");
        wpabuf_put_be16(msg, ATTR_MANUFACTURER);
        len = dev->manufacturer ? os_strlen(dev->manufacturer) : 0;
+#ifndef CONFIG_WPS_STRICT
        if (len == 0) {
                /*
                 * Some deployed WPS implementations fail to parse zero-length
-                * attributes. As a workaround, send a null character if the
+                * attributes. As a workaround, send a space character if the
                 * device attribute string is empty.
                 */
                wpabuf_put_be16(msg, 1);
-               wpabuf_put_u8(msg, '\0');
-       } else {
-               wpabuf_put_be16(msg, len);
-               wpabuf_put_data(msg, dev->manufacturer, len);
+               wpabuf_put_u8(msg, ' ');
+               return 0;
        }
+#endif /* CONFIG_WPS_STRICT */
+       wpabuf_put_be16(msg, len);
+       wpabuf_put_data(msg, dev->manufacturer, len);
        return 0;
 }
 
 
-static int wps_build_model_name(struct wps_device_data *dev,
-                               struct wpabuf *msg)
+int wps_build_model_name(struct wps_device_data *dev, struct wpabuf *msg)
 {
        size_t len;
        wpa_printf(MSG_DEBUG, "WPS:  * Model Name");
        wpabuf_put_be16(msg, ATTR_MODEL_NAME);
        len = dev->model_name ? os_strlen(dev->model_name) : 0;
+#ifndef CONFIG_WPS_STRICT
        if (len == 0) {
                /*
                 * Some deployed WPS implementations fail to parse zero-length
-                * attributes. As a workaround, send a null character if the
+                * attributes. As a workaround, send a space character if the
                 * device attribute string is empty.
                 */
                wpabuf_put_be16(msg, 1);
-               wpabuf_put_u8(msg, '\0');
-       } else {
-               wpabuf_put_be16(msg, len);
-               wpabuf_put_data(msg, dev->model_name, len);
+               wpabuf_put_u8(msg, ' ');
+               return 0;
        }
+#endif /* CONFIG_WPS_STRICT */
+       wpabuf_put_be16(msg, len);
+       wpabuf_put_data(msg, dev->model_name, len);
        return 0;
 }
 
 
-static int wps_build_model_number(struct wps_device_data *dev,
-                                 struct wpabuf *msg)
+int wps_build_model_number(struct wps_device_data *dev, struct wpabuf *msg)
 {
        size_t len;
        wpa_printf(MSG_DEBUG, "WPS:  * Model Number");
        wpabuf_put_be16(msg, ATTR_MODEL_NUMBER);
        len = dev->model_number ? os_strlen(dev->model_number) : 0;
+#ifndef CONFIG_WPS_STRICT
        if (len == 0) {
                /*
                 * Some deployed WPS implementations fail to parse zero-length
-                * attributes. As a workaround, send a null character if the
+                * attributes. As a workaround, send a space character if the
                 * device attribute string is empty.
                 */
                wpabuf_put_be16(msg, 1);
-               wpabuf_put_u8(msg, '\0');
-       } else {
-               wpabuf_put_be16(msg, len);
-               wpabuf_put_data(msg, dev->model_number, len);
+               wpabuf_put_u8(msg, ' ');
+               return 0;
        }
+#endif /* CONFIG_WPS_STRICT */
+       wpabuf_put_be16(msg, len);
+       wpabuf_put_data(msg, dev->model_number, len);
        return 0;
 }
 
@@ -95,18 +98,20 @@ static int wps_build_serial_number(struct wps_device_data *dev,
        wpa_printf(MSG_DEBUG, "WPS:  * Serial Number");
        wpabuf_put_be16(msg, ATTR_SERIAL_NUMBER);
        len = dev->serial_number ? os_strlen(dev->serial_number) : 0;
+#ifndef CONFIG_WPS_STRICT
        if (len == 0) {
                /*
                 * Some deployed WPS implementations fail to parse zero-length
-                * attributes. As a workaround, send a null character if the
+                * attributes. As a workaround, send a space character if the
                 * device attribute string is empty.
                 */
                wpabuf_put_be16(msg, 1);
-               wpabuf_put_u8(msg, '\0');
-       } else {
-               wpabuf_put_be16(msg, len);
-               wpabuf_put_data(msg, dev->serial_number, len);
+               wpabuf_put_u8(msg, ' ');
+               return 0;
        }
+#endif /* CONFIG_WPS_STRICT */
+       wpabuf_put_be16(msg, len);
+       wpabuf_put_data(msg, dev->serial_number, len);
        return 0;
 }
 
@@ -121,24 +126,62 @@ int wps_build_primary_dev_type(struct wps_device_data *dev, struct wpabuf *msg)
 }
 
 
-static int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg)
+int wps_build_secondary_dev_type(struct wps_device_data *dev,
+                                 struct wpabuf *msg)
+{
+       if (!dev->num_sec_dev_types)
+               return 0;
+
+       wpa_printf(MSG_DEBUG, "WPS:  * Secondary Device Type");
+       wpabuf_put_be16(msg, ATTR_SECONDARY_DEV_TYPE_LIST);
+       wpabuf_put_be16(msg, WPS_DEV_TYPE_LEN * dev->num_sec_dev_types);
+       wpabuf_put_data(msg, dev->sec_dev_type,
+                       WPS_DEV_TYPE_LEN * dev->num_sec_dev_types);
+
+       return 0;
+}
+
+
+int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg,
+                          unsigned int num_req_dev_types,
+                          const u8 *req_dev_types)
+{
+       unsigned int i;
+
+       for (i = 0; i < num_req_dev_types; i++) {
+               wpa_hexdump(MSG_DEBUG, "WPS: * Requested Device Type",
+                           req_dev_types + i * WPS_DEV_TYPE_LEN,
+                           WPS_DEV_TYPE_LEN);
+               wpabuf_put_be16(msg, ATTR_REQUESTED_DEV_TYPE);
+               wpabuf_put_be16(msg, WPS_DEV_TYPE_LEN);
+               wpabuf_put_data(msg, req_dev_types + i * WPS_DEV_TYPE_LEN,
+                               WPS_DEV_TYPE_LEN);
+       }
+
+       return 0;
+}
+
+
+int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg)
 {
        size_t len;
        wpa_printf(MSG_DEBUG, "WPS:  * Device Name");
        wpabuf_put_be16(msg, ATTR_DEV_NAME);
        len = dev->device_name ? os_strlen(dev->device_name) : 0;
+#ifndef CONFIG_WPS_STRICT
        if (len == 0) {
                /*
                 * Some deployed WPS implementations fail to parse zero-length
-                * attributes. As a workaround, send a null character if the
+                * attributes. As a workaround, send a space character if the
                 * device attribute string is empty.
                 */
                wpabuf_put_be16(msg, 1);
-               wpabuf_put_u8(msg, '\0');
-       } else {
-               wpabuf_put_be16(msg, len);
-               wpabuf_put_data(msg, dev->device_name, len);
+               wpabuf_put_u8(msg, ' ');
+               return 0;
        }
+#endif /* CONFIG_WPS_STRICT */
+       wpabuf_put_be16(msg, len);
+       wpabuf_put_data(msg, dev->device_name, len);
        return 0;
 }
 
@@ -176,6 +219,25 @@ int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg)
 }
 
 
+int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg)
+{
+       int i;
+
+       for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+               if (dev->vendor_ext[i] == NULL)
+                       continue;
+               wpa_hexdump(MSG_DEBUG, "WPS:  * Vendor Extension",
+                           wpabuf_head_u8(dev->vendor_ext[i]),
+                           wpabuf_len(dev->vendor_ext[i]));
+               wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
+               wpabuf_put_be16(msg, wpabuf_len(dev->vendor_ext[i]));
+               wpabuf_put_buf(msg, dev->vendor_ext[i]);
+       }
+
+       return 0;
+}
+
+
 static int wps_process_manufacturer(struct wps_device_data *dev, const u8 *str,
                                    size_t str_len)
 {
index a9c16ea..f26a05b 100644 (file)
 
 struct wps_parse_attr;
 
+int wps_build_manufacturer(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_model_name(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_model_number(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg);
 int wps_build_device_attrs(struct wps_device_data *dev, struct wpabuf *msg);
 int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg);
 int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg);
 int wps_build_primary_dev_type(struct wps_device_data *dev,
                               struct wpabuf *msg);
+int wps_build_secondary_dev_type(struct wps_device_data *dev,
+                                struct wpabuf *msg);
+int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg);
 int wps_process_device_attrs(struct wps_device_data *dev,
                             struct wps_parse_attr *attr);
 int wps_process_os_version(struct wps_device_data *dev, const u8 *ver);
@@ -29,5 +36,9 @@ int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands);
 void wps_device_data_dup(struct wps_device_data *dst,
                         const struct wps_device_data *src);
 void wps_device_data_free(struct wps_device_data *dev);
+int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg,
+                          unsigned int num_req_dev_types,
+                          const u8 *req_dev_types);
 
 #endif /* WPS_DEV_ATTR_H */
index dff24d4..0fbaa3f 100644 (file)
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "crypto/crypto.h"
 #include "crypto/sha256.h"
+#include "crypto/random.h"
 #include "wps_i.h"
 #include "wps_dev_attr.h"
 
@@ -53,7 +54,7 @@ static int wps_build_e_hash(struct wps_data *wps, struct wpabuf *msg)
        const u8 *addr[4];
        size_t len[4];
 
-       if (os_get_random(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0)
+       if (random_get_bytes(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0)
                return -1;
        wpa_hexdump(MSG_DEBUG, "WPS: E-S1", wps->snonce, WPS_SECRET_NONCE_LEN);
        wpa_hexdump(MSG_DEBUG, "WPS: E-S2",
@@ -119,8 +120,9 @@ static int wps_build_e_snonce2(struct wps_data *wps, struct wpabuf *msg)
 static struct wpabuf * wps_build_m1(struct wps_data *wps)
 {
        struct wpabuf *msg;
+       u16 config_methods;
 
-       if (os_get_random(wps->nonce_e, WPS_NONCE_LEN) < 0)
+       if (random_get_bytes(wps->nonce_e, WPS_NONCE_LEN) < 0)
                return NULL;
        wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Nonce",
                    wps->nonce_e, WPS_NONCE_LEN);
@@ -130,6 +132,26 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps)
        if (msg == NULL)
                return NULL;
 
+       config_methods = wps->wps->config_methods;
+       if (wps->wps->ap && !wps->pbc_in_m1 &&
+           (wps->dev_password_len != 0 ||
+            (config_methods & WPS_CONFIG_DISPLAY))) {
+               /*
+                * These are the methods that the AP supports as an Enrollee
+                * for adding external Registrars, so remove PushButton.
+                *
+                * As a workaround for Windows 7 mechanism for probing WPS
+                * capabilities from M1, leave PushButton option if no PIN
+                * method is available or if WPS configuration enables PBC
+                * workaround.
+                */
+               config_methods &= ~WPS_CONFIG_PUSHBUTTON;
+#ifdef CONFIG_WPS2
+               config_methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
+                                   WPS_CONFIG_PHY_PUSHBUTTON);
+#endif /* CONFIG_WPS2 */
+       }
+
        if (wps_build_version(msg) ||
            wps_build_msg_type(msg, WPS_M1) ||
            wps_build_uuid_e(msg, wps->uuid_e) ||
@@ -139,14 +161,15 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps)
            wps_build_auth_type_flags(wps, msg) ||
            wps_build_encr_type_flags(wps, msg) ||
            wps_build_conn_type_flags(wps, msg) ||
-           wps_build_config_methods(msg, wps->wps->config_methods) ||
+           wps_build_config_methods(msg, config_methods) ||
            wps_build_wps_state(wps, msg) ||
            wps_build_device_attrs(&wps->wps->dev, msg) ||
            wps_build_rf_bands(&wps->wps->dev, msg) ||
            wps_build_assoc_state(wps, msg) ||
            wps_build_dev_password_id(msg, wps->dev_pw_id) ||
            wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
-           wps_build_os_version(&wps->wps->dev, msg)) {
+           wps_build_os_version(&wps->wps->dev, msg) ||
+           wps_build_wfa_ext(msg, 0, NULL, 0)) {
                wpabuf_free(msg);
                return NULL;
        }
@@ -176,6 +199,7 @@ static struct wpabuf * wps_build_m3(struct wps_data *wps)
            wps_build_msg_type(msg, WPS_M3) ||
            wps_build_registrar_nonce(wps, msg) ||
            wps_build_e_hash(wps, msg) ||
+           wps_build_wfa_ext(msg, 0, NULL, 0) ||
            wps_build_authenticator(wps, msg)) {
                wpabuf_free(msg);
                return NULL;
@@ -208,6 +232,7 @@ static struct wpabuf * wps_build_m5(struct wps_data *wps)
            wps_build_e_snonce1(wps, plain) ||
            wps_build_key_wrap_auth(wps, plain) ||
            wps_build_encr_settings(wps, msg, plain) ||
+           wps_build_wfa_ext(msg, 0, NULL, 0) ||
            wps_build_authenticator(wps, msg)) {
                wpabuf_free(plain);
                wpabuf_free(msg);
@@ -310,6 +335,7 @@ static struct wpabuf * wps_build_m7(struct wps_data *wps)
            (wps->wps->ap && wps_build_ap_settings(wps, plain)) ||
            wps_build_key_wrap_auth(wps, plain) ||
            wps_build_encr_settings(wps, msg, plain) ||
+           wps_build_wfa_ext(msg, 0, NULL, 0) ||
            wps_build_authenticator(wps, msg)) {
                wpabuf_free(plain);
                wpabuf_free(msg);
@@ -345,7 +371,8 @@ static struct wpabuf * wps_build_wsc_done(struct wps_data *wps)
        if (wps_build_version(msg) ||
            wps_build_msg_type(msg, WPS_WSC_DONE) ||
            wps_build_enrollee_nonce(wps, msg) ||
-           wps_build_registrar_nonce(wps, msg)) {
+           wps_build_registrar_nonce(wps, msg) ||
+           wps_build_wfa_ext(msg, 0, NULL, 0)) {
                wpabuf_free(msg);
                return NULL;
        }
@@ -360,51 +387,6 @@ static struct wpabuf * wps_build_wsc_done(struct wps_data *wps)
 }
 
 
-static struct wpabuf * wps_build_wsc_ack(struct wps_data *wps)
-{
-       struct wpabuf *msg;
-
-       wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_ACK");
-
-       msg = wpabuf_alloc(1000);
-       if (msg == NULL)
-               return NULL;
-
-       if (wps_build_version(msg) ||
-           wps_build_msg_type(msg, WPS_WSC_ACK) ||
-           wps_build_enrollee_nonce(wps, msg) ||
-           wps_build_registrar_nonce(wps, msg)) {
-               wpabuf_free(msg);
-               return NULL;
-       }
-
-       return msg;
-}
-
-
-static struct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
-{
-       struct wpabuf *msg;
-
-       wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_NACK");
-
-       msg = wpabuf_alloc(1000);
-       if (msg == NULL)
-               return NULL;
-
-       if (wps_build_version(msg) ||
-           wps_build_msg_type(msg, WPS_WSC_NACK) ||
-           wps_build_enrollee_nonce(wps, msg) ||
-           wps_build_registrar_nonce(wps, msg) ||
-           wps_build_config_error(msg, wps->config_error)) {
-               wpabuf_free(msg);
-               return NULL;
-       }
-
-       return msg;
-}
-
-
 struct wpabuf * wps_enrollee_get_msg(struct wps_data *wps,
                                     enum wsc_op_code *op_code)
 {
@@ -657,7 +639,7 @@ static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2)
 
 
 static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
-                             size_t cred_len)
+                             size_t cred_len, int wps2)
 {
        struct wps_parse_attr attr;
        struct wpabuf msg;
@@ -682,8 +664,31 @@ static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
                 * reasons, allow this to be processed since we do not really
                 * use the MAC Address information for anything.
                 */
+#ifdef CONFIG_WPS_STRICT
+               if (wps2) {
+                       wpa_printf(MSG_INFO, "WPS: Do not accept incorrect "
+                                  "MAC Address in AP Settings");
+                       return -1;
+               }
+#endif /* CONFIG_WPS_STRICT */
        }
 
+#ifdef CONFIG_WPS2
+       if (!(wps->cred.encr_type &
+             (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES))) {
+               if (wps->cred.encr_type & WPS_ENCR_WEP) {
+                       wpa_printf(MSG_INFO, "WPS: Reject Credential "
+                                  "due to WEP configuration");
+                       wps->error_indication = WPS_EI_SECURITY_WEP_PROHIBITED;
+                       return -2;
+               }
+
+               wpa_printf(MSG_INFO, "WPS: Reject Credential due to "
+                          "invalid encr_type 0x%x", wps->cred.encr_type);
+               return -1;
+       }
+#endif /* CONFIG_WPS2 */
+
        if (wps->wps->cred_cb) {
                wps->cred.cred_attr = cred - 4;
                wps->cred.cred_attr_len = cred_len + 4;
@@ -697,9 +702,10 @@ static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
 
 
 static int wps_process_creds(struct wps_data *wps, const u8 *cred[],
-                            size_t cred_len[], size_t num_cred)
+                            size_t cred_len[], size_t num_cred, int wps2)
 {
        size_t i;
+       int ok = 0;
 
        if (wps->wps->ap)
                return 0;
@@ -711,17 +717,29 @@ static int wps_process_creds(struct wps_data *wps, const u8 *cred[],
        }
 
        for (i = 0; i < num_cred; i++) {
-               if (wps_process_cred_e(wps, cred[i], cred_len[i]))
+               int res;
+               res = wps_process_cred_e(wps, cred[i], cred_len[i], wps2);
+               if (res == 0)
+                       ok++;
+               else if (res == -2)
+                       wpa_printf(MSG_DEBUG, "WPS: WEP credential skipped");
+               else
                        return -1;
        }
 
+       if (ok == 0) {
+               wpa_printf(MSG_DEBUG, "WPS: No valid Credential attribute "
+                          "received");
+               return -1;
+       }
+
        return 0;
 }
 
 
 static int wps_process_ap_settings_e(struct wps_data *wps,
                                     struct wps_parse_attr *attr,
-                                    struct wpabuf *attrs)
+                                    struct wpabuf *attrs, int wps2)
 {
        struct wps_credential cred;
 
@@ -747,8 +765,62 @@ static int wps_process_ap_settings_e(struct wps_data *wps,
                 * reasons, allow this to be processed since we do not really
                 * use the MAC Address information for anything.
                 */
+#ifdef CONFIG_WPS_STRICT
+               if (wps2) {
+                       wpa_printf(MSG_INFO, "WPS: Do not accept incorrect "
+                                  "MAC Address in AP Settings");
+                       return -1;
+               }
+#endif /* CONFIG_WPS_STRICT */
+       }
+
+#ifdef CONFIG_WPS2
+       if (!(cred.encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES)))
+       {
+               if (cred.encr_type & WPS_ENCR_WEP) {
+                       wpa_printf(MSG_INFO, "WPS: Reject new AP settings "
+                                  "due to WEP configuration");
+                       wps->error_indication = WPS_EI_SECURITY_WEP_PROHIBITED;
+                       return -1;
+               }
+
+               wpa_printf(MSG_INFO, "WPS: Reject new AP settings due to "
+                          "invalid encr_type 0x%x", cred.encr_type);
+               return -1;
+       }
+#endif /* CONFIG_WPS2 */
+
+#ifdef CONFIG_WPS_STRICT
+       if (wps2) {
+               if ((cred.encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) ==
+                   WPS_ENCR_TKIP ||
+                   (cred.auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) ==
+                   WPS_AUTH_WPAPSK) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC 2.0 "
+                                  "AP Settings: WPA-Personal/TKIP only");
+                       wps->error_indication =
+                               WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED;
+                       return -1;
+               }
+       }
+#endif /* CONFIG_WPS_STRICT */
+
+#ifdef CONFIG_WPS2
+       if ((cred.encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) == WPS_ENCR_TKIP)
+       {
+               wpa_printf(MSG_DEBUG, "WPS: Upgrade encr_type TKIP -> "
+                          "TKIP+AES");
+               cred.encr_type |= WPS_ENCR_AES;
        }
 
+       if ((cred.auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) ==
+           WPS_AUTH_WPAPSK) {
+               wpa_printf(MSG_DEBUG, "WPS: Upgrade auth_type WPAPSK -> "
+                          "WPAPSK+WPA2PSK");
+               cred.auth_type |= WPS_AUTH_WPA2PSK;
+       }
+#endif /* CONFIG_WPS2 */
+
        if (wps->wps->cred_cb) {
                cred.cred_attr = wpabuf_head(attrs);
                cred.cred_attr_len = wpabuf_len(attrs);
@@ -779,8 +851,15 @@ static enum wps_process_res wps_process_m2(struct wps_data *wps,
                return WPS_CONTINUE;
        }
 
+       /*
+        * Stop here on an AP as an Enrollee if AP Setup is locked unless the
+        * special locked mode is used to allow protocol run up to M7 in order
+        * to support external Registrars that only learn the current AP
+        * configuration without changing it.
+        */
        if (wps->wps->ap &&
-           (wps->wps->ap_setup_locked || wps->dev_password == NULL)) {
+           ((wps->wps->ap_setup_locked && wps->wps->ap_setup_locked != 2) ||
+            wps->dev_password == NULL)) {
                wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse "
                           "registration of a new Registrar");
                wps->config_error = WPS_CFG_SETUP_LOCKED;
@@ -888,6 +967,12 @@ static enum wps_process_res wps_process_m4(struct wps_data *wps,
                return WPS_CONTINUE;
        }
 
+       if (wps_validate_m4_encr(decrypted, attr->version2 != NULL) < 0) {
+               wpabuf_free(decrypted);
+               wps->state = SEND_WSC_NACK;
+               return WPS_CONTINUE;
+       }
+
        wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
                   "attribute");
        if (wps_parse_msg(decrypted, &eattr) < 0 ||
@@ -935,6 +1020,12 @@ static enum wps_process_res wps_process_m6(struct wps_data *wps,
                return WPS_CONTINUE;
        }
 
+       if (wps_validate_m6_encr(decrypted, attr->version2 != NULL) < 0) {
+               wpabuf_free(decrypted);
+               wps->state = SEND_WSC_NACK;
+               return WPS_CONTINUE;
+       }
+
        wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
                   "attribute");
        if (wps_parse_msg(decrypted, &eattr) < 0 ||
@@ -973,6 +1064,19 @@ static enum wps_process_res wps_process_m8(struct wps_data *wps,
                return WPS_CONTINUE;
        }
 
+       if (wps->wps->ap && wps->wps->ap_setup_locked) {
+               /*
+                * Stop here if special ap_setup_locked == 2 mode allowed the
+                * protocol to continue beyond M2. This allows ER to learn the
+                * current AP settings without changing them.
+                */
+               wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse "
+                          "registration of a new Registrar");
+               wps->config_error = WPS_CFG_SETUP_LOCKED;
+               wps->state = SEND_WSC_NACK;
+               return WPS_CONTINUE;
+       }
+
        decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
                                              attr->encr_settings_len);
        if (decrypted == NULL) {
@@ -982,13 +1086,21 @@ static enum wps_process_res wps_process_m8(struct wps_data *wps,
                return WPS_CONTINUE;
        }
 
+       if (wps_validate_m8_encr(decrypted, wps->wps->ap,
+                                attr->version2 != NULL) < 0) {
+               wpabuf_free(decrypted);
+               wps->state = SEND_WSC_NACK;
+               return WPS_CONTINUE;
+       }
+
        wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
                   "attribute");
        if (wps_parse_msg(decrypted, &eattr) < 0 ||
            wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
            wps_process_creds(wps, eattr.cred, eattr.cred_len,
-                             eattr.num_cred) ||
-           wps_process_ap_settings_e(wps, &eattr, decrypted)) {
+                             eattr.num_cred, attr->version2 != NULL) ||
+           wps_process_ap_settings_e(wps, &eattr, decrypted,
+                                     attr->version2 != NULL)) {
                wpabuf_free(decrypted);
                wps->state = SEND_WSC_NACK;
                return WPS_CONTINUE;
@@ -1011,12 +1123,6 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
        if (wps_parse_msg(msg, &attr) < 0)
                return WPS_FAILURE;
 
-       if (!wps_version_supported(attr.version)) {
-               wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
-                          attr.version ? *attr.version : 0);
-               return WPS_FAILURE;
-       }
-
        if (attr.enrollee_nonce == NULL ||
            os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
                wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
@@ -1025,30 +1131,44 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
 
        if (attr.msg_type == NULL) {
                wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
-               return WPS_FAILURE;
+               wps->state = SEND_WSC_NACK;
+               return WPS_CONTINUE;
        }
 
        switch (*attr.msg_type) {
        case WPS_M2:
+               if (wps_validate_m2(msg) < 0)
+                       return WPS_FAILURE;
                ret = wps_process_m2(wps, msg, &attr);
                break;
        case WPS_M2D:
+               if (wps_validate_m2d(msg) < 0)
+                       return WPS_FAILURE;
                ret = wps_process_m2d(wps, &attr);
                break;
        case WPS_M4:
+               if (wps_validate_m4(msg) < 0)
+                       return WPS_FAILURE;
                ret = wps_process_m4(wps, msg, &attr);
                if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
-                       wps_fail_event(wps->wps, WPS_M4);
+                       wps_fail_event(wps->wps, WPS_M4, wps->config_error,
+                                      wps->error_indication);
                break;
        case WPS_M6:
+               if (wps_validate_m6(msg) < 0)
+                       return WPS_FAILURE;
                ret = wps_process_m6(wps, msg, &attr);
                if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
-                       wps_fail_event(wps->wps, WPS_M6);
+                       wps_fail_event(wps->wps, WPS_M6, wps->config_error,
+                                      wps->error_indication);
                break;
        case WPS_M8:
+               if (wps_validate_m8(msg) < 0)
+                       return WPS_FAILURE;
                ret = wps_process_m8(wps, msg, &attr);
                if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
-                       wps_fail_event(wps->wps, WPS_M8);
+                       wps_fail_event(wps->wps, WPS_M8, wps->config_error,
+                                      wps->error_indication);
                break;
        default:
                wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d",
@@ -1084,12 +1204,6 @@ static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
        if (wps_parse_msg(msg, &attr) < 0)
                return WPS_FAILURE;
 
-       if (!wps_version_supported(attr.version)) {
-               wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
-                          attr.version ? *attr.version : 0);
-               return WPS_FAILURE;
-       }
-
        if (attr.msg_type == NULL) {
                wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
                return WPS_FAILURE;
@@ -1130,18 +1244,13 @@ static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
                                                 const struct wpabuf *msg)
 {
        struct wps_parse_attr attr;
+       u16 config_error;
 
        wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK");
 
        if (wps_parse_msg(msg, &attr) < 0)
                return WPS_FAILURE;
 
-       if (!wps_version_supported(attr.version)) {
-               wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
-                          attr.version ? *attr.version : 0);
-               return WPS_FAILURE;
-       }
-
        if (attr.msg_type == NULL) {
                wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
                return WPS_FAILURE;
@@ -1180,18 +1289,22 @@ static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
                return WPS_FAILURE;
        }
 
+       config_error = WPA_GET_BE16(attr.config_error);
        wpa_printf(MSG_DEBUG, "WPS: Registrar terminated negotiation with "
-                  "Configuration Error %d", WPA_GET_BE16(attr.config_error));
+                  "Configuration Error %d", config_error);
 
        switch (wps->state) {
        case RECV_M4:
-               wps_fail_event(wps->wps, WPS_M3);
+               wps_fail_event(wps->wps, WPS_M3, config_error,
+                              wps->error_indication);
                break;
        case RECV_M6:
-               wps_fail_event(wps->wps, WPS_M5);
+               wps_fail_event(wps->wps, WPS_M5, config_error,
+                              wps->error_indication);
                break;
        case RECV_M8:
-               wps_fail_event(wps->wps, WPS_M7);
+               wps_fail_event(wps->wps, WPS_M7, config_error,
+                              wps->error_indication);
                break;
        default:
                break;
@@ -1230,8 +1343,12 @@ enum wps_process_res wps_enrollee_process_msg(struct wps_data *wps,
        case WSC_UPnP:
                return wps_process_wsc_msg(wps, msg);
        case WSC_ACK:
+               if (wps_validate_wsc_ack(msg) < 0)
+                       return WPS_FAILURE;
                return wps_process_wsc_ack(wps, msg);
        case WSC_NACK:
+               if (wps_validate_wsc_nack(msg) < 0)
+                       return WPS_FAILURE;
                return wps_process_wsc_nack(wps, msg);
        default:
                wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code);
index e0cdd1d..856e9fb 100644 (file)
@@ -62,11 +62,15 @@ static void wps_er_sta_event(struct wps_context *wps, struct wps_er_sta *sta,
 }
 
 
-static struct wps_er_sta * wps_er_sta_get(struct wps_er_ap *ap, const u8 *addr)
+static struct wps_er_sta * wps_er_sta_get(struct wps_er_ap *ap, const u8 *addr,
+                                         const u8 *uuid)
 {
        struct wps_er_sta *sta;
        dl_list_for_each(sta, &ap->sta, struct wps_er_sta, list) {
-               if (os_memcmp(sta->addr, addr, ETH_ALEN) == 0)
+               if ((addr == NULL ||
+                    os_memcmp(sta->addr, addr, ETH_ALEN) == 0) &&
+                   (uuid == NULL ||
+                    os_memcmp(uuid, sta->uuid, WPS_UUID_LEN) == 0))
                        return sta;
        }
        return NULL;
@@ -275,6 +279,64 @@ fail:
        wps_er_ap_unsubscribed(ap->er, ap);
 }
 
+
+static struct wps_er_ap_settings * wps_er_ap_get_settings(struct wps_er *er,
+                                                         const u8 *uuid)
+{
+       struct wps_er_ap_settings *s;
+       dl_list_for_each(s, &er->ap_settings, struct wps_er_ap_settings, list)
+               if (os_memcmp(uuid, s->uuid, WPS_UUID_LEN) == 0)
+                       return s;
+       return NULL;
+}
+
+
+int wps_er_ap_cache_settings(struct wps_er *er, struct in_addr *addr)
+{
+       struct wps_er_ap *ap;
+       struct wps_er_ap_settings *settings;
+
+       ap = wps_er_ap_get(er, addr, NULL);
+       if (ap == NULL || ap->ap_settings == NULL)
+               return -1;
+
+       settings = wps_er_ap_get_settings(er, ap->uuid);
+       if (!settings) {
+               settings = os_zalloc(sizeof(*settings));
+               if (settings == NULL)
+                       return -1;
+               os_memcpy(settings->uuid, ap->uuid, WPS_UUID_LEN);
+               dl_list_add(&er->ap_settings, &settings->list);
+       }
+       os_memcpy(&settings->ap_settings, ap->ap_settings,
+                 sizeof(struct wps_credential));
+
+       return 0;
+}
+
+
+static int wps_er_ap_use_cached_settings(struct wps_er *er,
+                                        struct wps_er_ap *ap)
+{
+       struct wps_er_ap_settings *s;
+
+       if (ap->ap_settings)
+               return 0;
+
+       s = wps_er_ap_get_settings(ap->er, ap->uuid);
+       if (!s)
+               return -1;
+
+       ap->ap_settings = os_malloc(sizeof(*ap->ap_settings));
+       if (ap->ap_settings == NULL)
+               return -1;
+
+       os_memcpy(ap->ap_settings, &s->ap_settings, sizeof(*ap->ap_settings));
+       wpa_printf(MSG_DEBUG, "WPS ER: Use cached AP settings");
+       return 0;
+}
+
+
 static void wps_er_ap_remove_entry(struct wps_er *er, struct wps_er_ap *ap)
 {
        wpa_printf(MSG_DEBUG, "WPS ER: Removing AP entry for %s (%s)",
@@ -352,6 +414,7 @@ static void wps_er_http_subscribe_cb(void *ctx, struct http_client *c,
                wpa_printf(MSG_DEBUG, "WPS ER: Subscribed to events");
                ap->subscribed = 1;
                wps_er_get_sid(ap, http_client_get_hdr_line(c, "SID"));
+               wps_er_ap_use_cached_settings(ap->er, ap);
                wps_er_ap_event(ap->er->wps, ap, WPS_EV_ER_AP_ADD);
                break;
        case HTTP_CLIENT_FAILED:
@@ -439,16 +502,61 @@ static void wps_er_get_device_info(struct wps_er_ap *ap)
 }
 
 
+static const char * wps_er_find_wfadevice(const char *data)
+{
+       const char *tag, *tagname, *end;
+       char *val;
+       int found = 0;
+
+       while (!found) {
+               /* Find next <device> */
+               for (;;) {
+                       if (xml_next_tag(data, &tag, &tagname, &end))
+                               return NULL;
+                       data = end;
+                       if (!os_strncasecmp(tagname, "device", 6) &&
+                           *tag != '/' &&
+                           (tagname[6] == '>' || !isgraph(tagname[6]))) {
+                               break;
+                       }
+               }
+
+               /* Check whether deviceType is WFADevice */
+               val = xml_get_first_item(data, "deviceType");
+               if (val == NULL)
+                       return NULL;
+               wpa_printf(MSG_DEBUG, "WPS ER: Found deviceType '%s'", val);
+               found = os_strcasecmp(val, "urn:schemas-wifialliance-org:"
+                                     "device:WFADevice:1") == 0;
+               os_free(val);
+       }
+
+       return data;
+}
+
+
 static void wps_er_parse_device_description(struct wps_er_ap *ap,
                                            struct wpabuf *reply)
 {
        /* Note: reply includes null termination after the buffer data */
-       const char *data = wpabuf_head(reply);
+       const char *tmp, *data = wpabuf_head(reply);
        char *pos;
 
        wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Device info",
                          wpabuf_head(reply), wpabuf_len(reply));
 
+       /*
+        * The root device description may include multiple devices, so first
+        * find the beginning of the WFADevice description to allow the
+        * simplistic parser to pick the correct entries.
+        */
+       tmp = wps_er_find_wfadevice(data);
+       if (tmp == NULL) {
+               wpa_printf(MSG_DEBUG, "WPS ER: WFADevice:1 device not found - "
+                          "trying to parse invalid data");
+       } else
+               data = tmp;
+
        ap->friendly_name = xml_get_first_item(data, "friendlyName");
        wpa_printf(MSG_DEBUG, "WPS ER: friendlyName='%s'", ap->friendly_name);
 
@@ -583,8 +691,12 @@ void wps_er_ap_remove(struct wps_er *er, struct in_addr *addr)
 static void wps_er_ap_remove_all(struct wps_er *er)
 {
        struct wps_er_ap *prev, *ap;
+       struct wps_er_ap_settings *prev_s, *s;
        dl_list_for_each_safe(ap, prev, &er->ap, struct wps_er_ap, list)
                wps_er_ap_remove_entry(er, ap);
+       dl_list_for_each_safe(s, prev_s, &er->ap_settings,
+                             struct wps_er_ap_settings, list)
+               os_free(s);
 }
 
 
@@ -649,7 +761,7 @@ static struct wps_er_sta * wps_er_add_sta_data(struct wps_er_ap *ap,
                                               struct wps_parse_attr *attr,
                                               int probe_req)
 {
-       struct wps_er_sta *sta = wps_er_sta_get(ap, addr);
+       struct wps_er_sta *sta = wps_er_sta_get(ap, addr, NULL);
        int new_sta = 0;
        int m1;
 
@@ -756,6 +868,12 @@ static void wps_er_process_wlanevent_probe_req(struct wps_er_ap *ap,
        wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message "
                        "(TLVs from Probe Request)", msg);
 
+       if (wps_validate_probe_req(msg, addr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: ER: Ignore invalid proxied "
+                          "Probe Request frame from " MACSTR, MAC2STR(addr));
+               return;
+       }
+
        if (wps_parse_msg(msg, &attr) < 0) {
                wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in "
                           "WLANEvent message");
@@ -763,6 +881,7 @@ static void wps_er_process_wlanevent_probe_req(struct wps_er_ap *ap,
        }
 
        wps_er_add_sta_data(ap, addr, &attr, 1);
+       wps_registrar_probe_req_rx(ap->er->wps->registrar, addr, msg, 0);
 }
 
 
@@ -1151,7 +1270,7 @@ static void wps_er_http_req(void *ctx, struct http_request *req)
 
 
 struct wps_er *
-wps_er_init(struct wps_context *wps, const char *ifname)
+wps_er_init(struct wps_context *wps, const char *ifname, const char *filter)
 {
        struct wps_er *er;
        struct in_addr addr;
@@ -1161,6 +1280,7 @@ wps_er_init(struct wps_context *wps, const char *ifname)
                return NULL;
        dl_list_init(&er->ap);
        dl_list_init(&er->ap_unsubscribing);
+       dl_list_init(&er->ap_settings);
 
        er->multicast_sd = -1;
        er->ssdp_sd = -1;
@@ -1175,6 +1295,16 @@ wps_er_init(struct wps_context *wps, const char *ifname)
        /* Limit event_id to < 32 bits to avoid issues with atoi() */
        er->event_id &= 0x0fffffff;
 
+       if (filter) {
+               if (inet_aton(filter, &er->filter_addr) == 0) {
+                       wpa_printf(MSG_INFO, "WPS UPnP: Invalid filter "
+                                  "address %s", filter);
+                       wps_er_deinit(er, NULL, NULL);
+                       return NULL;
+               }
+               wpa_printf(MSG_DEBUG, "WPS UPnP: Only accepting connections "
+                          "with %s", filter);
+       }
        if (get_netif_info(ifname, &er->ip_addr, &er->ip_addr_text,
                           er->mac_addr)) {
                wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
@@ -1184,6 +1314,7 @@ wps_er_init(struct wps_context *wps, const char *ifname)
        }
 
        if (wps_er_ssdp_init(er) < 0) {
+               wpa_printf(MSG_INFO, "WPS UPnP: SSDP initialization failed");
                wps_er_deinit(er, NULL, NULL);
                return NULL;
        }
@@ -1191,6 +1322,7 @@ wps_er_init(struct wps_context *wps, const char *ifname)
        addr.s_addr = er->ip_addr;
        er->http_srv = http_server_init(&addr, -1, wps_er_http_req, er);
        if (er->http_srv == NULL) {
+               wpa_printf(MSG_INFO, "WPS UPnP: HTTP initialization failed");
                wps_er_deinit(er, NULL, NULL);
                return NULL;
        }
@@ -1256,19 +1388,30 @@ static void wps_er_http_set_sel_reg_cb(void *ctx, struct http_client *c,
                                       enum http_client_event event)
 {
        struct wps_er_ap *ap = ctx;
+       union wps_event_data data;
+
+       os_memset(&data, 0, sizeof(data));
 
        switch (event) {
        case HTTP_CLIENT_OK:
                wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar OK");
+               data.set_sel_reg.state = WPS_ER_SET_SEL_REG_DONE;
+               data.set_sel_reg.uuid = ap->uuid;
                break;
        case HTTP_CLIENT_FAILED:
        case HTTP_CLIENT_INVALID_REPLY:
        case HTTP_CLIENT_TIMEOUT:
                wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar failed");
+               data.set_sel_reg.state = WPS_ER_SET_SEL_REG_FAILED;
+               data.set_sel_reg.uuid = ap->uuid;
                break;
        }
        http_client_free(ap->http);
        ap->http = NULL;
+
+       if (data.set_sel_reg.uuid)
+               ap->er->wps->event_cb(ap->er->wps->cb_ctx,
+                                     WPS_EV_ER_SET_SELECTED_REGISTRAR, &data);
 }
 
 
@@ -1290,6 +1433,12 @@ static void wps_er_send_set_sel_reg(struct wps_er_ap *ap, struct wpabuf *msg)
                return;
        }
 
+       if (ap->wps) {
+               wpa_printf(MSG_DEBUG, "WPS ER: Pending WPS operation for AP - "
+                          "skip SetSelectedRegistrar");
+               return;
+       }
+
        url = http_client_url_parse(ap->control_url, &dst, &path);
        if (url == NULL) {
                wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
@@ -1339,26 +1488,74 @@ static int wps_er_build_sel_reg_config_methods(struct wpabuf *msg,
 }
 
 
+static int wps_er_build_uuid_r(struct wpabuf *msg, const u8 *uuid_r)
+{
+#ifdef CONFIG_WPS2
+       wpabuf_put_be16(msg, ATTR_UUID_R);
+       wpabuf_put_be16(msg, WPS_UUID_LEN);
+       wpabuf_put_data(msg, uuid_r, WPS_UUID_LEN);
+#endif /* CONFIG_WPS2 */
+       return 0;
+}
+
+
 void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
                        u16 sel_reg_config_methods)
 {
        struct wpabuf *msg;
        struct wps_er_ap *ap;
+       struct wps_registrar *reg = er->wps->registrar;
+       const u8 *auth_macs;
+#ifdef CONFIG_WPS2
+       u8 bcast[ETH_ALEN];
+#endif /* CONFIG_WPS2 */
+       size_t count;
+       union wps_event_data data;
+
+       if (er->skip_set_sel_reg) {
+               wpa_printf(MSG_DEBUG, "WPS ER: Skip SetSelectedRegistrar");
+               return;
+       }
 
        msg = wpabuf_alloc(500);
        if (msg == NULL)
                return;
 
+       auth_macs = wps_authorized_macs(reg, &count);
+#ifdef CONFIG_WPS2
+       if (count == 0) {
+               os_memset(bcast, 0xff, ETH_ALEN);
+               auth_macs = bcast;
+               count = 1;
+       }
+#endif /* CONFIG_WPS2 */
+
        if (wps_build_version(msg) ||
            wps_er_build_selected_registrar(msg, sel_reg) ||
            wps_er_build_dev_password_id(msg, dev_passwd_id) ||
-           wps_er_build_sel_reg_config_methods(msg, sel_reg_config_methods)) {
+           wps_er_build_sel_reg_config_methods(msg, sel_reg_config_methods) ||
+           wps_build_wfa_ext(msg, 0, auth_macs, count) ||
+           wps_er_build_uuid_r(msg, er->wps->uuid)) {
                wpabuf_free(msg);
                return;
        }
 
-       dl_list_for_each(ap, &er->ap, struct wps_er_ap, list)
+       os_memset(&data, 0, sizeof(data));
+       data.set_sel_reg.sel_reg = sel_reg;
+       data.set_sel_reg.dev_passwd_id = dev_passwd_id;
+       data.set_sel_reg.sel_reg_config_methods = sel_reg_config_methods;
+       data.set_sel_reg.state = WPS_ER_SET_SEL_REG_START;
+
+       dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
+               if (er->set_sel_reg_uuid_filter &&
+                   os_memcmp(ap->uuid, er->set_sel_reg_uuid_filter,
+                             WPS_UUID_LEN) != 0)
+                       continue;
+               data.set_sel_reg.uuid = ap->uuid;
+               er->wps->event_cb(er->wps->cb_ctx,
+                                 WPS_EV_ER_SET_SELECTED_REGISTRAR, &data);
                wps_er_send_set_sel_reg(ap, msg);
+       }
 
        wpabuf_free(msg);
 }
@@ -1366,16 +1563,41 @@ 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 res;
+       struct wps_er_ap *ap;
+
        if (er == NULL || er->wps == NULL)
                return -1;
 
-       /*
-        * TODO: Should enable PBC mode only in a single AP based on which AP
-        * the Enrollee (uuid) is using. Now, we may end up enabling multiple
-        * APs in PBC mode which could result in session overlap at the
-        * Enrollee.
-        */
-       if (wps_registrar_button_pushed(er->wps->registrar))
+       if (wps_registrar_pbc_overlap(er->wps->registrar, NULL, NULL)) {
+               wpa_printf(MSG_DEBUG, "WPS ER: PBC overlap - do not start PBC "
+                          "mode");
+               return -2;
+       }
+
+       ap = wps_er_ap_get(er, NULL, uuid);
+       if (ap == NULL) {
+               struct wps_er_sta *sta = NULL;
+               dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
+                       sta = wps_er_sta_get(ap, NULL, uuid);
+                       if (sta) {
+                               uuid = ap->uuid;
+                               break;
+                       }
+               }
+               if (sta == NULL)
+                       return -3; /* Unknown UUID */
+       }
+
+       if (ap->ap_settings == NULL) {
+               wpa_printf(MSG_DEBUG, "WPS ER: AP settings not known");
+               return -4;
+       }
+
+       er->set_sel_reg_uuid_filter = uuid;
+       res = wps_registrar_button_pushed(er->wps->registrar, NULL);
+       er->set_sel_reg_uuid_filter = NULL;
+       if (res)
                return -1;
 
        return 0;
@@ -1385,6 +1607,8 @@ int wps_er_pbc(struct wps_er *er, const u8 *uuid)
 static void wps_er_ap_settings_cb(void *ctx, const struct wps_credential *cred)
 {
        struct wps_er_ap *ap = ctx;
+       union wps_event_data data;
+
        wpa_printf(MSG_DEBUG, "WPS ER: AP Settings received");
        os_free(ap->ap_settings);
        ap->ap_settings = os_malloc(sizeof(*cred));
@@ -1393,7 +1617,11 @@ static void wps_er_ap_settings_cb(void *ctx, const struct wps_credential *cred)
                ap->ap_settings->cred_attr = NULL;
        }
 
-       /* TODO: send info through ctrl_iface */
+       os_memset(&data, 0, sizeof(data));
+       data.ap_settings.uuid = ap->uuid;
+       data.ap_settings.cred = cred;
+       ap->er->wps->event_cb(ap->er->wps->cb_ctx, WPS_EV_ER_AP_SETTINGS,
+                             &data);
 }
 
 
@@ -1436,6 +1664,8 @@ static void wps_er_http_put_message_cb(void *ctx, struct http_client *c,
                if (buf == NULL) {
                        wpa_printf(MSG_DEBUG, "WPS ER: Could not extract "
                                   "NewOutMessage from PutMessage response");
+                       wps_deinit(ap->wps);
+                       ap->wps = NULL;
                        return;
                }
                wps_er_ap_process(ap, buf);
@@ -1487,10 +1717,26 @@ static void wps_er_ap_put_message(struct wps_er_ap *ap,
 static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg)
 {
        enum wps_process_res res;
+       struct wps_parse_attr attr;
+       enum wsc_op_code op_code;
+
+       op_code = WSC_MSG;
+       if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type) {
+               switch (*attr.msg_type) {
+               case WPS_WSC_ACK:
+                       op_code = WSC_ACK;
+                       break;
+               case WPS_WSC_NACK:
+                       op_code = WSC_NACK;
+                       break;
+               case WPS_WSC_DONE:
+                       op_code = WSC_Done;
+                       break;
+               }
+       }
 
-       res = wps_process_msg(ap->wps, WSC_MSG, msg);
+       res = wps_process_msg(ap->wps, op_code, msg);
        if (res == WPS_CONTINUE) {
-               enum wsc_op_code op_code;
                struct wpabuf *next = wps_get_msg(ap->wps, &op_code);
                if (next) {
                        wps_er_ap_put_message(ap, next);
@@ -1501,6 +1747,10 @@ static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg)
                        wps_deinit(ap->wps);
                        ap->wps = NULL;
                }
+       } else if (res == WPS_DONE) {
+               wpa_printf(MSG_DEBUG, "WPS ER: Protocol run done");
+               wps_deinit(ap->wps);
+               ap->wps = NULL;
        } else {
                wpa_printf(MSG_DEBUG, "WPS ER: Failed to process message from "
                           "AP (res=%d)", res);
@@ -1656,8 +1906,99 @@ int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
        if (wps_er_send_get_device_info(ap, wps_er_ap_learn_m1) < 0)
                return -1;
 
-       /* TODO: add PIN without SetSelectedRegistrar trigger to all APs */
-       wps_registrar_add_pin(er->wps->registrar, uuid, pin, pin_len, 0);
+       er->skip_set_sel_reg = 1;
+       wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0);
+       er->skip_set_sel_reg = 0;
+
+       return 0;
+}
+
+
+int wps_er_set_config(struct wps_er *er, const u8 *uuid,
+                     const struct wps_credential *cred)
+{
+       struct wps_er_ap *ap;
+
+       if (er == NULL)
+               return -1;
+
+       ap = wps_er_ap_get(er, NULL, uuid);
+       if (ap == NULL) {
+               wpa_printf(MSG_DEBUG, "WPS ER: AP not found for set config "
+                          "request");
+               return -1;
+       }
+
+       os_free(ap->ap_settings);
+       ap->ap_settings = os_malloc(sizeof(*cred));
+       if (ap->ap_settings == NULL)
+               return -1;
+       os_memcpy(ap->ap_settings, cred, sizeof(*cred));
+       ap->ap_settings->cred_attr = NULL;
+       wpa_printf(MSG_DEBUG, "WPS ER: Updated local AP settings based set "
+                  "config request");
+
+       return 0;
+}
+
+
+static void wps_er_ap_config_m1(struct wps_er_ap *ap, struct wpabuf *m1)
+{
+       struct wps_config cfg;
+
+       if (ap->wps) {
+               wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in "
+                          "progress with this AP");
+               return;
+       }
+
+       os_memset(&cfg, 0, sizeof(cfg));
+       cfg.wps = ap->er->wps;
+       cfg.registrar = 1;
+       cfg.new_ap_settings = ap->ap_settings;
+       ap->wps = wps_init(&cfg);
+       if (ap->wps == NULL)
+               return;
+       ap->wps->ap_settings_cb = NULL;
+       ap->wps->ap_settings_cb_ctx = NULL;
+
+       wps_er_ap_process(ap, m1);
+}
+
+
+int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin,
+                 size_t pin_len, const struct wps_credential *cred)
+{
+       struct wps_er_ap *ap;
+
+       if (er == NULL)
+               return -1;
+
+       ap = wps_er_ap_get(er, NULL, uuid);
+       if (ap == NULL) {
+               wpa_printf(MSG_DEBUG, "WPS ER: AP not found for config "
+                          "request");
+               return -1;
+       }
+       if (ap->wps) {
+               wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
+                          "with the AP - cannot start config");
+               return -1;
+       }
+
+       os_free(ap->ap_settings);
+       ap->ap_settings = os_malloc(sizeof(*cred));
+       if (ap->ap_settings == NULL)
+               return -1;
+       os_memcpy(ap->ap_settings, cred, sizeof(*cred));
+       ap->ap_settings->cred_attr = NULL;
+
+       if (wps_er_send_get_device_info(ap, wps_er_ap_config_m1) < 0)
+               return -1;
+
+       er->skip_set_sel_reg = 1;
+       wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0);
+       er->skip_set_sel_reg = 0;
 
        return 0;
 }
index b13b950..5388ed1 100644 (file)
@@ -73,6 +73,12 @@ struct wps_er_ap {
        void (*m1_handler)(struct wps_er_ap *ap, struct wpabuf *m1);
 };
 
+struct wps_er_ap_settings {
+       struct dl_list list;
+       u8 uuid[WPS_UUID_LEN];
+       struct wps_credential ap_settings;
+};
+
 struct wps_er {
        struct wps_context *wps;
        char ifname[17];
@@ -83,6 +89,7 @@ struct wps_er {
        int ssdp_sd;
        struct dl_list ap;
        struct dl_list ap_unsubscribing;
+       struct dl_list ap_settings;
        struct http_server *http_srv;
        int http_port;
        unsigned int next_ap_id;
@@ -90,6 +97,9 @@ struct wps_er {
        int deinitializing;
        void (*deinit_done_cb)(void *ctx);
        void *deinit_done_ctx;
+       struct in_addr filter_addr;
+       int skip_set_sel_reg;
+       const u8 *set_sel_reg_uuid_filter;
 };
 
 
@@ -97,6 +107,7 @@ struct wps_er {
 void wps_er_ap_add(struct wps_er *er, const u8 *uuid, struct in_addr *addr,
                   const char *location, int max_age);
 void wps_er_ap_remove(struct wps_er *er, struct in_addr *addr);
+int wps_er_ap_cache_settings(struct wps_er *er, struct in_addr *addr);
 
 /* wps_er_ssdp.c */
 int wps_er_ssdp_init(struct wps_er *er);
index f108435..83de9ad 100644 (file)
@@ -41,6 +41,9 @@ static void wps_er_ssdp_rx(int sd, void *eloop_ctx, void *sock_ctx)
        if (nread <= 0)
                return;
        buf[nread] = '\0';
+       if (er->filter_addr.s_addr &&
+           er->filter_addr.s_addr != addr.sin_addr.s_addr)
+               return;
 
        wpa_printf(MSG_DEBUG, "WPS ER: Received SSDP from %s",
                   inet_ntoa(addr.sin_addr));
@@ -110,6 +113,7 @@ static void wps_er_ssdp_rx(int sd, void *eloop_ctx, void *sock_ctx)
                return; /* Not WPS advertisement/reply */
 
        if (byebye) {
+               wps_er_ap_cache_settings(er, &addr.sin_addr);
                wps_er_ap_remove(er, &addr.sin_addr);
                return;
        }
@@ -162,16 +166,25 @@ void wps_er_send_ssdp_msearch(struct wps_er *er)
 
 int wps_er_ssdp_init(struct wps_er *er)
 {
-       if (add_ssdp_network(er->ifname))
+       if (add_ssdp_network(er->ifname)) {
+               wpa_printf(MSG_INFO, "WPS ER: Failed to add routing entry for "
+                          "SSDP");
                return -1;
+       }
 
        er->multicast_sd = ssdp_open_multicast_sock(er->ip_addr);
-       if (er->multicast_sd < 0)
+       if (er->multicast_sd < 0) {
+               wpa_printf(MSG_INFO, "WPS ER: Failed to open multicast socket "
+                          "for SSDP");
                return -1;
+       }
 
        er->ssdp_sd = ssdp_listener_open();
-       if (er->ssdp_sd < 0)
+       if (er->ssdp_sd < 0) {
+               wpa_printf(MSG_INFO, "WPS ER: Failed to open SSDP listener "
+                          "socket");
                return -1;
+       }
 
        if (eloop_register_sock(er->multicast_sd, EVENT_TYPE_READ,
                                wps_er_ssdp_rx, er, NULL) ||
index 50e66f6..bdb6da2 100644 (file)
@@ -102,6 +102,7 @@ struct wps_data {
         * config_error - Configuration Error value to be used in NACK
         */
        u16 config_error;
+       u16 error_indication;
 
        int ext_reg;
        int int_reg;
@@ -116,12 +117,16 @@ struct wps_data {
        struct wps_credential *use_cred;
 
        int use_psk_key;
+       u8 p2p_dev_addr[ETH_ALEN]; /* P2P Device Address of the client or
+                                   * 00:00:00:00:00:00 if not a P2p client */
+       int pbc_in_m1;
 };
 
 
 struct wps_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 */
@@ -162,6 +167,9 @@ struct wps_parse_attr {
        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;
@@ -186,12 +194,24 @@ struct wps_parse_attr {
        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;
 };
 
 /* wps_common.c */
@@ -202,7 +222,8 @@ void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
                    size_t dev_passwd_len);
 struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
                                          size_t encr_len);
-void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg);
+void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
+                   u16 config_error, u16 error_indication);
 void wps_success_event(struct wps_context *wps);
 void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part);
 void wps_pbc_overlap_event(struct wps_context *wps);
@@ -212,6 +233,9 @@ 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);
 
@@ -228,6 +252,8 @@ int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg);
 int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
                            struct wpabuf *plain);
 int wps_build_version(struct wpabuf *msg);
+int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
+                     const u8 *auth_macs, size_t auth_macs_count);
 int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type);
 int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg);
 int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg);
@@ -236,6 +262,7 @@ 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);
+struct wpabuf * wps_ie_encapsulate(struct wpabuf *data);
 
 /* wps_attr_process.c */
 int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
@@ -264,15 +291,12 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg);
 int wps_device_store(struct wps_registrar *reg,
                     struct wps_device_data *dev, const u8 *uuid);
 void wps_registrar_selected_registrar_changed(struct wps_registrar *reg);
+const u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count);
+int wps_registrar_pbc_overlap(struct wps_registrar *reg,
+                             const u8 *addr, const u8 *uuid_e);
 
 /* ndef.c */
 struct wpabuf * ndef_parse_wifi(struct wpabuf *buf);
 struct wpabuf * ndef_build_wifi(struct wpabuf *buf);
 
-static inline int wps_version_supported(const u8 *version)
-{
-       /* Require major version match, but allow minor version differences */
-       return version && (*version & 0xf0) == (WPS_VERSION & 0xf0);
-}
-
 #endif /* WPS_I_H */
index 81ddf3a..eda1c70 100644 (file)
 #include "utils/list.h"
 #include "crypto/crypto.h"
 #include "crypto/sha256.h"
+#include "crypto/random.h"
 #include "common/ieee802_11_defs.h"
 #include "wps_i.h"
 #include "wps_dev_attr.h"
 #include "wps_upnp.h"
 #include "wps_upnp_i.h"
 
+#ifndef CONFIG_WPS_STRICT
 #define WPS_WORKAROUNDS
+#endif /* CONFIG_WPS_STRICT */
 
 struct wps_uuid_pin {
        struct dl_list list;
@@ -39,6 +42,7 @@ struct wps_uuid_pin {
 #define PIN_EXPIRES BIT(1)
        int flags;
        struct os_time expiration;
+       u8 enrollee_addr[ETH_ALEN];
 };
 
 
@@ -123,10 +127,16 @@ struct wps_registrar {
        int sel_reg_dev_password_id_override;
        int sel_reg_config_methods_override;
        int static_wep_only;
+       int dualband;
 
        struct wps_registrar_device *devices;
 
        int force_pbc_overlap;
+
+       u8 authorized_macs[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];
+       u8 authorized_macs_union[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];
+
+       u8 p2p_dev_addr[ETH_ALEN];
 };
 
 
@@ -136,6 +146,52 @@ static void wps_registrar_set_selected_timeout(void *eloop_ctx,
                                               void *timeout_ctx);
 
 
+static void wps_registrar_add_authorized_mac(struct wps_registrar *reg,
+                                            const u8 *addr)
+{
+       int i;
+       wpa_printf(MSG_DEBUG, "WPS: Add authorized MAC " MACSTR,
+                  MAC2STR(addr));
+       for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++)
+               if (os_memcmp(reg->authorized_macs[i], addr, ETH_ALEN) == 0) {
+                       wpa_printf(MSG_DEBUG, "WPS: Authorized MAC was "
+                                  "already in the list");
+                       return; /* already in list */
+               }
+       for (i = WPS_MAX_AUTHORIZED_MACS - 1; i > 0; i--)
+               os_memcpy(reg->authorized_macs[i], reg->authorized_macs[i - 1],
+                         ETH_ALEN);
+       os_memcpy(reg->authorized_macs[0], addr, ETH_ALEN);
+       wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs",
+                   (u8 *) reg->authorized_macs, sizeof(reg->authorized_macs));
+}
+
+
+static void wps_registrar_remove_authorized_mac(struct wps_registrar *reg,
+                                               const u8 *addr)
+{
+       int i;
+       wpa_printf(MSG_DEBUG, "WPS: Remove authorized MAC " MACSTR,
+                  MAC2STR(addr));
+       for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++) {
+               if (os_memcmp(reg->authorized_macs, addr, ETH_ALEN) == 0)
+                       break;
+       }
+       if (i == WPS_MAX_AUTHORIZED_MACS) {
+               wpa_printf(MSG_DEBUG, "WPS: Authorized MAC was not in the "
+                          "list");
+               return; /* not in the list */
+       }
+       for (; i + 1 < WPS_MAX_AUTHORIZED_MACS; i++)
+               os_memcpy(reg->authorized_macs[i], reg->authorized_macs[i + 1],
+                         ETH_ALEN);
+       os_memset(reg->authorized_macs[WPS_MAX_AUTHORIZED_MACS - 1], 0,
+                 ETH_ALEN);
+       wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs",
+                   (u8 *) reg->authorized_macs, sizeof(reg->authorized_macs));
+}
+
+
 static void wps_free_devices(struct wps_registrar_device *dev)
 {
        struct wps_registrar_device *prev;
@@ -254,20 +310,29 @@ static void wps_registrar_add_pbc_session(struct wps_registrar *reg,
 
 
 static void wps_registrar_remove_pbc_session(struct wps_registrar *reg,
-                                            const u8 *addr, const u8 *uuid_e)
+                                            const u8 *uuid_e,
+                                            const u8 *p2p_dev_addr)
 {
-       struct wps_pbc_session *pbc, *prev = NULL;
+       struct wps_pbc_session *pbc, *prev = NULL, *tmp;
 
        pbc = reg->pbc_sessions;
        while (pbc) {
-               if (os_memcmp(pbc->addr, addr, ETH_ALEN) == 0 &&
-                   os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0) {
+               if (os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0 ||
+                   (p2p_dev_addr && !is_zero_ether_addr(reg->p2p_dev_addr) &&
+                    os_memcmp(reg->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) ==
+                    0)) {
                        if (prev)
                                prev->next = pbc->next;
                        else
                                reg->pbc_sessions = pbc->next;
-                       os_free(pbc);
-                       break;
+                       tmp = pbc;
+                       pbc = pbc->next;
+                       wpa_printf(MSG_DEBUG, "WPS: Removing PBC session for "
+                                  "addr=" MACSTR, MAC2STR(tmp->addr));
+                       wpa_hexdump(MSG_DEBUG, "WPS: Removed UUID-E",
+                                   tmp->uuid_e, WPS_UUID_LEN);
+                       os_free(tmp);
+                       continue;
                }
                prev = pbc;
                pbc = pbc->next;
@@ -275,26 +340,50 @@ static void wps_registrar_remove_pbc_session(struct wps_registrar *reg,
 }
 
 
-static int wps_registrar_pbc_overlap(struct wps_registrar *reg,
-                                    const u8 *addr, const u8 *uuid_e)
+int wps_registrar_pbc_overlap(struct wps_registrar *reg,
+                             const u8 *addr, const u8 *uuid_e)
 {
        int count = 0;
        struct wps_pbc_session *pbc;
+       struct wps_pbc_session *first = NULL;
        struct os_time now;
 
        os_get_time(&now);
 
+       wpa_printf(MSG_DEBUG, "WPS: Checking active PBC sessions for overlap");
+
+       if (uuid_e) {
+               wpa_printf(MSG_DEBUG, "WPS: Add one for the requested UUID");
+               wpa_hexdump(MSG_DEBUG, "WPS: Requested UUID",
+                           uuid_e, WPS_UUID_LEN);
+               count++;
+       }
+
        for (pbc = reg->pbc_sessions; pbc; pbc = pbc->next) {
-               if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME)
+               wpa_printf(MSG_DEBUG, "WPS: Consider PBC session with " MACSTR,
+                          MAC2STR(pbc->addr));
+               wpa_hexdump(MSG_DEBUG, "WPS: UUID-E",
+                           pbc->uuid_e, WPS_UUID_LEN);
+               if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME) {
+                       wpa_printf(MSG_DEBUG, "WPS: PBC walk time has "
+                                  "expired");
                        break;
-               if (addr == NULL || os_memcmp(addr, pbc->addr, ETH_ALEN) ||
-                   uuid_e == NULL ||
-                   os_memcmp(uuid_e, pbc->uuid_e, WPS_UUID_LEN))
+               }
+               if (first &&
+                   os_memcmp(pbc->uuid_e, first->uuid_e, WPS_UUID_LEN) == 0) {
+                       wpa_printf(MSG_DEBUG, "WPS: Same Enrollee");
+                       continue; /* same Enrollee */
+               }
+               if (uuid_e == NULL ||
+                   os_memcmp(uuid_e, pbc->uuid_e, WPS_UUID_LEN)) {
+                       wpa_printf(MSG_DEBUG, "WPS: New Enrollee");
                        count++;
+               }
+               if (first == NULL)
+                       first = pbc;
        }
 
-       if (addr || uuid_e)
-               count++;
+       wpa_printf(MSG_DEBUG, "WPS: %u active PBC session(s) found", count);
 
        return count > 1 ? 1 : 0;
 }
@@ -339,7 +428,7 @@ static void wps_registrar_free_pending_m2(struct wps_context *wps)
 static int wps_build_ap_setup_locked(struct wps_context *wps,
                                     struct wpabuf *msg)
 {
-       if (wps->ap_setup_locked) {
+       if (wps->ap_setup_locked && wps->ap_setup_locked != 2) {
                wpa_printf(MSG_DEBUG, "WPS:  * AP Setup Locked");
                wpabuf_put_be16(msg, ATTR_AP_SETUP_LOCKED);
                wpabuf_put_be16(msg, 1);
@@ -378,15 +467,55 @@ static int wps_build_sel_reg_dev_password_id(struct wps_registrar *reg,
 }
 
 
+static int wps_build_sel_pbc_reg_uuid_e(struct wps_registrar *reg,
+                                       struct wpabuf *msg)
+{
+       u16 id = reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT;
+       if (!reg->sel_reg_union)
+               return 0;
+       if (reg->sel_reg_dev_password_id_override >= 0)
+               id = reg->sel_reg_dev_password_id_override;
+       if (id != DEV_PW_PUSHBUTTON || !reg->dualband)
+               return 0;
+       return wps_build_uuid_e(msg, reg->wps->uuid);
+}
+
+
+static void wps_set_pushbutton(u16 *methods, u16 conf_methods)
+{
+       *methods |= WPS_CONFIG_PUSHBUTTON;
+#ifdef CONFIG_WPS2
+       if (conf_methods & WPS_CONFIG_VIRT_PUSHBUTTON)
+               *methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
+       if (conf_methods & WPS_CONFIG_PHY_PUSHBUTTON)
+               *methods |= WPS_CONFIG_PHY_PUSHBUTTON;
+       if (!(*methods & (WPS_CONFIG_VIRT_PUSHBUTTON |
+                         WPS_CONFIG_PHY_PUSHBUTTON))) {
+               /*
+                * Required to include virtual/physical flag, but we were not
+                * configured with push button type, so have to default to one
+                * of them.
+                */
+               *methods |= WPS_CONFIG_PHY_PUSHBUTTON;
+       }
+#endif /* CONFIG_WPS2 */
+}
+
+
 static int wps_build_sel_reg_config_methods(struct wps_registrar *reg,
                                            struct wpabuf *msg)
 {
        u16 methods;
        if (!reg->sel_reg_union)
                return 0;
-       methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
+       methods = reg->wps->config_methods;
+       methods &= ~WPS_CONFIG_PUSHBUTTON;
+#ifdef CONFIG_WPS2
+       methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
+                    WPS_CONFIG_PHY_PUSHBUTTON);
+#endif /* CONFIG_WPS2 */
        if (reg->pbc)
-               methods |= WPS_CONFIG_PUSHBUTTON;
+               wps_set_pushbutton(&methods, reg->wps->config_methods);
        if (reg->sel_reg_config_methods_override >= 0)
                methods = reg->sel_reg_config_methods_override;
        wpa_printf(MSG_DEBUG, "WPS:  * Selected Registrar Config Methods (%x)",
@@ -407,6 +536,10 @@ static int wps_build_probe_config_methods(struct wps_registrar *reg,
         * external Registrars.
         */
        methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
+#ifdef CONFIG_WPS2
+       methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
+                    WPS_CONFIG_PHY_PUSHBUTTON);
+#endif /* CONFIG_WPS2 */
        wpa_printf(MSG_DEBUG, "WPS:  * Config Methods (%x)", methods);
        wpabuf_put_be16(msg, ATTR_CONFIG_METHODS);
        wpabuf_put_be16(msg, 2);
@@ -418,11 +551,23 @@ static int wps_build_probe_config_methods(struct wps_registrar *reg,
 static int wps_build_config_methods_r(struct wps_registrar *reg,
                                      struct wpabuf *msg)
 {
-       u16 methods;
-       methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
-       if (reg->pbc)
-               methods |= WPS_CONFIG_PUSHBUTTON;
-       return wps_build_config_methods(msg, methods);
+       return wps_build_config_methods(msg, reg->wps->config_methods);
+}
+
+
+const u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count)
+{
+       *count = 0;
+
+#ifdef CONFIG_WPS2
+       while (*count < WPS_MAX_AUTHORIZED_MACS) {
+               if (is_zero_ether_addr(reg->authorized_macs_union[*count]))
+                       break;
+               (*count)++;
+       }
+#endif /* CONFIG_WPS2 */
+
+       return (const u8 *) reg->authorized_macs_union;
 }
 
 
@@ -468,6 +613,7 @@ wps_registrar_init(struct wps_context *wps,
        reg->sel_reg_dev_password_id_override = -1;
        reg->sel_reg_config_methods_override = -1;
        reg->static_wep_only = cfg->static_wep_only;
+       reg->dualband = cfg->dualband;
 
        if (wps_set_ie(reg)) {
                wps_registrar_deinit(reg);
@@ -499,20 +645,24 @@ void wps_registrar_deinit(struct wps_registrar *reg)
 /**
  * wps_registrar_add_pin - Configure a new PIN for Registrar
  * @reg: Registrar data from wps_registrar_init()
+ * @addr: Enrollee MAC address or %NULL if not known
  * @uuid: UUID-E or %NULL for wildcard (any UUID)
  * @pin: PIN (Device Password)
  * @pin_len: Length of pin in octets
  * @timeout: Time (in seconds) when the PIN will be invalidated; 0 = no timeout
  * Returns: 0 on success, -1 on failure
  */
-int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
-                         const u8 *pin, size_t pin_len, int timeout)
+int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,
+                         const u8 *uuid, const u8 *pin, size_t pin_len,
+                         int timeout)
 {
        struct wps_uuid_pin *p;
 
        p = os_zalloc(sizeof(*p));
        if (p == NULL)
                return -1;
+       if (addr)
+               os_memcpy(p->enrollee_addr, addr, ETH_ALEN);
        if (uuid == NULL)
                p->wildcard_uuid = 1;
        else
@@ -539,6 +689,11 @@ int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
        wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: PIN", pin, pin_len);
        reg->selected_registrar = 1;
        reg->pbc = 0;
+       if (addr)
+               wps_registrar_add_authorized_mac(reg, addr);
+       else
+               wps_registrar_add_authorized_mac(
+                       reg, (u8 *) "\xff\xff\xff\xff\xff\xff");
        wps_registrar_selected_registrar_changed(reg);
        eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
        eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
@@ -549,6 +704,22 @@ int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
 }
 
 
+static void wps_registrar_remove_pin(struct wps_registrar *reg,
+                                    struct wps_uuid_pin *pin)
+{
+       u8 *addr;
+       u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+       if (is_zero_ether_addr(pin->enrollee_addr))
+               addr = bcast;
+       else
+               addr = pin->enrollee_addr;
+       wps_registrar_remove_authorized_mac(reg, addr);
+       wps_remove_pin(pin);
+       wps_registrar_selected_registrar_changed(reg);
+}
+
+
 static void wps_registrar_expire_pins(struct wps_registrar *reg)
 {
        struct wps_uuid_pin *pin, *prev;
@@ -561,9 +732,32 @@ static void wps_registrar_expire_pins(struct wps_registrar *reg)
                    os_time_before(&pin->expiration, &now)) {
                        wpa_hexdump(MSG_DEBUG, "WPS: Expired PIN for UUID",
                                    pin->uuid, WPS_UUID_LEN);
-                       wps_remove_pin(pin);
+                       wps_registrar_remove_pin(reg, pin);
+               }
+       }
+}
+
+
+/**
+ * wps_registrar_invalidate_wildcard_pin - Invalidate a wildcard PIN
+ * @reg: Registrar data from wps_registrar_init()
+ * Returns: 0 on success, -1 if not wildcard PIN is enabled
+ */
+static int wps_registrar_invalidate_wildcard_pin(struct wps_registrar *reg)
+{
+       struct wps_uuid_pin *pin, *prev;
+
+       dl_list_for_each_safe(pin, prev, &reg->pins, struct wps_uuid_pin, list)
+       {
+               if (pin->wildcard_uuid) {
+                       wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID",
+                                   pin->uuid, WPS_UUID_LEN);
+                       wps_registrar_remove_pin(reg, pin);
+                       return 0;
                }
        }
+
+       return -1;
 }
 
 
@@ -582,7 +776,7 @@ int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid)
                if (os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) {
                        wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID",
                                    pin->uuid, WPS_UUID_LEN);
-                       wps_remove_pin(pin);
+                       wps_registrar_remove_pin(reg, pin);
                        return 0;
                }
        }
@@ -673,6 +867,9 @@ static void wps_registrar_stop_pbc(struct wps_registrar *reg)
 {
        reg->selected_registrar = 0;
        reg->pbc = 0;
+       os_memset(reg->p2p_dev_addr, 0, ETH_ALEN);
+       wps_registrar_remove_authorized_mac(reg,
+                                           (u8 *) "\xff\xff\xff\xff\xff\xff");
        wps_registrar_selected_registrar_changed(reg);
 }
 
@@ -690,26 +887,40 @@ static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx)
 /**
  * wps_registrar_button_pushed - Notify Registrar that AP button was pushed
  * @reg: Registrar data from wps_registrar_init()
- * Returns: 0 on success, -1 on failure
+ * @p2p_dev_addr: Limit allowed PBC devices to the specified P2P device, %NULL
+ *     indicates no such filtering
+ * Returns: 0 on success, -1 on failure, -2 on session overlap
  *
  * This function is called on an AP when a push button is pushed to activate
  * PBC mode. The PBC mode will be stopped after walk time (2 minutes) timeout
- * or when a PBC registration is completed.
+ * or when a PBC registration is completed. If more than one Enrollee in active
+ * PBC mode has been detected during the monitor time (previous 2 minutes), the
+ * PBC mode is not activated and -2 is returned to indicate session overlap.
+ * This is skipped if a specific Enrollee is selected.
  */
-int wps_registrar_button_pushed(struct wps_registrar *reg)
+int wps_registrar_button_pushed(struct wps_registrar *reg,
+                               const u8 *p2p_dev_addr)
 {
-       if (wps_registrar_pbc_overlap(reg, NULL, NULL)) {
+       if (p2p_dev_addr == NULL &&
+           wps_registrar_pbc_overlap(reg, NULL, NULL)) {
                wpa_printf(MSG_DEBUG, "WPS: PBC overlap - do not start PBC "
                           "mode");
                wps_pbc_overlap_event(reg->wps);
-               return -1;
+               return -2;
        }
        wpa_printf(MSG_DEBUG, "WPS: Button pushed - PBC mode started");
        reg->force_pbc_overlap = 0;
        reg->selected_registrar = 1;
        reg->pbc = 1;
+       if (p2p_dev_addr)
+               os_memcpy(reg->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
+       else
+               os_memset(reg->p2p_dev_addr, 0, ETH_ALEN);
+       wps_registrar_add_authorized_mac(reg,
+                                        (u8 *) "\xff\xff\xff\xff\xff\xff");
        wps_registrar_selected_registrar_changed(reg);
 
+       eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
        eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
        eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wps_registrar_pbc_timeout,
                               reg, NULL);
@@ -734,6 +945,35 @@ static void wps_registrar_pin_completed(struct wps_registrar *reg)
 }
 
 
+void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e)
+{
+       if (registrar->pbc) {
+               wps_registrar_remove_pbc_session(registrar,
+                                                uuid_e, NULL);
+               wps_registrar_pbc_completed(registrar);
+       } else {
+               wps_registrar_pin_completed(registrar);
+       }
+}
+
+
+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);
+               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);
+               return 1;
+       }
+       return 0;
+}
+
+
 /**
  * wps_registrar_probe_req_rx - Notify Registrar of Probe Request
  * @reg: Registrar data from wps_registrar_init()
@@ -745,7 +985,8 @@ static void wps_registrar_pin_completed(struct wps_registrar *reg)
  * situation with other WPS APs.
  */
 void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
-                               const struct wpabuf *wps_data)
+                               const struct wpabuf *wps_data,
+                               int p2p_wildcard)
 {
        struct wps_parse_attr attr;
 
@@ -755,11 +996,6 @@ void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
 
        if (wps_parse_msg(wps_data, &attr) < 0)
                return;
-       if (!wps_version_supported(attr.version)) {
-               wpa_printf(MSG_DEBUG, "WPS: Unsupported ProbeReq WPS IE "
-                          "version 0x%x", attr.version ? *attr.version : 0);
-               return;
-       }
 
        if (attr.config_methods == NULL) {
                wpa_printf(MSG_DEBUG, "WPS: No Config Methods attribute in "
@@ -774,7 +1010,7 @@ void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
        }
 
        if (reg->enrollee_seen_cb && attr.uuid_e &&
-           attr.primary_dev_type && attr.request_type) {
+           attr.primary_dev_type && attr.request_type && !p2p_wildcard) {
                char *dev_name = NULL;
                if (attr.dev_name) {
                        dev_name = os_zalloc(attr.dev_name_len + 1);
@@ -801,6 +1037,8 @@ void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
                           "UUID-E included");
                return;
        }
+       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);
        if (wps_registrar_pbc_overlap(reg, addr, attr.uuid_e)) {
@@ -856,74 +1094,84 @@ static void wps_cb_set_sel_reg(struct wps_registrar *reg)
 
        if (reg->selected_registrar) {
                methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
+#ifdef CONFIG_WPS2
+               methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
+                            WPS_CONFIG_PHY_PUSHBUTTON);
+#endif /* CONFIG_WPS2 */
                if (reg->pbc)
-                       methods |= WPS_CONFIG_PUSHBUTTON;
+                       wps_set_pushbutton(&methods, reg->wps->config_methods);
        }
 
+       wpa_printf(MSG_DEBUG, "WPS: wps_cb_set_sel_reg: sel_reg=%d "
+                  "config_methods=0x%x pbc=%d methods=0x%x",
+                  reg->selected_registrar, reg->wps->config_methods,
+                  reg->pbc, methods);
+
        reg->set_sel_reg_cb(reg->cb_ctx, reg->selected_registrar,
                            reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT,
                            methods);
 }
 
 
-/* Encapsulate WPS IE data with one (or more, if needed) IE headers */
-static struct wpabuf * wps_ie_encapsulate(struct wpabuf *data)
-{
-       struct wpabuf *ie;
-       const u8 *pos, *end;
-
-       ie = wpabuf_alloc(wpabuf_len(data) + 100);
-       if (ie == NULL) {
-               wpabuf_free(data);
-               return NULL;
-       }
-
-       pos = wpabuf_head(data);
-       end = pos + wpabuf_len(data);
-
-       while (end > pos) {
-               size_t frag_len = end - pos;
-               if (frag_len > 251)
-                       frag_len = 251;
-               wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
-               wpabuf_put_u8(ie, 4 + frag_len);
-               wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
-               wpabuf_put_data(ie, pos, frag_len);
-               pos += frag_len;
-       }
-
-       wpabuf_free(data);
-
-       return ie;
-}
-
-
 static int wps_set_ie(struct wps_registrar *reg)
 {
        struct wpabuf *beacon;
        struct wpabuf *probe;
+       const u8 *auth_macs;
+       size_t count;
+       size_t vendor_len = 0;
+       int i;
 
        if (reg->set_ie_cb == NULL)
                return 0;
 
-       wpa_printf(MSG_DEBUG, "WPS: Build Beacon and Probe Response IEs");
+       for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+               if (reg->wps->dev.vendor_ext[i]) {
+                       vendor_len += 2 + 2;
+                       vendor_len += wpabuf_len(reg->wps->dev.vendor_ext[i]);
+               }
+       }
 
-       beacon = wpabuf_alloc(300);
+       beacon = wpabuf_alloc(400 + vendor_len);
        if (beacon == NULL)
                return -1;
-       probe = wpabuf_alloc(400);
+       probe = wpabuf_alloc(500 + vendor_len);
        if (probe == NULL) {
                wpabuf_free(beacon);
                return -1;
        }
 
+       auth_macs = wps_authorized_macs(reg, &count);
+
+       wpa_printf(MSG_DEBUG, "WPS: Build Beacon IEs");
+
        if (wps_build_version(beacon) ||
            wps_build_wps_state(reg->wps, beacon) ||
            wps_build_ap_setup_locked(reg->wps, beacon) ||
            wps_build_selected_registrar(reg, beacon) ||
            wps_build_sel_reg_dev_password_id(reg, beacon) ||
            wps_build_sel_reg_config_methods(reg, beacon) ||
-           wps_build_version(probe) ||
+           wps_build_sel_pbc_reg_uuid_e(reg, beacon) ||
+           (reg->dualband && wps_build_rf_bands(&reg->wps->dev, beacon)) ||
+           wps_build_wfa_ext(beacon, 0, auth_macs, count) ||
+           wps_build_vendor_ext(&reg->wps->dev, beacon)) {
+               wpabuf_free(beacon);
+               wpabuf_free(probe);
+               return -1;
+       }
+
+#ifdef CONFIG_P2P
+       if (wps_build_dev_name(&reg->wps->dev, beacon) ||
+           wps_build_primary_dev_type(&reg->wps->dev, beacon)) {
+               wpabuf_free(beacon);
+               wpabuf_free(probe);
+               return -1;
+       }
+#endif /* CONFIG_P2P */
+
+       wpa_printf(MSG_DEBUG, "WPS: Build Probe Response IEs");
+
+       if (wps_build_version(probe) ||
            wps_build_wps_state(reg->wps, probe) ||
            wps_build_ap_setup_locked(reg->wps, probe) ||
            wps_build_selected_registrar(reg, probe) ||
@@ -934,7 +1182,9 @@ 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)) {
+           wps_build_rf_bands(&reg->wps->dev, probe) ||
+           wps_build_wfa_ext(probe, 0, auth_macs, count) ||
+           wps_build_vendor_ext(&reg->wps->dev, probe)) {
                wpabuf_free(beacon);
                wpabuf_free(probe);
                return -1;
@@ -1025,7 +1275,7 @@ static int wps_build_r_hash(struct wps_data *wps, struct wpabuf *msg)
        const u8 *addr[4];
        size_t len[4];
 
-       if (os_get_random(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0)
+       if (random_get_bytes(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0)
                return -1;
        wpa_hexdump(MSG_DEBUG, "WPS: R-S1", wps->snonce, WPS_SECRET_NONCE_LEN);
        wpa_hexdump(MSG_DEBUG, "WPS: R-S2",
@@ -1091,7 +1341,7 @@ static int wps_build_r_snonce2(struct wps_data *wps, struct wpabuf *msg)
 static int wps_build_cred_network_idx(struct wpabuf *msg,
                                      const struct wps_credential *cred)
 {
-       wpa_printf(MSG_DEBUG, "WPS:  * Network Index");
+       wpa_printf(MSG_DEBUG, "WPS:  * Network Index (1)");
        wpabuf_put_be16(msg, ATTR_NETWORK_INDEX);
        wpabuf_put_be16(msg, 1);
        wpabuf_put_u8(msg, 1);
@@ -1103,6 +1353,8 @@ static int wps_build_cred_ssid(struct wpabuf *msg,
                               const struct wps_credential *cred)
 {
        wpa_printf(MSG_DEBUG, "WPS:  * SSID");
+       wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID for Credential",
+                         cred->ssid, cred->ssid_len);
        wpabuf_put_be16(msg, ATTR_SSID);
        wpabuf_put_be16(msg, cred->ssid_len);
        wpabuf_put_data(msg, cred->ssid, cred->ssid_len);
@@ -1139,6 +1391,8 @@ static int wps_build_cred_network_key(struct wpabuf *msg,
 {
        wpa_printf(MSG_DEBUG, "WPS:  * Network Key (len=%d)",
                   (int) cred->key_len);
+       wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
+                       cred->key, cred->key_len);
        wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
        wpabuf_put_be16(msg, cred->key_len);
        wpabuf_put_data(msg, cred->key, cred->key_len);
@@ -1172,6 +1426,25 @@ static int wps_build_credential(struct wpabuf *msg,
 }
 
 
+int wps_build_credential_wrap(struct wpabuf *msg,
+                             const struct wps_credential *cred)
+{
+       struct wpabuf *wbuf;
+       wbuf = wpabuf_alloc(200);
+       if (wbuf == NULL)
+               return -1;
+       if (wps_build_credential(wbuf, cred)) {
+               wpabuf_free(wbuf);
+               return -1;
+       }
+       wpabuf_put_be16(msg, ATTR_CRED);
+       wpabuf_put_be16(msg, wpabuf_len(wbuf));
+       wpabuf_put_buf(msg, wbuf);
+       wpabuf_free(wbuf);
+       return 0;
+}
+
+
 int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
 {
        struct wpabuf *cred;
@@ -1237,7 +1510,7 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
            !wps->wps->registrar->disable_auto_conf) {
                u8 r[16];
                /* Generate a random passphrase */
-               if (os_get_random(r, sizeof(r)) < 0)
+               if (random_get_bytes(r, sizeof(r)) < 0)
                        return -1;
                os_free(wps->new_psk);
                wps->new_psk = base64_encode(r, sizeof(r), &wps->new_psk_len);
@@ -1269,7 +1542,7 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
                wps->new_psk = os_malloc(wps->new_psk_len);
                if (wps->new_psk == NULL)
                        return -1;
-               if (os_get_random(wps->new_psk, wps->new_psk_len) < 0) {
+               if (random_get_bytes(wps->new_psk, wps->new_psk_len) < 0) {
                        os_free(wps->new_psk);
                        wps->new_psk = NULL;
                        return -1;
@@ -1283,6 +1556,33 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
        }
 
 use_provided:
+#ifdef CONFIG_WPS_TESTING
+       if (wps_testing_dummy_cred)
+               cred = wpabuf_alloc(200);
+       else
+               cred = NULL;
+       if (cred) {
+               struct wps_credential dummy;
+               wpa_printf(MSG_DEBUG, "WPS: Add dummy credential");
+               os_memset(&dummy, 0, sizeof(dummy));
+               os_memcpy(dummy.ssid, "dummy", 5);
+               dummy.ssid_len = 5;
+               dummy.auth_type = WPS_AUTH_WPA2PSK;
+               dummy.encr_type = WPS_ENCR_AES;
+               os_memcpy(dummy.key, "dummy psk", 9);
+               dummy.key_len = 9;
+               os_memcpy(dummy.mac_addr, wps->mac_addr_e, ETH_ALEN);
+               wps_build_credential(cred, &dummy);
+               wpa_hexdump_buf(MSG_DEBUG, "WPS: Dummy Credential", cred);
+
+               wpabuf_put_be16(msg, ATTR_CRED);
+               wpabuf_put_be16(msg, wpabuf_len(cred));
+               wpabuf_put_buf(msg, cred);
+
+               wpabuf_free(cred);
+       }
+#endif /* CONFIG_WPS_TESTING */
+
        cred = wpabuf_alloc(200);
        if (cred == NULL)
                return -1;
@@ -1318,11 +1618,40 @@ static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *msg)
 }
 
 
+static struct wpabuf * wps_build_ap_cred(struct wps_data *wps)
+{
+       struct wpabuf *msg, *plain;
+
+       msg = wpabuf_alloc(1000);
+       if (msg == NULL)
+               return NULL;
+
+       plain = wpabuf_alloc(200);
+       if (plain == NULL) {
+               wpabuf_free(msg);
+               return NULL;
+       }
+
+       if (wps_build_ap_settings(wps, plain)) {
+               wpabuf_free(plain);
+               wpabuf_free(msg);
+               return NULL;
+       }
+
+       wpabuf_put_be16(msg, ATTR_CRED);
+       wpabuf_put_be16(msg, wpabuf_len(plain));
+       wpabuf_put_buf(msg, plain);
+       wpabuf_free(plain);
+
+       return msg;
+}
+
+
 static struct wpabuf * wps_build_m2(struct wps_data *wps)
 {
        struct wpabuf *msg;
 
-       if (os_get_random(wps->nonce_r, WPS_NONCE_LEN) < 0)
+       if (random_get_bytes(wps->nonce_r, WPS_NONCE_LEN) < 0)
                return NULL;
        wpa_hexdump(MSG_DEBUG, "WPS: Registrar Nonce",
                    wps->nonce_r, WPS_NONCE_LEN);
@@ -1350,6 +1679,7 @@ static struct wpabuf * wps_build_m2(struct wps_data *wps)
            wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
            wps_build_dev_password_id(msg, wps->dev_pw_id) ||
            wps_build_os_version(&wps->wps->dev, msg) ||
+           wps_build_wfa_ext(msg, 0, NULL, 0) ||
            wps_build_authenticator(wps, msg)) {
                wpabuf_free(msg);
                return NULL;
@@ -1388,7 +1718,8 @@ static struct wpabuf * wps_build_m2d(struct wps_data *wps)
            wps_build_rf_bands(&wps->wps->dev, msg) ||
            wps_build_assoc_state(wps, msg) ||
            wps_build_config_error(msg, err) ||
-           wps_build_os_version(&wps->wps->dev, msg)) {
+           wps_build_os_version(&wps->wps->dev, msg) ||
+           wps_build_wfa_ext(msg, 0, NULL, 0)) {
                wpabuf_free(msg);
                return NULL;
        }
@@ -1423,6 +1754,7 @@ static struct wpabuf * wps_build_m4(struct wps_data *wps)
            wps_build_r_snonce1(wps, plain) ||
            wps_build_key_wrap_auth(wps, plain) ||
            wps_build_encr_settings(wps, msg, plain) ||
+           wps_build_wfa_ext(msg, 0, NULL, 0) ||
            wps_build_authenticator(wps, msg)) {
                wpabuf_free(plain);
                wpabuf_free(msg);
@@ -1457,6 +1789,7 @@ static struct wpabuf * wps_build_m6(struct wps_data *wps)
            wps_build_r_snonce2(wps, plain) ||
            wps_build_key_wrap_auth(wps, plain) ||
            wps_build_encr_settings(wps, msg, plain) ||
+           wps_build_wfa_ext(msg, 0, NULL, 0) ||
            wps_build_authenticator(wps, msg)) {
                wpabuf_free(plain);
                wpabuf_free(msg);
@@ -1493,6 +1826,7 @@ static struct wpabuf * wps_build_m8(struct wps_data *wps)
            (!wps->wps->ap && !wps->er && wps_build_ap_settings(wps, plain)) ||
            wps_build_key_wrap_auth(wps, plain) ||
            wps_build_encr_settings(wps, msg, plain) ||
+           wps_build_wfa_ext(msg, 0, NULL, 0) ||
            wps_build_authenticator(wps, msg)) {
                wpabuf_free(plain);
                wpabuf_free(msg);
@@ -1505,51 +1839,6 @@ static struct wpabuf * wps_build_m8(struct wps_data *wps)
 }
 
 
-static struct wpabuf * wps_build_wsc_ack(struct wps_data *wps)
-{
-       struct wpabuf *msg;
-
-       wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_ACK");
-
-       msg = wpabuf_alloc(1000);
-       if (msg == NULL)
-               return NULL;
-
-       if (wps_build_version(msg) ||
-           wps_build_msg_type(msg, WPS_WSC_ACK) ||
-           wps_build_enrollee_nonce(wps, msg) ||
-           wps_build_registrar_nonce(wps, msg)) {
-               wpabuf_free(msg);
-               return NULL;
-       }
-
-       return msg;
-}
-
-
-static struct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
-{
-       struct wpabuf *msg;
-
-       wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_NACK");
-
-       msg = wpabuf_alloc(1000);
-       if (msg == NULL)
-               return NULL;
-
-       if (wps_build_version(msg) ||
-           wps_build_msg_type(msg, WPS_WSC_NACK) ||
-           wps_build_enrollee_nonce(wps, msg) ||
-           wps_build_registrar_nonce(wps, msg) ||
-           wps_build_config_error(msg, wps->config_error)) {
-               wpabuf_free(msg);
-               return NULL;
-       }
-
-       return msg;
-}
-
-
 struct wpabuf * wps_registrar_get_msg(struct wps_data *wps,
                                      enum wsc_op_code *op_code)
 {
@@ -2047,6 +2336,45 @@ static int wps_process_config_error(struct wps_data *wps, const u8 *err)
 }
 
 
+static int wps_registrar_p2p_dev_addr_match(struct wps_data *wps)
+{
+#ifdef CONFIG_P2P
+       struct wps_registrar *reg = wps->wps->registrar;
+
+       if (is_zero_ether_addr(reg->p2p_dev_addr))
+               return 1; /* no filtering in use */
+
+       if (os_memcmp(reg->p2p_dev_addr, wps->p2p_dev_addr, ETH_ALEN) != 0) {
+               wpa_printf(MSG_DEBUG, "WPS: No match on P2P Device Address "
+                          "filtering for PBC: expected " MACSTR " was "
+                          MACSTR " - indicate PBC session overlap",
+                          MAC2STR(reg->p2p_dev_addr),
+                          MAC2STR(wps->p2p_dev_addr));
+               return 0;
+       }
+#endif /* CONFIG_P2P */
+       return 1;
+}
+
+
+static int wps_registrar_skip_overlap(struct wps_data *wps)
+{
+#ifdef CONFIG_P2P
+       struct wps_registrar *reg = wps->wps->registrar;
+
+       if (is_zero_ether_addr(reg->p2p_dev_addr))
+               return 0; /* no specific Enrollee selected */
+
+       if (os_memcmp(reg->p2p_dev_addr, wps->p2p_dev_addr, ETH_ALEN) == 0) {
+               wpa_printf(MSG_DEBUG, "WPS: Skip PBC overlap due to selected "
+                          "Enrollee match");
+               return 1;
+       }
+#endif /* CONFIG_P2P */
+       return 0;
+}
+
+
 static enum wps_process_res wps_process_m1(struct wps_data *wps,
                                           struct wps_parse_attr *attr)
 {
@@ -2099,14 +2427,19 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps,
 #endif /* CONFIG_WPS_OOB */
 
        if (wps->dev_pw_id == DEV_PW_PUSHBUTTON) {
-               if (wps->wps->registrar->force_pbc_overlap ||
-                   wps_registrar_pbc_overlap(wps->wps->registrar,
-                                             wps->mac_addr_e, wps->uuid_e)) {
+               if ((wps->wps->registrar->force_pbc_overlap ||
+                    wps_registrar_pbc_overlap(wps->wps->registrar,
+                                              wps->mac_addr_e, wps->uuid_e) ||
+                    !wps_registrar_p2p_dev_addr_match(wps)) &&
+                   !wps_registrar_skip_overlap(wps)) {
                        wpa_printf(MSG_DEBUG, "WPS: PBC overlap - deny PBC "
                                   "negotiation");
                        wps->state = SEND_M2D;
                        wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
                        wps_pbc_overlap_event(wps->wps);
+                       wps_fail_event(wps->wps, WPS_M1,
+                                      WPS_CFG_MULTIPLE_PBC_DETECTED,
+                                      WPS_EI_NO_ERROR);
                        wps->wps->registrar->force_pbc_overlap = 1;
                        return WPS_CONTINUE;
                }
@@ -2150,7 +2483,8 @@ static enum wps_process_res wps_process_m3(struct wps_data *wps,
                return WPS_CONTINUE;
        }
 
-       if (wps->pbc && wps->wps->registrar->force_pbc_overlap) {
+       if (wps->pbc && wps->wps->registrar->force_pbc_overlap &&
+           !wps_registrar_skip_overlap(wps)) {
                wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC "
                           "session overlap");
                wps->state = SEND_WSC_NACK;
@@ -2187,7 +2521,8 @@ static enum wps_process_res wps_process_m5(struct wps_data *wps,
                return WPS_CONTINUE;
        }
 
-       if (wps->pbc && wps->wps->registrar->force_pbc_overlap) {
+       if (wps->pbc && wps->wps->registrar->force_pbc_overlap &&
+           !wps_registrar_skip_overlap(wps)) {
                wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC "
                           "session overlap");
                wps->state = SEND_WSC_NACK;
@@ -2210,6 +2545,12 @@ static enum wps_process_res wps_process_m5(struct wps_data *wps,
                return WPS_CONTINUE;
        }
 
+       if (wps_validate_m5_encr(decrypted, attr->version2 != NULL) < 0) {
+               wpabuf_free(decrypted);
+               wps->state = SEND_WSC_NACK;
+               return WPS_CONTINUE;
+       }
+
        wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
                   "attribute");
        if (wps_parse_msg(decrypted, &eattr) < 0 ||
@@ -2264,6 +2605,8 @@ static void wps_cred_update(struct wps_credential *dst,
 static int wps_process_ap_settings_r(struct wps_data *wps,
                                     struct wps_parse_attr *attr)
 {
+       struct wpabuf *msg;
+
        if (wps->wps->ap || wps->er)
                return 0;
 
@@ -2283,12 +2626,31 @@ static int wps_process_ap_settings_r(struct wps_data *wps,
                 * Use the AP PIN only to receive the current AP settings, not
                 * to reconfigure the AP.
                 */
+
+               /*
+                * Clear selected registrar here since we do not get to
+                * WSC_Done in this protocol run.
+                */
+               wps_registrar_pin_completed(wps->wps->registrar);
+
+               msg = wps_build_ap_cred(wps);
+               if (msg == NULL)
+                       return -1;
+               wps->cred.cred_attr = wpabuf_head(msg);
+               wps->cred.cred_attr_len = wpabuf_len(msg);
+
                if (wps->ap_settings_cb) {
                        wps->ap_settings_cb(wps->ap_settings_cb_ctx,
                                            &wps->cred);
+                       wpabuf_free(msg);
                        return 1;
                }
                wps_sta_cred_cb(wps);
+
+               wps->cred.cred_attr = NULL;
+               wps->cred.cred_attr_len = 0;
+               wpabuf_free(msg);
+
                return 1;
        }
 }
@@ -2310,7 +2672,8 @@ static enum wps_process_res wps_process_m7(struct wps_data *wps,
                return WPS_CONTINUE;
        }
 
-       if (wps->pbc && wps->wps->registrar->force_pbc_overlap) {
+       if (wps->pbc && wps->wps->registrar->force_pbc_overlap &&
+           !wps_registrar_skip_overlap(wps)) {
                wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC "
                           "session overlap");
                wps->state = SEND_WSC_NACK;
@@ -2333,6 +2696,13 @@ static enum wps_process_res wps_process_m7(struct wps_data *wps,
                return WPS_CONTINUE;
        }
 
+       if (wps_validate_m7_encr(decrypted, wps->wps->ap || wps->er,
+                                attr->version2 != NULL) < 0) {
+               wpabuf_free(decrypted);
+               wps->state = SEND_WSC_NACK;
+               return WPS_CONTINUE;
+       }
+
        wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
                   "attribute");
        if (wps_parse_msg(decrypted, &eattr) < 0 ||
@@ -2362,15 +2732,10 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
        if (wps_parse_msg(msg, &attr) < 0)
                return WPS_FAILURE;
 
-       if (!wps_version_supported(attr.version)) {
-               wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
-                          attr.version ? *attr.version : 0);
-               return WPS_FAILURE;
-       }
-
        if (attr.msg_type == NULL) {
                wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
-               return WPS_FAILURE;
+               wps->state = SEND_WSC_NACK;
+               return WPS_CONTINUE;
        }
 
        if (*attr.msg_type != WPS_M1 &&
@@ -2383,6 +2748,8 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
 
        switch (*attr.msg_type) {
        case WPS_M1:
+               if (wps_validate_m1(msg) < 0)
+                       return WPS_FAILURE;
 #ifdef CONFIG_WPS_UPNP
                if (wps->wps->wps_upnp && attr.mac_addr) {
                        /* Remove old pending messages when starting new run */
@@ -2397,19 +2764,28 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
                ret = wps_process_m1(wps, &attr);
                break;
        case WPS_M3:
+               if (wps_validate_m3(msg) < 0)
+                       return WPS_FAILURE;
                ret = wps_process_m3(wps, msg, &attr);
                if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
-                       wps_fail_event(wps->wps, WPS_M3);
+                       wps_fail_event(wps->wps, WPS_M3, wps->config_error,
+                                      wps->error_indication);
                break;
        case WPS_M5:
+               if (wps_validate_m5(msg) < 0)
+                       return WPS_FAILURE;
                ret = wps_process_m5(wps, msg, &attr);
                if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
-                       wps_fail_event(wps->wps, WPS_M5);
+                       wps_fail_event(wps->wps, WPS_M5, wps->config_error,
+                                      wps->error_indication);
                break;
        case WPS_M7:
+               if (wps_validate_m7(msg) < 0)
+                       return WPS_FAILURE;
                ret = wps_process_m7(wps, msg, &attr);
                if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
-                       wps_fail_event(wps->wps, WPS_M7);
+                       wps_fail_event(wps->wps, WPS_M7, wps->config_error,
+                                      wps->error_indication);
                break;
        default:
                wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d",
@@ -2438,12 +2814,6 @@ static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
        if (wps_parse_msg(msg, &attr) < 0)
                return WPS_FAILURE;
 
-       if (!wps_version_supported(attr.version)) {
-               wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
-                          attr.version ? *attr.version : 0);
-               return WPS_FAILURE;
-       }
-
        if (attr.msg_type == NULL) {
                wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
                return WPS_FAILURE;
@@ -2506,6 +2876,7 @@ static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
 {
        struct wps_parse_attr attr;
        int old_state;
+       u16 config_error;
 
        wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK");
 
@@ -2515,12 +2886,6 @@ static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
        if (wps_parse_msg(msg, &attr) < 0)
                return WPS_FAILURE;
 
-       if (!wps_version_supported(attr.version)) {
-               wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
-                          attr.version ? *attr.version : 0);
-               return WPS_FAILURE;
-       }
-
        if (attr.msg_type == NULL) {
                wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
                return WPS_FAILURE;
@@ -2559,21 +2924,26 @@ static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
                return WPS_FAILURE;
        }
 
+       config_error = WPA_GET_BE16(attr.config_error);
        wpa_printf(MSG_DEBUG, "WPS: Enrollee terminated negotiation with "
-                  "Configuration Error %d", WPA_GET_BE16(attr.config_error));
+                  "Configuration Error %d", config_error);
 
        switch (old_state) {
        case RECV_M3:
-               wps_fail_event(wps->wps, WPS_M2);
+               wps_fail_event(wps->wps, WPS_M2, config_error,
+                              wps->error_indication);
                break;
        case RECV_M5:
-               wps_fail_event(wps->wps, WPS_M4);
+               wps_fail_event(wps->wps, WPS_M4, config_error,
+                              wps->error_indication);
                break;
        case RECV_M7:
-               wps_fail_event(wps->wps, WPS_M6);
+               wps_fail_event(wps->wps, WPS_M6, config_error,
+                              wps->error_indication);
                break;
        case RECV_DONE:
-               wps_fail_event(wps->wps, WPS_M8);
+               wps_fail_event(wps->wps, WPS_M8, config_error,
+                              wps->error_indication);
                break;
        default:
                break;
@@ -2600,12 +2970,6 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
        if (wps_parse_msg(msg, &attr) < 0)
                return WPS_FAILURE;
 
-       if (!wps_version_supported(attr.version)) {
-               wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
-                          attr.version ? *attr.version : 0);
-               return WPS_FAILURE;
-       }
-
        if (attr.msg_type == NULL) {
                wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
                return WPS_FAILURE;
@@ -2687,11 +3051,14 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
 
        if (wps->pbc) {
                wps_registrar_remove_pbc_session(wps->wps->registrar,
-                                                wps->mac_addr_e, wps->uuid_e);
+                                                wps->uuid_e,
+                                                wps->p2p_dev_addr);
                wps_registrar_pbc_completed(wps->wps->registrar);
        } else {
                wps_registrar_pin_completed(wps->wps->registrar);
        }
+       /* TODO: maintain AuthorizedMACs somewhere separately for each ER and
+        * merge them into APs own list.. */
 
        wps_success_event(wps->wps);
 
@@ -2747,14 +3114,22 @@ enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,
        case WSC_MSG:
                return wps_process_wsc_msg(wps, msg);
        case WSC_ACK:
+               if (wps_validate_wsc_ack(msg) < 0)
+                       return WPS_FAILURE;
                return wps_process_wsc_ack(wps, msg);
        case WSC_NACK:
+               if (wps_validate_wsc_nack(msg) < 0)
+                       return WPS_FAILURE;
                return wps_process_wsc_nack(wps, msg);
        case WSC_Done:
+               if (wps_validate_wsc_done(msg) < 0)
+                       return WPS_FAILURE;
                ret = wps_process_wsc_done(wps, msg);
                if (ret == WPS_FAILURE) {
                        wps->state = SEND_WSC_NACK;
-                       wps_fail_event(wps->wps, WPS_WSC_DONE);
+                       wps_fail_event(wps->wps, WPS_WSC_DONE,
+                                      wps->config_error,
+                                      wps->error_indication);
                }
                return ret;
        default:
@@ -2787,6 +3162,7 @@ static void wps_registrar_set_selected_timeout(void *eloop_ctx,
 static void wps_registrar_sel_reg_add(struct wps_registrar *reg,
                                      struct subscription *s)
 {
+       int i, j;
        wpa_printf(MSG_DEBUG, "WPS: External Registrar selected (dev_pw_id=%d "
                   "config_methods=0x%x)",
                   s->dev_password_id, s->config_methods);
@@ -2796,6 +3172,22 @@ static void wps_registrar_sel_reg_add(struct wps_registrar *reg,
        if (reg->sel_reg_config_methods_override == -1)
                reg->sel_reg_config_methods_override = 0;
        reg->sel_reg_config_methods_override |= s->config_methods;
+       for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++)
+               if (is_zero_ether_addr(reg->authorized_macs_union[i]))
+                       break;
+       for (j = 0; i < WPS_MAX_AUTHORIZED_MACS && j < WPS_MAX_AUTHORIZED_MACS;
+            j++) {
+               if (is_zero_ether_addr(s->authorized_macs[j]))
+                       break;
+               wpa_printf(MSG_DEBUG, "WPS: Add authorized MAC into union: "
+                          MACSTR, MAC2STR(s->authorized_macs[j]));
+               os_memcpy(reg->authorized_macs_union[i],
+                         s->authorized_macs[j], ETH_ALEN);
+               i++;
+       }
+       wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs union",
+                   (u8 *) reg->authorized_macs_union,
+                   sizeof(reg->authorized_macs_union));
 }
 #endif /* CONFIG_WPS_UPNP */
 
@@ -2841,17 +3233,27 @@ void wps_registrar_selected_registrar_changed(struct wps_registrar *reg)
        reg->sel_reg_union = reg->selected_registrar;
        reg->sel_reg_dev_password_id_override = -1;
        reg->sel_reg_config_methods_override = -1;
+       os_memcpy(reg->authorized_macs_union, reg->authorized_macs,
+                 WPS_MAX_AUTHORIZED_MACS * ETH_ALEN);
+       wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs union (start with own)",
+                   (u8 *) reg->authorized_macs_union,
+                   sizeof(reg->authorized_macs_union));
        if (reg->selected_registrar) {
-               reg->sel_reg_config_methods_override =
-                       reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
+               u16 methods;
+
+               methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
+#ifdef CONFIG_WPS2
+               methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
+                            WPS_CONFIG_PHY_PUSHBUTTON);
+#endif /* CONFIG_WPS2 */
                if (reg->pbc) {
                        reg->sel_reg_dev_password_id_override =
                                DEV_PW_PUSHBUTTON;
-                       reg->sel_reg_config_methods_override |=
-                               WPS_CONFIG_PUSHBUTTON;
+                       wps_set_pushbutton(&methods, reg->wps->config_methods);
                }
                wpa_printf(MSG_DEBUG, "WPS: Internal Registrar selected "
                           "(pbc=%d)", reg->pbc);
+               reg->sel_reg_config_methods_override = methods;
        } else
                wpa_printf(MSG_DEBUG, "WPS: Internal Registrar not selected");
 
@@ -2898,3 +3300,43 @@ int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr,
 
        return len;
 }
+
+
+int wps_registrar_config_ap(struct wps_registrar *reg,
+                           struct wps_credential *cred)
+{
+#ifdef CONFIG_WPS2
+       printf("encr_type=0x%x\n", cred->encr_type);
+       if (!(cred->encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP |
+                                WPS_ENCR_AES))) {
+               if (cred->encr_type & WPS_ENCR_WEP) {
+                       wpa_printf(MSG_INFO, "WPS: Reject new AP settings "
+                                  "due to WEP configuration");
+                       return -1;
+               }
+
+               wpa_printf(MSG_INFO, "WPS: Reject new AP settings due to "
+                          "invalid encr_type 0x%x", cred->encr_type);
+               return -1;
+       }
+
+       if ((cred->encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) ==
+           WPS_ENCR_TKIP) {
+               wpa_printf(MSG_DEBUG, "WPS: Upgrade encr_type TKIP -> "
+                          "TKIP+AES");
+               cred->encr_type |= WPS_ENCR_AES;
+       }
+
+       if ((cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) ==
+           WPS_AUTH_WPAPSK) {
+               wpa_printf(MSG_DEBUG, "WPS: Upgrade auth_type WPAPSK -> "
+                          "WPAPSK+WPA2PSK");
+               cred->auth_type |= WPS_AUTH_WPA2PSK;
+       }
+#endif /* CONFIG_WPS2 */
+
+       if (reg->wps->cred_cb)
+               return reg->wps->cred_cb(reg->wps->cb_ctx, cred);
+
+       return -1;
+}
index 1a911e1..61f6553 100644 (file)
@@ -16,7 +16,6 @@
 #include "common.h"
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/wait.h>
 #include <fcntl.h>
 #include <dirent.h>
 
index f99b859..06dcd20 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-2010, Jouni Malinen <j@w1.fi>
  *
  * See below for more details on licensing and code history.
  */
@@ -47,7 +47,7 @@
  * -- Needs renaming with module prefix to avoid polluting the debugger
  * namespace and causing possible collisions with other static fncs
  * and structure declarations when using the debugger.
- * -- The http error code generation is pretty bogus, hopefully noone cares.
+ * -- The http error code generation is pretty bogus, hopefully no one cares.
  *
  * Author: Ted Merrill, Atheros Communications, based upon earlier work
  * as explained above and below.
 
 #include "includes.h"
 
-#include <assert.h>
+#include <time.h>
 #include <net/if.h>
 #include <netdb.h>
 #include <sys/ioctl.h>
 #define MAX_SUBSCRIPTIONS 4    /* how many subscribing clients we handle */
 #define MAX_ADDR_PER_SUBSCRIPTION 8
 
+/* Maximum number of Probe Request events per second */
+#define MAX_EVENTS_PER_SEC 5
+
+
+static struct upnp_wps_device_sm *shared_upnp_device = NULL;
+
 
 /* Write the current date/time per RFC */
 void format_date(struct wpabuf *buf)
@@ -270,7 +276,7 @@ static void uuid_make(u8 uuid[UUID_LEN])
 /* subscr_addr_delete -- delete single unlinked subscriber address
  * (be sure to unlink first if need be)
  */
-static void subscr_addr_delete(struct subscr_addr *a)
+void subscr_addr_delete(struct subscr_addr *a)
 {
        /*
         * Note: do NOT free domain_and_port or path because they point to
@@ -293,7 +299,8 @@ static void subscr_addr_free_all(struct subscription *s)
 
 
 /* subscr_addr_add_url -- add address(es) for one url to subscription */
-static void subscr_addr_add_url(struct subscription *s, const char *url)
+static void subscr_addr_add_url(struct subscription *s, const char *url,
+                               size_t url_len)
 {
        int alloc_len;
        char *scratch_mem = NULL;
@@ -307,20 +314,21 @@ static void subscr_addr_add_url(struct subscription *s, const char *url)
        struct addrinfo *result = NULL;
        struct addrinfo *rp;
        int rerr;
-       struct subscr_addr *a = NULL;
 
        /* url MUST begin with http: */
-       if (os_strncasecmp(url, "http://", 7))
+       if (url_len < 7 || os_strncasecmp(url, "http://", 7))
                goto fail;
        url += 7;
+       url_len -= 7;
 
        /* allocate memory for the extra stuff we need */
-       alloc_len = (2 * (os_strlen(url) + 1));
+       alloc_len = 2 * (url_len + 1);
        scratch_mem = os_zalloc(alloc_len);
        if (scratch_mem == NULL)
                goto fail;
        mem = scratch_mem;
-       strcpy(mem, url);
+       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, '/');
@@ -332,7 +340,7 @@ static void subscr_addr_add_url(struct subscription *s, const char *url)
        }
        domain = mem;
        strcpy(domain, domain_and_port);
-       delim = strchr(domain, ':');
+       delim = os_strchr(domain, ':');
        if (delim) {
                *delim++ = 0;   /* null terminate domain */
                if (isdigit(*delim))
@@ -367,6 +375,8 @@ static void subscr_addr_add_url(struct subscription *s, const char *url)
                goto fail;
        }
        for (rp = result; rp; rp = rp->ai_next) {
+               struct subscr_addr *a;
+
                /* Limit no. of address to avoid denial of service attack */
                if (dl_list_len(&s->addr_list) >= MAX_ADDR_PER_SUBSCRIPTION) {
                        wpa_printf(MSG_INFO, "WPS UPnP: subscr_addr_add_url: "
@@ -385,19 +395,17 @@ static void subscr_addr_add_url(struct subscription *s, const char *url)
                if (path[0] != '/')
                        *mem++ = '/';
                strcpy(mem, path);
-               mem += 1 + strlen(mem);
+               mem += 1 + os_strlen(mem);
                os_memcpy(&a->saddr, rp->ai_addr, sizeof(a->saddr));
                a->saddr.sin_port = htons(port);
 
                dl_list_add(&s->addr_list, &a->list);
-               a = NULL;       /* don't free it below */
        }
 
 fail:
        if (result)
                freeaddrinfo(result);
        os_free(scratch_mem);
-       os_free(a);
 }
 
 
@@ -407,7 +415,8 @@ fail:
 static void subscr_addr_list_create(struct subscription *s,
                                    const char *url_list)
 {
-       char *end;
+       const char *end;
+       wpa_printf(MSG_DEBUG, "WPS UPnP: Parsing URL list '%s'", url_list);
        for (;;) {
                while (*url_list == ' ' || *url_list == '\t')
                        url_list++;
@@ -417,9 +426,8 @@ static void subscr_addr_list_create(struct subscription *s,
                end = os_strchr(url_list, '>');
                if (end == NULL)
                        break;
-               *end++ = 0;
-               subscr_addr_add_url(s, url_list);
-               url_list = end;
+               subscr_addr_add_url(s, url_list, end - url_list);
+               url_list = end + 1;
        }
 }
 
@@ -472,12 +480,38 @@ static void upnp_wps_device_send_event(struct upnp_wps_device_sm *sm)
                "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
                "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">\n";
        const char *format_tail = "</e:propertyset>\n";
+       struct os_time now;
 
        if (dl_list_empty(&sm->subscriptions)) {
                /* optimize */
                return;
        }
 
+       if (os_get_time(&now) == 0) {
+               if (now.sec != sm->last_event_sec) {
+                       sm->last_event_sec = now.sec;
+                       sm->num_events_in_sec = 1;
+               } else {
+                       sm->num_events_in_sec++;
+                       /*
+                        * In theory, this should apply to all WLANEvent
+                        * notifications, but EAP messages are of much higher
+                        * priority and Probe Request notifications should not
+                        * be allowed to drop EAP messages, so only throttle
+                        * Probe Request notifications.
+                        */
+                       if (sm->num_events_in_sec > MAX_EVENTS_PER_SEC &&
+                           sm->wlanevent_type ==
+                           UPNP_WPS_WLANEVENT_TYPE_PROBE) {
+                               wpa_printf(MSG_DEBUG, "WPS UPnP: Throttle "
+                                          "event notifications (%u seen "
+                                          "during one second)",
+                                          sm->num_events_in_sec);
+                               return;
+                       }
+               }
+       }
+
        /* Determine buffer size needed first */
        buf_size += os_strlen(format_head);
        buf_size += 50 + 2 * os_strlen("WLANEvent");
@@ -497,12 +531,8 @@ static void upnp_wps_device_send_event(struct upnp_wps_device_sm *sm)
 
        dl_list_for_each_safe(s, tmp, &sm->subscriptions, struct subscription,
                              list) {
-               if (event_add(s, buf)) {
-                       wpa_printf(MSG_INFO, "WPS UPnP: Dropping "
-                                  "subscriber due to event backlog");
-                       dl_list_del(&s->list);
-                       subscription_destroy(s);
-               }
+               event_add(s, buf,
+                         sm->wlanevent_type == UPNP_WPS_WLANEVENT_TYPE_PROBE);
        }
 
        wpabuf_free(buf);
@@ -578,6 +608,7 @@ static struct wpabuf * build_fake_wsc_ack(void)
        wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE);
        wpabuf_put_be16(msg, WPS_NONCE_LEN);
        wpabuf_put(msg, WPS_NONCE_LEN);
+       wps_build_wfa_ext(msg, 0, NULL, 0);
        return msg;
 }
 
@@ -605,6 +636,7 @@ static int subscription_first_event(struct subscription *s)
                "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">\n";
        const char *tail = "</e:propertyset>\n";
        char txt[10];
+       int ret;
 
        if (s->sm->wlanevent == NULL) {
                /*
@@ -636,7 +668,7 @@ static int subscription_first_event(struct subscription *s)
        }
        buf = wpabuf_alloc(500 + os_strlen(wlan_event));
        if (buf == NULL)
-               return 1;
+               return -1;
 
        wpabuf_put_str(buf, head);
        wpabuf_put_property(buf, "STAStatus", "1");
@@ -646,9 +678,10 @@ static int subscription_first_event(struct subscription *s)
                wpabuf_put_property(buf, "WLANEvent", wlan_event);
        wpabuf_put_str(buf, tail);
 
-       if (event_add(s, buf)) {
+       ret = event_add(s, buf, 0);
+       if (ret) {
                wpabuf_free(buf);
-               return 1;
+               return ret;
        }
        wpabuf_free(buf);
 
@@ -692,6 +725,13 @@ struct subscription * subscription_start(struct upnp_wps_device_sm *sm,
        s->timeout_time = expire;
        uuid_make(s->uuid);
        subscr_addr_list_create(s, callback_urls);
+       if (dl_list_empty(&s->addr_list)) {
+               wpa_printf(MSG_DEBUG, "WPS UPnP: No valid callback URLs in "
+                          "'%s' - drop subscription", callback_urls);
+               subscription_destroy(s);
+               return NULL;
+       }
+
        /* Add to end of list, since it has the highest expiration time */
        dl_list_add_tail(&sm->subscriptions, &s->list);
        /* Queue up immediate event message (our last event)
@@ -786,6 +826,7 @@ int upnp_wps_device_send_wlan_event(struct upnp_wps_device_sm *sm,
 
        os_free(sm->wlanevent);
        sm->wlanevent = val;
+       sm->wlanevent_type = ev_type;
        upnp_wps_device_send_event(sm);
 
        ret = 0;
@@ -914,10 +955,13 @@ static void upnp_wps_free_msearchreply(struct dl_list *head)
 }
 
 
-static void upnp_wps_free_subscriptions(struct dl_list *head)
+static void upnp_wps_free_subscriptions(struct dl_list *head,
+                                       struct wps_registrar *reg)
 {
        struct subscription *s, *tmp;
        dl_list_for_each_safe(s, tmp, head, struct subscription, list) {
+               if (reg && s->reg != reg)
+                       continue;
                dl_list_del(&s->list);
                subscription_destroy(s);
        }
@@ -928,7 +972,7 @@ static void upnp_wps_free_subscriptions(struct dl_list *head)
  * upnp_wps_device_stop - Stop WPS UPnP operations on an interface
  * @sm: WPS UPnP state machine from upnp_wps_device_init()
  */
-void upnp_wps_device_stop(struct upnp_wps_device_sm *sm)
+static void upnp_wps_device_stop(struct upnp_wps_device_sm *sm)
 {
        if (!sm || !sm->started)
                return;
@@ -936,7 +980,7 @@ void upnp_wps_device_stop(struct upnp_wps_device_sm *sm)
        wpa_printf(MSG_DEBUG, "WPS UPnP: Stop device");
        web_listener_stop(sm);
        upnp_wps_free_msearchreply(&sm->msearch_replies);
-       upnp_wps_free_subscriptions(&sm->subscriptions);
+       upnp_wps_free_subscriptions(&sm->subscriptions, NULL);
 
        advertisement_state_machine_stop(sm, 1);
 
@@ -960,7 +1004,7 @@ void upnp_wps_device_stop(struct upnp_wps_device_sm *sm)
  * @net_if: Selected network interface name
  * Returns: 0 on success, -1 on failure
  */
-int upnp_wps_device_start(struct upnp_wps_device_sm *sm, char *net_if)
+static int upnp_wps_device_start(struct upnp_wps_device_sm *sm, char *net_if)
 {
        if (!sm || !net_if)
                return -1;
@@ -1015,24 +1059,59 @@ fail:
 }
 
 
+static struct upnp_wps_device_interface *
+upnp_wps_get_iface(struct upnp_wps_device_sm *sm, void *priv)
+{
+       struct upnp_wps_device_interface *iface;
+       dl_list_for_each(iface, &sm->interfaces,
+                        struct upnp_wps_device_interface, list) {
+               if (iface->priv == priv)
+                       return iface;
+       }
+       return NULL;
+}
+
+
 /**
  * upnp_wps_device_deinit - Deinitialize WPS UPnP
  * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * @priv: External context data that was used in upnp_wps_device_init() call
  */
-void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm)
+void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm, void *priv)
 {
+       struct upnp_wps_device_interface *iface;
+
        if (!sm)
                return;
 
-       upnp_wps_device_stop(sm);
-
-       if (sm->peer.wps)
-               wps_deinit(sm->peer.wps);
-       os_free(sm->root_dir);
-       os_free(sm->desc_url);
-       os_free(sm->ctx->ap_pin);
-       os_free(sm->ctx);
-       os_free(sm);
+       iface = upnp_wps_get_iface(sm, priv);
+       if (iface == NULL) {
+               wpa_printf(MSG_ERROR, "WPS UPnP: Could not find the interface "
+                          "instance to deinit");
+               return;
+       }
+       wpa_printf(MSG_DEBUG, "WPS UPnP: Deinit interface instance %p", iface);
+       if (dl_list_len(&sm->interfaces) == 1) {
+               wpa_printf(MSG_DEBUG, "WPS UPnP: Deinitializing last instance "
+                          "- free global device instance");
+               upnp_wps_device_stop(sm);
+       } else
+               upnp_wps_free_subscriptions(&sm->subscriptions,
+                                           iface->wps->registrar);
+       dl_list_del(&iface->list);
+
+       if (iface->peer.wps)
+               wps_deinit(iface->peer.wps);
+       os_free(iface->ctx->ap_pin);
+       os_free(iface->ctx);
+       os_free(iface);
+
+       if (dl_list_empty(&sm->interfaces)) {
+               os_free(sm->root_dir);
+               os_free(sm->desc_url);
+               os_free(sm);
+               shared_upnp_device = NULL;
+       }
 }
 
 
@@ -1041,25 +1120,59 @@ void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm)
  * @ctx: callback table; we must eventually free it
  * @wps: Pointer to longterm WPS context
  * @priv: External context data that will be used in callbacks
+ * @net_if: Selected network interface name
  * Returns: WPS UPnP state or %NULL on failure
  */
 struct upnp_wps_device_sm *
 upnp_wps_device_init(struct upnp_wps_device_ctx *ctx, struct wps_context *wps,
-                    void *priv)
+                    void *priv, char *net_if)
 {
        struct upnp_wps_device_sm *sm;
+       struct upnp_wps_device_interface *iface;
+       int start = 0;
 
-       sm = os_zalloc(sizeof(*sm));
-       if (!sm) {
-               wpa_printf(MSG_ERROR, "WPS UPnP: upnp_wps_device_init failed");
+       iface = os_zalloc(sizeof(*iface));
+       if (iface == NULL) {
+               os_free(ctx->ap_pin);
+               os_free(ctx);
+               return NULL;
+       }
+       wpa_printf(MSG_DEBUG, "WPS UPnP: Init interface instance %p", iface);
+
+       iface->ctx = ctx;
+       iface->wps = wps;
+       iface->priv = priv;
+
+       if (shared_upnp_device) {
+               wpa_printf(MSG_DEBUG, "WPS UPnP: Share existing device "
+                          "context");
+               sm = shared_upnp_device;
+       } else {
+               wpa_printf(MSG_DEBUG, "WPS UPnP: Initialize device context");
+               sm = os_zalloc(sizeof(*sm));
+               if (!sm) {
+                       wpa_printf(MSG_ERROR, "WPS UPnP: upnp_wps_device_init "
+                                  "failed");
+                       os_free(iface);
+                       os_free(ctx->ap_pin);
+                       os_free(ctx);
+                       return NULL;
+               }
+               shared_upnp_device = sm;
+
+               dl_list_init(&sm->msearch_replies);
+               dl_list_init(&sm->subscriptions);
+               dl_list_init(&sm->interfaces);
+               start = 1;
+       }
+
+       dl_list_add(&sm->interfaces, &iface->list);
+
+       if (start && upnp_wps_device_start(sm, net_if)) {
+               upnp_wps_device_deinit(sm, priv);
                return NULL;
        }
 
-       sm->ctx = ctx;
-       sm->wps = wps;
-       sm->priv = priv;
-       dl_list_init(&sm->msearch_replies);
-       dl_list_init(&sm->subscriptions);
 
        return sm;
 }
@@ -1078,16 +1191,20 @@ int upnp_wps_subscribers(struct upnp_wps_device_sm *sm)
 
 int upnp_wps_set_ap_pin(struct upnp_wps_device_sm *sm, const char *ap_pin)
 {
+       struct upnp_wps_device_interface *iface;
        if (sm == NULL)
                return 0;
 
-       os_free(sm->ctx->ap_pin);
-       if (ap_pin) {
-               sm->ctx->ap_pin = os_strdup(ap_pin);
-               if (sm->ctx->ap_pin == NULL)
-                       return -1;
-       } else
-               sm->ctx->ap_pin = NULL;
+       dl_list_for_each(iface, &sm->interfaces,
+                        struct upnp_wps_device_interface, list) {
+               os_free(iface->ctx->ap_pin);
+               if (ap_pin) {
+                       iface->ctx->ap_pin = os_strdup(ap_pin);
+                       if (iface->ctx->ap_pin == NULL)
+                               return -1;
+               } else
+                       iface->ctx->ap_pin = NULL;
+       }
 
        return 0;
 }
index 06bc31f..87b7ab1 100644 (file)
@@ -35,11 +35,8 @@ struct upnp_wps_device_ctx {
 
 struct upnp_wps_device_sm *
 upnp_wps_device_init(struct upnp_wps_device_ctx *ctx, struct wps_context *wps,
-                    void *priv);
-void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm);
-
-int upnp_wps_device_start(struct upnp_wps_device_sm *sm, char *net_if);
-void upnp_wps_device_stop(struct upnp_wps_device_sm *sm);
+                    void *priv, char *net_if);
+void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm, void *priv);
 
 int upnp_wps_device_send_wlan_event(struct upnp_wps_device_sm *sm,
                                    const u8 from_mac_addr[ETH_ALEN],
index 93746da..501ecbc 100644 (file)
@@ -39,18 +39,16 @@ int upnp_er_set_selected_registrar(struct wps_registrar *reg,
 
        wpa_hexdump_buf(MSG_MSGDUMP, "WPS: SetSelectedRegistrar attributes",
                        msg);
+       if (wps_validate_upnp_set_selected_registrar(msg) < 0)
+               return -1;
 
        if (wps_parse_msg(msg, &attr) < 0)
                return -1;
-       if (!wps_version_supported(attr.version)) {
-               wpa_printf(MSG_DEBUG, "WPS: Unsupported SetSelectedRegistrar "
-                          "version 0x%x", attr.version ? *attr.version : 0);
-               return -1;
-       }
 
        s->reg = reg;
        eloop_cancel_timeout(upnp_er_set_selected_timeout, s, NULL);
 
+       os_memset(s->authorized_macs, 0, sizeof(s->authorized_macs));
        if (attr.selected_registrar == NULL || *attr.selected_registrar == 0) {
                wpa_printf(MSG_DEBUG, "WPS: SetSelectedRegistrar: Disable "
                           "Selected Registrar");
@@ -61,6 +59,19 @@ int upnp_er_set_selected_registrar(struct wps_registrar *reg,
                        WPA_GET_BE16(attr.dev_password_id) : DEV_PW_DEFAULT;
                s->config_methods = attr.sel_reg_config_methods ?
                        WPA_GET_BE16(attr.sel_reg_config_methods) : -1;
+               if (attr.authorized_macs) {
+                       int count = attr.authorized_macs_len / ETH_ALEN;
+                       if (count > WPS_MAX_AUTHORIZED_MACS)
+                               count = WPS_MAX_AUTHORIZED_MACS;
+                       os_memcpy(s->authorized_macs, attr.authorized_macs,
+                                 count * ETH_ALEN);
+               } else if (!attr.version2) {
+#ifdef CONFIG_WPS2
+                       wpa_printf(MSG_DEBUG, "WPS: Add broadcast "
+                                  "AuthorizedMACs for WPS 1.0 ER");
+                       os_memset(s->authorized_macs, 0xff, ETH_ALEN);
+#endif /* CONFIG_WPS2 */
+               }
                eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
                                       upnp_er_set_selected_timeout, s, NULL);
        }
index ae5efdb..2c8ed4f 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-2010, Jouni Malinen <j@w1.fi>
  *
  * See wps_upnp.c for more details on licensing and code history.
  */
@@ -31,7 +31,7 @@
  */
 
 #define MAX_EVENTS_QUEUED 20   /* How far behind queued events */
-#define EVENT_TIMEOUT_SEC 30   /* Drop sending event after timeout */
+#define MAX_FAILURES 10 /* Drop subscription after this many failures */
 
 /* How long to wait before sending event */
 #define EVENT_DELAY_SECONDS 0
@@ -73,6 +73,7 @@ static void event_clean(struct wps_event_ *e)
  */
 static void event_delete(struct wps_event_ *e)
 {
+       wpa_printf(MSG_DEBUG, "WPS UPnP: Delete event %p", e);
        event_clean(e);
        wpabuf_free(e->data);
        os_free(e);
@@ -86,8 +87,11 @@ static struct wps_event_ *event_dequeue(struct subscription *s)
 {
        struct wps_event_ *e;
        e = dl_list_first(&s->event_queue, struct wps_event_, list);
-       if (e)
+       if (e) {
+               wpa_printf(MSG_DEBUG, "WPS UPnP: Dequeue event %p for "
+                          "subscription %p", e, s);
                dl_list_del(&e->list);
+       }
        return e;
 }
 
@@ -115,14 +119,22 @@ static void event_retry(struct wps_event_ *e, int do_next_address)
        struct subscription *s = e->s;
        struct upnp_wps_device_sm *sm = s->sm;
 
+       wpa_printf(MSG_DEBUG, "WPS UPnP: Retry event %p for subscription %p",
+                  e, s);
        event_clean(e);
        /* will set: s->current_event = NULL; */
 
-       if (do_next_address)
+       if (do_next_address) {
                e->retry++;
+               wpa_printf(MSG_DEBUG, "WPS UPnP: Try address %d", e->retry);
+       }
        if (e->retry >= dl_list_len(&s->addr_list)) {
                wpa_printf(MSG_DEBUG, "WPS UPnP: Giving up on sending event "
                           "for %s", e->addr->domain_and_port);
+               event_delete(e);
+               s->last_event_failed = 1;
+               if (!dl_list_empty(&s->event_queue))
+                       event_send_all_later(s->sm);
                return;
        }
        dl_list_add(&s->event_queue, &e->list);
@@ -158,17 +170,60 @@ static struct wpabuf * event_build_message(struct wps_event_ *e)
 }
 
 
+static void event_addr_failure(struct wps_event_ *e)
+{
+       struct subscription *s = e->s;
+
+       e->addr->num_failures++;
+       wpa_printf(MSG_DEBUG, "WPS UPnP: Failed to send event %p to %s "
+                  "(num_failures=%u)",
+                  e, e->addr->domain_and_port, e->addr->num_failures);
+
+       if (e->addr->num_failures < MAX_FAILURES) {
+               /* Try other addresses, if available */
+               event_retry(e, 1);
+               return;
+       }
+
+       /*
+        * If other side doesn't like what we say, forget about them.
+        * (There is no way to tell other side that we are dropping them...).
+        */
+       wpa_printf(MSG_DEBUG, "WPS UPnP: Deleting subscription %p "
+                  "address %s due to errors", s, e->addr->domain_and_port);
+       dl_list_del(&e->addr->list);
+       subscr_addr_delete(e->addr);
+       e->addr = NULL;
+
+       if (dl_list_empty(&s->addr_list)) {
+               /* if we've given up on all addresses */
+               wpa_printf(MSG_DEBUG, "WPS UPnP: Removing subscription %p "
+                          "with no addresses", s);
+               dl_list_del(&s->list);
+               subscription_destroy(s);
+               return;
+       }
+
+       /* Try other addresses, if available */
+       event_retry(e, 0);
+}
+
+
 static void event_http_cb(void *ctx, struct http_client *c,
                          enum http_client_event event)
 {
        struct wps_event_ *e = ctx;
        struct subscription *s = e->s;
 
+       wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP client callback: e=%p c=%p "
+                  "event=%d", e, c, event);
        switch (event) {
        case HTTP_CLIENT_OK:
                wpa_printf(MSG_DEBUG,
-                          "WPS UPnP: Got event reply OK from "
-                          "%s", e->addr->domain_and_port);
+                          "WPS UPnP: Got event %p reply OK from %s",
+                          e, e->addr->domain_and_port);
+               e->addr->num_failures = 0;
+               s->last_event_failed = 0;
                event_delete(e);
 
                /* Schedule sending more if there is more to send */
@@ -176,24 +231,17 @@ static void event_http_cb(void *ctx, struct http_client *c,
                        event_send_all_later(s->sm);
                break;
        case HTTP_CLIENT_FAILED:
+               wpa_printf(MSG_DEBUG, "WPS UPnP: Event send failure");
+               event_addr_failure(e);
+               break;
        case HTTP_CLIENT_INVALID_REPLY:
-               wpa_printf(MSG_DEBUG, "WPS UPnP: Failed to send event to %s",
-                          e->addr->domain_and_port);
-
-               /*
-                * If other side doesn't like what we say, forget about them.
-                * (There is no way to tell other side that we are dropping
-                * them...).
-                * Alternately, we could just do event_delete(e)
-                */
-               wpa_printf(MSG_DEBUG, "WPS UPnP: Deleting subscription due to "
-                          "errors");
-               dl_list_del(&s->list);
-               subscription_destroy(s);
+               wpa_printf(MSG_DEBUG, "WPS UPnP: Invalid reply");
+               event_addr_failure(e);
                break;
        case HTTP_CLIENT_TIMEOUT:
                wpa_printf(MSG_DEBUG, "WPS UPnP: Event send timeout");
-               event_retry(e, 1);
+               event_addr_failure(e);
+               break;
        }
 }
 
@@ -228,9 +276,12 @@ static int event_send_start(struct subscription *s)
         * Assume we are called ONLY with no current event and ONLY with
         * nonempty event queue and ONLY with at least one address to send to.
         */
-       assert(!dl_list_empty(&s->addr_list));
-       assert(s->current_event == NULL);
-       assert(!dl_list_empty(&s->event_queue));
+       if (dl_list_empty(&s->addr_list))
+               return -1;
+       if (s->current_event)
+               return -1;
+       if (dl_list_empty(&s->event_queue))
+               return -1;
 
        s->current_event = e = event_dequeue(s);
 
@@ -270,18 +321,10 @@ static void event_send_all_later_handler(void *eloop_data, void *user_ctx)
        sm->event_send_all_queued = 0;
        dl_list_for_each_safe(s, tmp, &sm->subscriptions, struct subscription,
                              list) {
-               if (dl_list_empty(&s->addr_list)) {
-                       /* if we've given up on all addresses */
-                       wpa_printf(MSG_DEBUG, "WPS UPnP: Removing "
-                                  "subscription with no addresses");
-                       dl_list_del(&s->list);
-                       subscription_destroy(s);
-               } else {
-                       if (s->current_event == NULL /* not busy */ &&
-                           !dl_list_empty(&s->event_queue) /* more to do */) {
-                               if (event_send_start(s))
-                                       nerrors++;
-                       }
+               if (s->current_event == NULL /* not busy */ &&
+                   !dl_list_empty(&s->event_queue) /* more to do */) {
+                       if (event_send_start(s))
+                               nerrors++;
                }
        }
 
@@ -326,31 +369,54 @@ void event_send_stop_all(struct upnp_wps_device_sm *sm)
  * event_add - Add a new event to a queue
  * @s: Subscription
  * @data: Event data (is copied; caller retains ownership)
- * Returns: 0 on success, 1 on error
+ * @probereq: Whether this is a Probe Request event
+ * Returns: 0 on success, -1 on error, 1 on max event queue limit reached
  */
-int event_add(struct subscription *s, const struct wpabuf *data)
+int event_add(struct subscription *s, const struct wpabuf *data, int probereq)
 {
        struct wps_event_ *e;
+       unsigned int len;
 
-       if (dl_list_len(&s->event_queue) >= MAX_EVENTS_QUEUED) {
+       len = dl_list_len(&s->event_queue);
+       if (len >= MAX_EVENTS_QUEUED) {
                wpa_printf(MSG_DEBUG, "WPS UPnP: Too many events queued for "
-                          "subscriber");
-               return 1;
+                          "subscriber %p", s);
+               if (probereq)
+                       return 1;
+
+               /* Drop oldest entry to allow EAP event to be stored. */
+               e = event_dequeue(s);
+               if (!e)
+                       return 1;
+               event_delete(e);
+       }
+
+       if (s->last_event_failed && probereq && len > 0) {
+               /*
+                * Avoid queuing frames for subscribers that may have left
+                * without unsubscribing.
+                */
+               wpa_printf(MSG_DEBUG, "WPS UPnP: Do not queue more Probe "
+                          "Request frames for subscription %p since last "
+                          "delivery failed", s);
+               return -1;
        }
 
        e = os_zalloc(sizeof(*e));
        if (e == NULL)
-               return 1;
+               return -1;
        dl_list_init(&e->list);
        e->s = s;
        e->data = wpabuf_dup(data);
        if (e->data == NULL) {
                os_free(e);
-               return 1;
+               return -1;
        }
        e->subscriber_sequence = s->next_subscriber_sequence++;
        if (s->next_subscriber_sequence == 0)
                s->next_subscriber_sequence++;
+       wpa_printf(MSG_DEBUG, "WPS UPnP: Queue event %p for subscriber %p "
+                  "(queue len %u)", e, s, len + 1);
        dl_list_add_tail(&s->event_queue, &e->list);
        event_send_all_later(s->sm);
        return 0;
index b31875a..3ecf05d 100644 (file)
@@ -67,6 +67,7 @@ struct subscr_addr {
        char *domain_and_port; /* domain and port part of url */
        char *path; /* "filepath" part of url (from "mem") */
        struct sockaddr_in saddr; /* address for doing connect */
+       unsigned num_failures;
 };
 
 
@@ -91,25 +92,37 @@ struct subscription {
        struct dl_list event_queue; /* Queued event messages. */
        struct wps_event_ *current_event; /* non-NULL if being sent (not in q)
                                           */
+       int last_event_failed; /* Whether delivery of last event failed */
 
        /* Information from SetSelectedRegistrar action */
        u8 selected_registrar;
        u16 dev_password_id;
        u16 config_methods;
+       u8 authorized_macs[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];
        struct wps_registrar *reg;
 };
 
 
+struct upnp_wps_device_interface {
+       struct dl_list list;
+       struct upnp_wps_device_ctx *ctx; /* callback table */
+       struct wps_context *wps;
+       void *priv;
+
+       /* FIX: maintain separate structures for each UPnP peer */
+       struct upnp_wps_peer peer;
+};
+
 /*
- * Our instance data corresponding to one WiFi network interface
- * (multiple might share the same wired network interface!).
+ * Our instance data corresponding to the AP device. Note that there may be
+ * multiple wireless interfaces sharing the same UPnP device instance. Each
+ * such interface is stored in the list of struct upnp_wps_device_interface
+ * instances.
  *
  * This is known as an opaque struct declaration to users of the WPS UPnP code.
  */
 struct upnp_wps_device_sm {
-       struct upnp_wps_device_ctx *ctx; /* callback table */
-       struct wps_context *wps;
-       void *priv;
+       struct dl_list interfaces; /* struct upnp_wps_device_interface */
        char *root_dir;
        char *desc_url;
        int started; /* nonzero if we are active */
@@ -130,9 +143,9 @@ struct upnp_wps_device_sm {
                                    */
 
        char *wlanevent; /* the last WLANEvent data */
-
-       /* FIX: maintain separate structures for each UPnP peer */
-       struct upnp_wps_peer peer;
+       enum upnp_wps_wlanevent_type wlanevent_type;
+       os_time_t last_event_sec;
+       unsigned int num_events_in_sec;
 };
 
 /* wps_upnp.c */
@@ -144,6 +157,7 @@ struct subscription * subscription_renew(struct upnp_wps_device_sm *sm,
 void subscription_destroy(struct subscription *s);
 struct subscription * subscription_find(struct upnp_wps_device_sm *sm,
                                        const u8 uuid[UUID_LEN]);
+void subscr_addr_delete(struct subscr_addr *a);
 int send_wpabuf(int fd, struct wpabuf *buf);
 int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
                   u8 mac[ETH_ALEN]);
@@ -165,7 +179,7 @@ int web_listener_start(struct upnp_wps_device_sm *sm);
 void web_listener_stop(struct upnp_wps_device_sm *sm);
 
 /* wps_upnp_event.c */
-int event_add(struct subscription *s, const struct wpabuf *data);
+int event_add(struct subscription *s, const struct wpabuf *data, int probereq);
 void event_delete_all(struct subscription *s);
 void event_send_all_later(struct upnp_wps_device_sm *sm);
 void event_send_stop_all(struct upnp_wps_device_sm *sm);
index 8505d05..4c4aebf 100644 (file)
@@ -97,16 +97,6 @@ static int line_length(const char *l)
 }
 
 
-/* No. of chars excluding trailing whitespace */
-static int line_length_stripped(const char *l)
-{
-       const char *lp = l + line_length(l);
-       while (lp > l && !isgraph(lp[-1]))
-               lp--;
-       return lp - l;
-}
-
-
 static int str_starts(const char *str, const char *start)
 {
        return os_strncmp(str, start, os_strlen(start)) == 0;
@@ -136,9 +126,12 @@ next_advertisement(struct upnp_wps_device_sm *sm,
        struct wpabuf *msg;
        char *NTString = "";
        char uuid_string[80];
+       struct upnp_wps_device_interface *iface;
 
        *islast = 0;
-       uuid_bin2str(sm->wps->uuid, uuid_string, sizeof(uuid_string));
+       iface = dl_list_first(&sm->interfaces,
+                             struct upnp_wps_device_interface, list);
+       uuid_bin2str(iface->wps->uuid, uuid_string, sizeof(uuid_string));
        msg = wpabuf_alloc(800); /* more than big enough */
        if (msg == NULL)
                goto fail;
@@ -527,7 +520,6 @@ static void ssdp_parse_msearch(struct upnp_wps_device_sm *sm,
 #ifndef CONFIG_NO_STDOUT_DEBUG
        const char *start = data;
 #endif /* CONFIG_NO_STDOUT_DEBUG */
-       const char *end;
        int got_host = 0;
        int got_st = 0, st_match = 0;
        int got_man = 0;
@@ -542,7 +534,6 @@ static void ssdp_parse_msearch(struct upnp_wps_device_sm *sm,
 
        /* Parse remaining lines */
        for (; *data != '\0'; data += line_length(data)) {
-               end = data + line_length_stripped(data);
                if (token_eq(data, "host")) {
                        /* The host line indicates who the packet
                         * is addressed to... but do we really care?
@@ -588,8 +579,13 @@ static void ssdp_parse_msearch(struct upnp_wps_device_sm *sm,
                        }
                        if (str_starts(data, "uuid:")) {
                                char uuid_string[80];
+                               struct upnp_wps_device_interface *iface;
+                               iface = dl_list_first(
+                                       &sm->interfaces,
+                                       struct upnp_wps_device_interface,
+                                       list);
                                data += os_strlen("uuid:");
-                               uuid_bin2str(sm->wps->uuid, uuid_string,
+                               uuid_bin2str(iface->wps->uuid, uuid_string,
                                             sizeof(uuid_string));
                                if (str_starts(data, uuid_string))
                                        st_match = 1;
@@ -875,11 +871,17 @@ int ssdp_open_multicast_sock(u32 ip_addr)
 #endif
 
        if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF,
-                      &ip_addr, sizeof(ip_addr)))
+                      &ip_addr, sizeof(ip_addr))) {
+               wpa_printf(MSG_DEBUG, "WPS: setsockopt(IP_MULTICAST_IF) %x: "
+                          "%d (%s)", ip_addr, errno, strerror(errno));
                return -1;
+       }
        if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL,
-                      &ttl, sizeof(ttl)))
+                      &ttl, sizeof(ttl))) {
+               wpa_printf(MSG_DEBUG, "WPS: setsockopt(IP_MULTICAST_TTL): "
+                          "%d (%s)", errno, strerror(errno));
                return -1;
+       }
 
 #if 0   /* not needed, because we don't receive using multicast_sd */
        {
index 9a6b36e..ce0bede 100644 (file)
@@ -184,6 +184,10 @@ static void format_wps_device_xml(struct upnp_wps_device_sm *sm,
 {
        const char *s;
        char uuid_string[80];
+       struct upnp_wps_device_interface *iface;
+
+       iface = dl_list_first(&sm->interfaces,
+                             struct upnp_wps_device_interface, list);
 
        wpabuf_put_str(buf, wps_device_xml_prefix);
 
@@ -191,38 +195,38 @@ static void format_wps_device_xml(struct upnp_wps_device_sm *sm,
         * Add required fields with default values if not configured. Add
         * optional and recommended fields only if configured.
         */
-       s = sm->wps->friendly_name;
+       s = iface->wps->friendly_name;
        s = ((s && *s) ? s : "WPS Access Point");
        xml_add_tagged_data(buf, "friendlyName", s);
 
-       s = sm->wps->dev.manufacturer;
+       s = iface->wps->dev.manufacturer;
        s = ((s && *s) ? s : "");
        xml_add_tagged_data(buf, "manufacturer", s);
 
-       if (sm->wps->manufacturer_url)
+       if (iface->wps->manufacturer_url)
                xml_add_tagged_data(buf, "manufacturerURL",
-                                   sm->wps->manufacturer_url);
+                                   iface->wps->manufacturer_url);
 
-       if (sm->wps->model_description)
+       if (iface->wps->model_description)
                xml_add_tagged_data(buf, "modelDescription",
-                                   sm->wps->model_description);
+                                   iface->wps->model_description);
 
-       s = sm->wps->dev.model_name;
+       s = iface->wps->dev.model_name;
        s = ((s && *s) ? s : "");
        xml_add_tagged_data(buf, "modelName", s);
 
-       if (sm->wps->dev.model_number)
+       if (iface->wps->dev.model_number)
                xml_add_tagged_data(buf, "modelNumber",
-                                   sm->wps->dev.model_number);
+                                   iface->wps->dev.model_number);
 
-       if (sm->wps->model_url)
-               xml_add_tagged_data(buf, "modelURL", sm->wps->model_url);
+       if (iface->wps->model_url)
+               xml_add_tagged_data(buf, "modelURL", iface->wps->model_url);
 
-       if (sm->wps->dev.serial_number)
+       if (iface->wps->dev.serial_number)
                xml_add_tagged_data(buf, "serialNumber",
-                                   sm->wps->dev.serial_number);
+                                   iface->wps->dev.serial_number);
 
-       uuid_bin2str(sm->wps->uuid, uuid_string, sizeof(uuid_string));
+       uuid_bin2str(iface->wps->uuid, uuid_string, sizeof(uuid_string));
        s = uuid_string;
        /* Need "uuid:" prefix, thus we can't use xml_add_tagged_data()
         * easily...
@@ -231,8 +235,8 @@ static void format_wps_device_xml(struct upnp_wps_device_sm *sm,
        xml_data_encode(buf, s, os_strlen(s));
        wpabuf_put_str(buf, "</UDN>\n");
 
-       if (sm->wps->upc)
-               xml_add_tagged_data(buf, "UPC", sm->wps->upc);
+       if (iface->wps->upc)
+               xml_add_tagged_data(buf, "UPC", iface->wps->upc);
 
        wpabuf_put_str(buf, wps_device_xml_postfix);
 }
@@ -311,6 +315,10 @@ static void web_connection_parse_get(struct upnp_wps_device_sm *sm,
        size_t extra_len = 0;
        int body_length;
        char len_buf[10];
+       struct upnp_wps_device_interface *iface;
+
+       iface = dl_list_first(&sm->interfaces,
+                             struct upnp_wps_device_interface, list);
 
        /*
         * It is not required that filenames be case insensitive but it is
@@ -322,16 +330,16 @@ static void web_connection_parse_get(struct upnp_wps_device_sm *sm,
                wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for device XML");
                req = GET_DEVICE_XML_FILE;
                extra_len = 3000;
-               if (sm->wps->friendly_name)
-                       extra_len += os_strlen(sm->wps->friendly_name);
-               if (sm->wps->manufacturer_url)
-                       extra_len += os_strlen(sm->wps->manufacturer_url);
-               if (sm->wps->model_description)
-                       extra_len += os_strlen(sm->wps->model_description);
-               if (sm->wps->model_url)
-                       extra_len += os_strlen(sm->wps->model_url);
-               if (sm->wps->upc)
-                       extra_len += os_strlen(sm->wps->upc);
+               if (iface->wps->friendly_name)
+                       extra_len += os_strlen(iface->wps->friendly_name);
+               if (iface->wps->manufacturer_url)
+                       extra_len += os_strlen(iface->wps->manufacturer_url);
+               if (iface->wps->model_description)
+                       extra_len += os_strlen(iface->wps->model_description);
+               if (iface->wps->model_url)
+                       extra_len += os_strlen(iface->wps->model_url);
+               if (iface->wps->upc)
+                       extra_len += os_strlen(iface->wps->upc);
        } else if (!os_strcasecmp(filename, UPNP_WPS_SCPD_XML_FILE)) {
                wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for SCPD XML");
                req = GET_SCPD_XML_FILE;
@@ -408,11 +416,16 @@ web_process_get_device_info(struct upnp_wps_device_sm *sm,
 {
        static const char *name = "NewDeviceInfo";
        struct wps_config cfg;
-       struct upnp_wps_peer *peer = &sm->peer;
+       struct upnp_wps_device_interface *iface;
+       struct upnp_wps_peer *peer;
+
+       iface = dl_list_first(&sm->interfaces,
+                             struct upnp_wps_device_interface, list);
+       peer = &iface->peer;
 
        wpa_printf(MSG_DEBUG, "WPS UPnP: GetDeviceInfo");
 
-       if (sm->ctx->ap_pin == NULL)
+       if (iface->ctx->ap_pin == NULL)
                return HTTP_INTERNAL_SERVER_ERROR;
 
        /*
@@ -427,9 +440,9 @@ web_process_get_device_info(struct upnp_wps_device_sm *sm,
                wps_deinit(peer->wps);
 
        os_memset(&cfg, 0, sizeof(cfg));
-       cfg.wps = sm->wps;
-       cfg.pin = (u8 *) sm->ctx->ap_pin;
-       cfg.pin_len = os_strlen(sm->ctx->ap_pin);
+       cfg.wps = iface->wps;
+       cfg.pin = (u8 *) iface->ctx->ap_pin;
+       cfg.pin_len = os_strlen(iface->ctx->ap_pin);
        peer->wps = wps_init(&cfg);
        if (peer->wps) {
                enum wsc_op_code op_code;
@@ -458,6 +471,10 @@ web_process_put_message(struct upnp_wps_device_sm *sm, char *data,
        enum http_reply_code ret;
        enum wps_process_res res;
        enum wsc_op_code op_code;
+       struct upnp_wps_device_interface *iface;
+
+       iface = dl_list_first(&sm->interfaces,
+                             struct upnp_wps_device_interface, list);
 
        /*
         * PutMessage is used by external UPnP-based Registrar to perform WPS
@@ -468,11 +485,11 @@ web_process_put_message(struct upnp_wps_device_sm *sm, char *data,
        msg = xml_get_base64_item(data, "NewInMessage", &ret);
        if (msg == NULL)
                return ret;
-       res = wps_process_msg(sm->peer.wps, WSC_UPnP, msg);
+       res = wps_process_msg(iface->peer.wps, WSC_UPnP, msg);
        if (res == WPS_FAILURE)
                *reply = NULL;
        else
-               *reply = wps_get_msg(sm->peer.wps, &op_code);
+               *reply = wps_get_msg(iface->peer.wps, &op_code);
        wpabuf_free(msg);
        if (*reply == NULL)
                return HTTP_INTERNAL_SERVER_ERROR;
@@ -491,6 +508,8 @@ web_process_put_wlan_response(struct upnp_wps_device_sm *sm, char *data,
        int ev_type;
        int type;
        char *val;
+       struct upnp_wps_device_interface *iface;
+       int ok = 0;
 
        /*
         * External UPnP-based Registrar is passing us a message to be proxied
@@ -523,6 +542,16 @@ web_process_put_wlan_response(struct upnp_wps_device_sm *sm, char *data,
        if (hwaddr_aton(val, macaddr)) {
                wpa_printf(MSG_DEBUG, "WPS UPnP: Invalid NewWLANEventMAC in "
                           "PutWLANResponse: '%s'", val);
+#ifdef CONFIG_WPS_STRICT
+               {
+                       struct wps_parse_attr attr;
+                       if (wps_parse_msg(msg, &attr) < 0 || attr.version2) {
+                               wpabuf_free(msg);
+                               os_free(val);
+                               return UPNP_ARG_VALUE_INVALID;
+                       }
+               }
+#endif /* CONFIG_WPS_STRICT */
                if (hwaddr_aton2(val, macaddr) > 0) {
                        /*
                         * At least some versions of Intel PROset seem to be
@@ -530,7 +559,8 @@ web_process_put_wlan_response(struct upnp_wps_device_sm *sm, char *data,
                         */
                        wpa_printf(MSG_DEBUG, "WPS UPnP: Workaround - allow "
                                   "incorrect MAC address format in "
-                                  "NewWLANEventMAC");
+                                  "NewWLANEventMAC: %s -> " MACSTR,
+                                  val, MAC2STR(macaddr));
                } else {
                        wpabuf_free(msg);
                        os_free(val);
@@ -548,9 +578,16 @@ web_process_put_wlan_response(struct upnp_wps_device_sm *sm, char *data,
                wpa_printf(MSG_DEBUG, "WPS UPnP: Message Type %d", type);
        } else
                type = -1;
-       if (!sm->ctx->rx_req_put_wlan_response ||
-           sm->ctx->rx_req_put_wlan_response(sm->priv, ev_type, macaddr, msg,
-                                             type)) {
+       dl_list_for_each(iface, &sm->interfaces,
+                        struct upnp_wps_device_interface, list) {
+               if (iface->ctx->rx_req_put_wlan_response &&
+                   iface->ctx->rx_req_put_wlan_response(iface->priv, ev_type,
+                                                        macaddr, msg, type)
+                   == 0)
+                       ok = 1;
+       }
+
+       if (!ok) {
                wpa_printf(MSG_INFO, "WPS UPnP: Fail: sm->ctx->"
                           "rx_req_put_wlan_response");
                wpabuf_free(msg);
@@ -595,6 +632,8 @@ web_process_set_selected_registrar(struct upnp_wps_device_sm *sm,
        struct wpabuf *msg;
        enum http_reply_code ret;
        struct subscription *s;
+       struct upnp_wps_device_interface *iface;
+       int err = 0;
 
        wpa_printf(MSG_DEBUG, "WPS UPnP: SetSelectedRegistrar");
        s = find_er(sm, cli);
@@ -606,11 +645,15 @@ web_process_set_selected_registrar(struct upnp_wps_device_sm *sm,
        msg = xml_get_base64_item(data, "NewMessage", &ret);
        if (msg == NULL)
                return ret;
-       if (upnp_er_set_selected_registrar(sm->wps->registrar, s, msg)) {
-               wpabuf_free(msg);
-               return HTTP_INTERNAL_SERVER_ERROR;
+       dl_list_for_each(iface, &sm->interfaces,
+                        struct upnp_wps_device_interface, list) {
+               if (upnp_er_set_selected_registrar(iface->wps->registrar, s,
+                                                  msg))
+                       err = 1;
        }
        wpabuf_free(msg);
+       if (err)
+               return HTTP_INTERNAL_SERVER_ERROR;
        *replyname = NULL;
        *reply = NULL;
        return HTTP_OK;
@@ -890,6 +933,9 @@ static void web_connection_parse_subscribe(struct upnp_wps_device_sm *sm,
                return;
        }
 
+       wpa_hexdump_ascii(MSG_DEBUG, "WPS UPnP: HTTP SUBSCRIBE",
+                         (u8 *) hdr, os_strlen(hdr));
+
        /* Parse/validate headers */
        h = hdr;
        /* First line: SUBSCRIBE /wps_event HTTP/1.1
@@ -910,7 +956,7 @@ static void web_connection_parse_subscribe(struct upnp_wps_device_sm *sm,
                        break; /* no unterminated lines allowed */
 
                /* NT assures that it is our type of subscription;
-                * not used for a renewl.
+                * not used for a renewal.
                 **/
                match = "NT:";
                match_len = os_strlen(match);
@@ -989,16 +1035,22 @@ static void web_connection_parse_subscribe(struct upnp_wps_device_sm *sm,
 
        if (got_uuid) {
                /* renewal */
+               wpa_printf(MSG_DEBUG, "WPS UPnP: Subscription renewal");
                if (callback_urls) {
                        ret = HTTP_BAD_REQUEST;
                        goto error;
                }
                s = subscription_renew(sm, uuid);
                if (s == NULL) {
+                       char str[80];
+                       uuid_bin2str(uuid, str, sizeof(str));
+                       wpa_printf(MSG_DEBUG, "WPS UPnP: Could not find "
+                                  "SID %s", str);
                        ret = HTTP_PRECONDITION_FAILED;
                        goto error;
                }
        } else if (callback_urls) {
+               wpa_printf(MSG_DEBUG, "WPS UPnP: New subscription");
                if (!got_nt) {
                        ret = HTTP_PRECONDITION_FAILED;
                        goto error;
@@ -1022,6 +1074,7 @@ static void web_connection_parse_subscribe(struct upnp_wps_device_sm *sm,
        /* subscription id */
        b = wpabuf_put(buf, 0);
        uuid_bin2str(s->uuid, b, 80);
+       wpa_printf(MSG_DEBUG, "WPS UPnP: Assigned SID %s", b);
        wpabuf_put(buf, os_strlen(b));
        wpabuf_put_str(buf, "\r\n");
        wpabuf_printf(buf, "Timeout: Second-%d\r\n", UPNP_SUBSCRIBE_SEC);
@@ -1055,6 +1108,7 @@ error:
        *     HTTP 500-series error code.
        *   599 Too many subscriptions (not a standard HTTP error)
        */
+       wpa_printf(MSG_DEBUG, "WPS UPnP: SUBSCRIBE failed - return %d", ret);
        http_put_empty(buf, ret);
        http_request_send_and_deinit(req, buf);
        os_free(callback_urls);
diff --git a/src/wps/wps_validate.c b/src/wps/wps_validate.c
new file mode 100644 (file)
index 0000000..c3071a0
--- /dev/null
@@ -0,0 +1,1981 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "wps_i.h"
+#include "wps.h"
+
+
+#ifndef WPS_STRICT_ALL
+#define WPS_STRICT_WPS2
+#endif /* WPS_STRICT_ALL */
+
+
+static int wps_validate_version(const u8 *version, int mandatory)
+{
+       if (version == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Version attribute "
+                                  "missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (*version != 0x10) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Version attribute "
+                          "value 0x%x", *version);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_version2(const u8 *version2, int mandatory)
+{
+       if (version2 == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Version2 attribute "
+                                  "missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (*version2 < 0x20) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Version2 attribute "
+                          "value 0x%x", *version2);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_request_type(const u8 *request_type, int mandatory)
+{
+       if (request_type == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Request Type "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (*request_type > 0x03) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Request Type "
+                          "attribute value 0x%x", *request_type);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_response_type(const u8 *response_type, int mandatory)
+{
+       if (response_type == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Response Type "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (*response_type > 0x03) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Response Type "
+                          "attribute value 0x%x", *response_type);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int valid_config_methods(u16 val, int wps2)
+{
+       if (wps2) {
+               if ((val & 0x6000) && !(val & WPS_CONFIG_DISPLAY)) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Physical/Virtual "
+                                  "Display flag without old Display flag "
+                                  "set");
+                       return 0;
+               }
+               if (!(val & 0x6000) && (val & WPS_CONFIG_DISPLAY)) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Display flag "
+                                  "without Physical/Virtual Display flag");
+                       return 0;
+               }
+               if ((val & 0x0600) && !(val & WPS_CONFIG_PUSHBUTTON)) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Physical/Virtual "
+                                  "PushButton flag without old PushButton "
+                                  "flag set");
+                       return 0;
+               }
+               if (!(val & 0x0600) && (val & WPS_CONFIG_PUSHBUTTON)) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: PushButton flag "
+                                  "without Physical/Virtual PushButton flag");
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
+
+static int wps_validate_config_methods(const u8 *config_methods, int wps2,
+                                      int mandatory)
+{
+       u16 val;
+
+       if (config_methods == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Configuration "
+                                  "Methods attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+
+       val = WPA_GET_BE16(config_methods);
+       if (!valid_config_methods(val, wps2)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Configuration "
+                          "Methods attribute value 0x%04x", val);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_ap_config_methods(const u8 *config_methods, int wps2,
+                                         int mandatory)
+{
+       u16 val;
+
+       if (wps_validate_config_methods(config_methods, wps2, mandatory) < 0)
+               return -1;
+       if (config_methods == NULL)
+               return 0;
+       val = WPA_GET_BE16(config_methods);
+       if (val & WPS_CONFIG_PUSHBUTTON) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Configuration "
+                          "Methods attribute value 0x%04x in AP info "
+                          "(PushButton not allowed for registering new ER)",
+                          val);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_uuid_e(const u8 *uuid_e, int mandatory)
+{
+       if (uuid_e == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: UUID-E "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_uuid_r(const u8 *uuid_r, int mandatory)
+{
+       if (uuid_r == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: UUID-R "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_primary_dev_type(const u8 *primary_dev_type,
+                                        int mandatory)
+{
+       if (primary_dev_type == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Primary Device Type "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_rf_bands(const u8 *rf_bands, int mandatory)
+{
+       if (rf_bands == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: RF Bands "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (*rf_bands != WPS_RF_24GHZ && *rf_bands != WPS_RF_50GHZ &&
+           *rf_bands != (WPS_RF_24GHZ | WPS_RF_50GHZ)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Rf Bands "
+                          "attribute value 0x%x", *rf_bands);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_assoc_state(const u8 *assoc_state, int mandatory)
+{
+       u16 val;
+       if (assoc_state == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Association State "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       val = WPA_GET_BE16(assoc_state);
+       if (val > 4) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Association State "
+                          "attribute value 0x%04x", val);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_config_error(const u8 *config_error, int mandatory)
+{
+       u16 val;
+
+       if (config_error == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Configuration Error "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       val = WPA_GET_BE16(config_error);
+       if (val > 18) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Configuration Error "
+                          "attribute value 0x%04x", val);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_dev_password_id(const u8 *dev_password_id,
+                                       int mandatory)
+{
+       u16 val;
+
+       if (dev_password_id == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Device Password ID "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       val = WPA_GET_BE16(dev_password_id);
+       if (val >= 0x0006 && val <= 0x000f) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Device Password ID "
+                          "attribute value 0x%04x", val);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_manufacturer(const u8 *manufacturer, size_t len,
+                                    int mandatory)
+{
+       if (manufacturer == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Manufacturer "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (len > 0 && manufacturer[len - 1] == 0) {
+               wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Manufacturer "
+                          "attribute value", manufacturer, len);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_model_name(const u8 *model_name, size_t len,
+                                  int mandatory)
+{
+       if (model_name == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Model Name "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (len > 0 && model_name[len - 1] == 0) {
+               wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Model Name "
+                          "attribute value", model_name, len);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_model_number(const u8 *model_number, size_t len,
+                                    int mandatory)
+{
+       if (model_number == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Model Number "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (len > 0 && model_number[len - 1] == 0) {
+               wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Model Number "
+                          "attribute value", model_number, len);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_serial_number(const u8 *serial_number, size_t len,
+                                     int mandatory)
+{
+       if (serial_number == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Serial Number "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (len > 0 && serial_number[len - 1] == 0) {
+               wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Serial "
+                                 "Number attribute value",
+                                 serial_number, len);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_dev_name(const u8 *dev_name, size_t len,
+                                int mandatory)
+{
+       if (dev_name == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Device Name "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (len > 0 && dev_name[len - 1] == 0) {
+               wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Device Name "
+                          "attribute value", dev_name, len);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_request_to_enroll(const u8 *request_to_enroll,
+                                         int mandatory)
+{
+       if (request_to_enroll == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Request to Enroll "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (*request_to_enroll > 0x01) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Request to Enroll "
+                          "attribute value 0x%x", *request_to_enroll);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_req_dev_type(const u8 *req_dev_type[], size_t num,
+                                    int mandatory)
+{
+       if (num == 0) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Requested Device "
+                                  "Type attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_wps_state(const u8 *wps_state, int mandatory)
+{
+       if (wps_state == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Wi-Fi Protected "
+                                  "Setup State attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (*wps_state != WPS_STATE_NOT_CONFIGURED &&
+           *wps_state != WPS_STATE_CONFIGURED) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Wi-Fi Protected "
+                          "Setup State attribute value 0x%x", *wps_state);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_ap_setup_locked(const u8 *ap_setup_locked,
+                                       int mandatory)
+{
+       if (ap_setup_locked == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: AP Setup Locked "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (*ap_setup_locked > 1) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid AP Setup Locked "
+                          "attribute value 0x%x", *ap_setup_locked);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_selected_registrar(const u8 *selected_registrar,
+                                          int mandatory)
+{
+       if (selected_registrar == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Selected Registrar "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (*selected_registrar > 1) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Selected Registrar "
+                          "attribute value 0x%x", *selected_registrar);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_sel_reg_config_methods(const u8 *config_methods,
+                                              int wps2, int mandatory)
+{
+       u16 val;
+
+       if (config_methods == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Selected Registrar "
+                                  "Configuration Methods attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+
+       val = WPA_GET_BE16(config_methods);
+       if (!valid_config_methods(val, wps2)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Selected Registrar "
+                          "Configuration Methods attribute value 0x%04x",
+                          val);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_authorized_macs(const u8 *authorized_macs, size_t len,
+                                       int mandatory)
+{
+       if (authorized_macs == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Authorized MACs "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (len > 30 && (len % ETH_ALEN) != 0) {
+               wpa_hexdump(MSG_INFO, "WPS-STRICT: Invalid Authorized "
+                           "MACs attribute value", authorized_macs, len);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_msg_type(const u8 *msg_type, int mandatory)
+{
+       if (msg_type == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Message Type "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (*msg_type < WPS_Beacon || *msg_type > WPS_WSC_DONE) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Message Type "
+                          "attribute value 0x%x", *msg_type);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_mac_addr(const u8 *mac_addr, int mandatory)
+{
+       if (mac_addr == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: MAC Address "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (mac_addr[0] & 0x01) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid MAC Address "
+                          "attribute value " MACSTR, MAC2STR(mac_addr));
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_enrollee_nonce(const u8 *enrollee_nonce, int mandatory)
+{
+       if (enrollee_nonce == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Enrollee Nonce "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_registrar_nonce(const u8 *registrar_nonce,
+                                       int mandatory)
+{
+       if (registrar_nonce == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Registrar Nonce "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_public_key(const u8 *public_key, size_t len,
+                                  int mandatory)
+{
+       if (public_key == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Public Key "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (len != 192) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Public Key "
+                          "attribute length %d", (int) len);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int num_bits_set(u16 val)
+{
+       int c;
+       for (c = 0; val; c++)
+               val &= val - 1;
+       return c;
+}
+
+
+static int wps_validate_auth_type_flags(const u8 *flags, int mandatory)
+{
+       u16 val;
+
+       if (flags == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Authentication Type "
+                                  "Flags attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       val = WPA_GET_BE16(flags);
+       if ((val & ~WPS_AUTH_TYPES) || !(val & WPS_AUTH_WPA2PSK)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Authentication Type "
+                          "Flags attribute value 0x%04x", val);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_auth_type(const u8 *type, int mandatory)
+{
+       u16 val;
+
+       if (type == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Authentication Type "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       val = WPA_GET_BE16(type);
+       if ((val & ~WPS_AUTH_TYPES) || val == 0 ||
+           (num_bits_set(val) > 1 &&
+            val != (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK))) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Authentication Type "
+                          "attribute value 0x%04x", val);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_encr_type_flags(const u8 *flags, int mandatory)
+{
+       u16 val;
+
+       if (flags == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Encryption Type "
+                                  "Flags attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       val = WPA_GET_BE16(flags);
+       if ((val & ~WPS_ENCR_TYPES) || !(val & WPS_ENCR_AES)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Encryption Type "
+                          "Flags attribute value 0x%04x", val);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_encr_type(const u8 *type, int mandatory)
+{
+       u16 val;
+
+       if (type == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Encryption Type "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       val = WPA_GET_BE16(type);
+       if ((val & ~WPS_ENCR_TYPES) || val == 0 ||
+           (num_bits_set(val) > 1 && val != (WPS_ENCR_TKIP | WPS_ENCR_AES))) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Encryption Type "
+                          "attribute value 0x%04x", val);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_conn_type_flags(const u8 *flags, int mandatory)
+{
+       if (flags == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Connection Type "
+                                  "Flags attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if ((*flags & ~(WPS_CONN_ESS | WPS_CONN_IBSS)) ||
+           !(*flags & WPS_CONN_ESS)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Connection Type "
+                          "Flags attribute value 0x%02x", *flags);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_os_version(const u8 *os_version, int mandatory)
+{
+       if (os_version == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: OS Version "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_authenticator(const u8 *authenticator, int mandatory)
+{
+       if (authenticator == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Authenticator "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_e_hash1(const u8 *hash, int mandatory)
+{
+       if (hash == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: E-Hash1 "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_e_hash2(const u8 *hash, int mandatory)
+{
+       if (hash == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: E-Hash2 "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_r_hash1(const u8 *hash, int mandatory)
+{
+       if (hash == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: R-Hash1 "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_r_hash2(const u8 *hash, int mandatory)
+{
+       if (hash == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: R-Hash2 "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_encr_settings(const u8 *encr_settings, size_t len,
+                                  int mandatory)
+{
+       if (encr_settings == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Encrypted Settings "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (len < 16) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Encrypted Settings "
+                          "attribute length %d", (int) len);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_settings_delay_time(const u8 *delay, int mandatory)
+{
+       if (delay == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Settings Delay Time "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_r_snonce1(const u8 *nonce, int mandatory)
+{
+       if (nonce == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: R-SNonce1 "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_r_snonce2(const u8 *nonce, int mandatory)
+{
+       if (nonce == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: R-SNonce2 "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_e_snonce1(const u8 *nonce, int mandatory)
+{
+       if (nonce == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: E-SNonce1 "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_e_snonce2(const u8 *nonce, int mandatory)
+{
+       if (nonce == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: E-SNonce2 "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_key_wrap_auth(const u8 *auth, int mandatory)
+{
+       if (auth == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Key Wrap "
+                                  "Authenticator attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_ssid(const u8 *ssid, size_t ssid_len, int mandatory)
+{
+       if (ssid == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: SSID "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (ssid_len == 0 || ssid[ssid_len - 1] == 0) {
+               wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid SSID "
+                                 "attribute value", ssid, ssid_len);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_network_key_index(const u8 *idx, int mandatory)
+{
+       if (idx == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Network Key Index "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_network_idx(const u8 *idx, int mandatory)
+{
+       if (idx == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Network Index "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+
+static int wps_validate_network_key(const u8 *key, size_t key_len,
+                                   const u8 *encr_type, int mandatory)
+{
+       if (key == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Network Key "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (((encr_type == NULL || WPA_GET_BE16(encr_type) != WPS_ENCR_WEP) &&
+            key_len > 8 && key_len < 64 && key[key_len - 1] == 0) ||
+           key_len > 64) {
+               wpa_hexdump_ascii_key(MSG_INFO, "WPS-STRICT: Invalid Network "
+                                     "Key attribute value", key, key_len);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_network_key_shareable(const u8 *val, int mandatory)
+{
+       if (val == NULL) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Network Key "
+                                  "Shareable attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+       if (*val > 1) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Network Key "
+                          "Shareable attribute value 0x%x", *val);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int wps_validate_cred(const u8 *cred, size_t len)
+{
+       struct wps_parse_attr attr;
+       struct wpabuf buf;
+
+       if (cred == NULL)
+               return -1;
+       wpabuf_set(&buf, cred, len);
+       if (wps_parse_msg(&buf, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse Credential");
+               return -1;
+       }
+
+       if (wps_validate_network_idx(attr.network_idx, 1) ||
+           wps_validate_ssid(attr.ssid, attr.ssid_len, 1) ||
+           wps_validate_auth_type(attr.auth_type, 1) ||
+           wps_validate_encr_type(attr.encr_type, 1) ||
+           wps_validate_network_key_index(attr.network_key_idx, 0) ||
+           wps_validate_network_key(attr.network_key, attr.network_key_len,
+                                    attr.encr_type, 1) ||
+           wps_validate_mac_addr(attr.mac_addr, 1) ||
+           wps_validate_network_key_shareable(attr.network_key_shareable, 0))
+       {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Credential");
+               return -1;
+       }
+
+
+       return 0;
+}
+
+
+static int wps_validate_credential(const u8 *cred[], size_t len[], size_t num,
+                                  int mandatory)
+{
+       size_t i;
+
+       if (num == 0) {
+               if (mandatory) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Credential "
+                                  "attribute missing");
+                       return -1;
+               }
+               return 0;
+       }
+
+       for (i = 0; i < num; i++) {
+               if (wps_validate_cred(cred[i], len[i]) < 0)
+                       return -1;
+       }
+
+       return 0;
+}
+
+
+int wps_validate_beacon(const struct wpabuf *wps_ie)
+{
+       struct wps_parse_attr attr;
+       int wps2, sel_reg;
+
+       if (wps_ie == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in Beacon frame");
+               return -1;
+       }
+       if (wps_parse_msg(wps_ie, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in "
+                          "Beacon frame");
+               return -1;
+       }
+
+       wps2 = attr.version2 != NULL;
+       sel_reg = attr.selected_registrar != NULL &&
+               *attr.selected_registrar != 0;
+       if (wps_validate_version(attr.version, 1) ||
+           wps_validate_wps_state(attr.wps_state, 1) ||
+           wps_validate_ap_setup_locked(attr.ap_setup_locked, 0) ||
+           wps_validate_selected_registrar(attr.selected_registrar, 0) ||
+           wps_validate_dev_password_id(attr.dev_password_id, sel_reg) ||
+           wps_validate_sel_reg_config_methods(attr.sel_reg_config_methods,
+                                               wps2, sel_reg) ||
+           wps_validate_uuid_e(attr.uuid_e, 0) ||
+           wps_validate_rf_bands(attr.rf_bands, 0) ||
+           wps_validate_version2(attr.version2, wps2) ||
+           wps_validate_authorized_macs(attr.authorized_macs,
+                                        attr.authorized_macs_len, 0)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Beacon frame");
+               return -1;
+       }
+
+       return 0;
+}
+
+
+int wps_validate_beacon_probe_resp(const struct wpabuf *wps_ie, int probe,
+                                  const u8 *addr)
+{
+       struct wps_parse_attr attr;
+       int wps2, sel_reg;
+
+       if (wps_ie == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in "
+                          "%sProbe Response frame", probe ? "" : "Beacon/");
+               return -1;
+       }
+       if (wps_parse_msg(wps_ie, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in "
+                          "%sProbe Response frame", probe ? "" : "Beacon/");
+               return -1;
+       }
+
+       wps2 = attr.version2 != NULL;
+       sel_reg = attr.selected_registrar != NULL &&
+               *attr.selected_registrar != 0;
+       if (wps_validate_version(attr.version, 1) ||
+           wps_validate_wps_state(attr.wps_state, 1) ||
+           wps_validate_ap_setup_locked(attr.ap_setup_locked, 0) ||
+           wps_validate_selected_registrar(attr.selected_registrar, 0) ||
+           wps_validate_dev_password_id(attr.dev_password_id, sel_reg) ||
+           wps_validate_sel_reg_config_methods(attr.sel_reg_config_methods,
+                                               wps2, sel_reg) ||
+           wps_validate_response_type(attr.response_type, probe) ||
+           wps_validate_uuid_e(attr.uuid_e, probe) ||
+           wps_validate_manufacturer(attr.manufacturer, attr.manufacturer_len,
+                                     probe) ||
+           wps_validate_model_name(attr.model_name, attr.model_name_len,
+                                   probe) ||
+           wps_validate_model_number(attr.model_number, attr.model_number_len,
+                                     probe) ||
+           wps_validate_serial_number(attr.serial_number,
+                                      attr.serial_number_len, probe) ||
+           wps_validate_primary_dev_type(attr.primary_dev_type, probe) ||
+           wps_validate_dev_name(attr.dev_name, attr.dev_name_len, probe) ||
+           wps_validate_ap_config_methods(attr.config_methods, wps2, probe) ||
+           wps_validate_rf_bands(attr.rf_bands, 0) ||
+           wps_validate_version2(attr.version2, wps2) ||
+           wps_validate_authorized_macs(attr.authorized_macs,
+                                        attr.authorized_macs_len, 0)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid %sProbe Response "
+                          "frame from " MACSTR, probe ? "" : "Beacon/",
+                          MAC2STR(addr));
+#ifdef WPS_STRICT_WPS2
+               if (wps2)
+                       return -1;
+#else /* WPS_STRICT_WPS2 */
+               return -1;
+#endif /* WPS_STRICT_WPS2 */
+       }
+
+       return 0;
+}
+
+
+int wps_validate_probe_req(const struct wpabuf *wps_ie, const u8 *addr)
+{
+       struct wps_parse_attr attr;
+       int wps2;
+
+       if (wps_ie == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in "
+                          "Probe Request frame");
+               return -1;
+       }
+       if (wps_parse_msg(wps_ie, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in "
+                          "Probe Request frame");
+               return -1;
+       }
+
+       wps2 = attr.version2 != NULL;
+       if (wps_validate_version(attr.version, 1) ||
+           wps_validate_request_type(attr.request_type, 1) ||
+           wps_validate_config_methods(attr.config_methods, wps2, 1) ||
+           wps_validate_uuid_e(attr.uuid_e, attr.uuid_r == NULL) ||
+           wps_validate_uuid_r(attr.uuid_r, attr.uuid_e == NULL) ||
+           wps_validate_primary_dev_type(attr.primary_dev_type, 1) ||
+           wps_validate_rf_bands(attr.rf_bands, 1) ||
+           wps_validate_assoc_state(attr.assoc_state, 1) ||
+           wps_validate_config_error(attr.config_error, 1) ||
+           wps_validate_dev_password_id(attr.dev_password_id, 1) ||
+           wps_validate_version2(attr.version2, wps2) ||
+           wps_validate_manufacturer(attr.manufacturer, attr.manufacturer_len,
+                                     wps2) ||
+           wps_validate_model_name(attr.model_name, attr.model_name_len,
+                                   wps2) ||
+           wps_validate_model_number(attr.model_number, attr.model_number_len,
+                                     wps2) ||
+           wps_validate_dev_name(attr.dev_name, attr.dev_name_len, wps2) ||
+           wps_validate_request_to_enroll(attr.request_to_enroll, 0) ||
+           wps_validate_req_dev_type(attr.req_dev_type, attr.num_req_dev_type,
+                                     0)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Probe Request "
+                          "frame from " MACSTR, MAC2STR(addr));
+               return -1;
+       }
+
+       return 0;
+}
+
+
+int wps_validate_assoc_req(const struct wpabuf *wps_ie)
+{
+       struct wps_parse_attr attr;
+       int wps2;
+
+       if (wps_ie == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in "
+                          "(Re)Association Request frame");
+               return -1;
+       }
+       if (wps_parse_msg(wps_ie, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in "
+                          "(Re)Association Request frame");
+               return -1;
+       }
+
+       wps2 = attr.version2 != NULL;
+       if (wps_validate_version(attr.version, 1) ||
+           wps_validate_request_type(attr.request_type, 1) ||
+           wps_validate_version2(attr.version2, wps2)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid (Re)Association "
+                          "Request frame");
+               return -1;
+       }
+
+       return 0;
+}
+
+
+int wps_validate_assoc_resp(const struct wpabuf *wps_ie)
+{
+       struct wps_parse_attr attr;
+       int wps2;
+
+       if (wps_ie == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in "
+                          "(Re)Association Response frame");
+               return -1;
+       }
+       if (wps_parse_msg(wps_ie, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in "
+                          "(Re)Association Response frame");
+               return -1;
+       }
+
+       wps2 = attr.version2 != NULL;
+       if (wps_validate_version(attr.version, 1) ||
+           wps_validate_response_type(attr.response_type, 1) ||
+           wps_validate_version2(attr.version2, wps2)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid (Re)Association "
+                          "Response frame");
+               return -1;
+       }
+
+       return 0;
+}
+
+
+int wps_validate_m1(const struct wpabuf *tlvs)
+{
+       struct wps_parse_attr attr;
+       int wps2;
+
+       if (tlvs == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M1");
+               return -1;
+       }
+       if (wps_parse_msg(tlvs, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+                          "in M1");
+               return -1;
+       }
+
+       wps2 = attr.version2 != NULL;
+       if (wps_validate_version(attr.version, 1) ||
+           wps_validate_msg_type(attr.msg_type, 1) ||
+           wps_validate_uuid_e(attr.uuid_e, 1) ||
+           wps_validate_mac_addr(attr.mac_addr, 1) ||
+           wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+           wps_validate_public_key(attr.public_key, attr.public_key_len, 1) ||
+           wps_validate_auth_type_flags(attr.auth_type_flags, 1) ||
+           wps_validate_encr_type_flags(attr.encr_type_flags, 1) ||
+           wps_validate_conn_type_flags(attr.conn_type_flags, 1) ||
+           wps_validate_config_methods(attr.config_methods, wps2, 1) ||
+           wps_validate_wps_state(attr.wps_state, 1) ||
+           wps_validate_manufacturer(attr.manufacturer, attr.manufacturer_len,
+                                     1) ||
+           wps_validate_model_name(attr.model_name, attr.model_name_len, 1) ||
+           wps_validate_model_number(attr.model_number, attr.model_number_len,
+                                     1) ||
+           wps_validate_serial_number(attr.serial_number,
+                                      attr.serial_number_len, 1) ||
+           wps_validate_primary_dev_type(attr.primary_dev_type, 1) ||
+           wps_validate_dev_name(attr.dev_name, attr.dev_name_len, 1) ||
+           wps_validate_rf_bands(attr.rf_bands, 1) ||
+           wps_validate_assoc_state(attr.assoc_state, 1) ||
+           wps_validate_dev_password_id(attr.dev_password_id, 1) ||
+           wps_validate_config_error(attr.config_error, 1) ||
+           wps_validate_os_version(attr.os_version, 1) ||
+           wps_validate_version2(attr.version2, wps2) ||
+           wps_validate_request_to_enroll(attr.request_to_enroll, 0)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M1");
+#ifdef WPS_STRICT_WPS2
+               if (wps2)
+                       return -1;
+#else /* WPS_STRICT_WPS2 */
+               return -1;
+#endif /* WPS_STRICT_WPS2 */
+       }
+
+       return 0;
+}
+
+
+int wps_validate_m2(const struct wpabuf *tlvs)
+{
+       struct wps_parse_attr attr;
+       int wps2;
+
+       if (tlvs == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M2");
+               return -1;
+       }
+       if (wps_parse_msg(tlvs, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+                          "in M2");
+               return -1;
+       }
+
+       wps2 = attr.version2 != NULL;
+       if (wps_validate_version(attr.version, 1) ||
+           wps_validate_msg_type(attr.msg_type, 1) ||
+           wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+           wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+           wps_validate_uuid_r(attr.uuid_r, 1) ||
+           wps_validate_public_key(attr.public_key, attr.public_key_len, 1) ||
+           wps_validate_auth_type_flags(attr.auth_type_flags, 1) ||
+           wps_validate_encr_type_flags(attr.encr_type_flags, 1) ||
+           wps_validate_conn_type_flags(attr.conn_type_flags, 1) ||
+           wps_validate_config_methods(attr.config_methods, wps2, 1) ||
+           wps_validate_manufacturer(attr.manufacturer, attr.manufacturer_len,
+                                     1) ||
+           wps_validate_model_name(attr.model_name, attr.model_name_len, 1) ||
+           wps_validate_model_number(attr.model_number, attr.model_number_len,
+                                     1) ||
+           wps_validate_serial_number(attr.serial_number,
+                                      attr.serial_number_len, 1) ||
+           wps_validate_primary_dev_type(attr.primary_dev_type, 1) ||
+           wps_validate_dev_name(attr.dev_name, attr.dev_name_len, 1) ||
+           wps_validate_rf_bands(attr.rf_bands, 1) ||
+           wps_validate_assoc_state(attr.assoc_state, 1) ||
+           wps_validate_config_error(attr.config_error, 1) ||
+           wps_validate_dev_password_id(attr.dev_password_id, 1) ||
+           wps_validate_os_version(attr.os_version, 1) ||
+           wps_validate_version2(attr.version2, wps2) ||
+           wps_validate_authenticator(attr.authenticator, 1)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M2");
+#ifdef WPS_STRICT_WPS2
+               if (wps2)
+                       return -1;
+#else /* WPS_STRICT_WPS2 */
+               return -1;
+#endif /* WPS_STRICT_WPS2 */
+       }
+
+       return 0;
+}
+
+
+int wps_validate_m2d(const struct wpabuf *tlvs)
+{
+       struct wps_parse_attr attr;
+       int wps2;
+
+       if (tlvs == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M2D");
+               return -1;
+       }
+       if (wps_parse_msg(tlvs, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+                          "in M2D");
+               return -1;
+       }
+
+       wps2 = attr.version2 != NULL;
+       if (wps_validate_version(attr.version, 1) ||
+           wps_validate_msg_type(attr.msg_type, 1) ||
+           wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+           wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+           wps_validate_uuid_r(attr.uuid_r, 1) ||
+           wps_validate_auth_type_flags(attr.auth_type_flags, 1) ||
+           wps_validate_encr_type_flags(attr.encr_type_flags, 1) ||
+           wps_validate_conn_type_flags(attr.conn_type_flags, 1) ||
+           wps_validate_config_methods(attr.config_methods, wps2, 1) ||
+           wps_validate_manufacturer(attr.manufacturer, attr.manufacturer_len,
+                                     1) ||
+           wps_validate_model_name(attr.model_name, attr.model_name_len, 1) ||
+           wps_validate_model_number(attr.model_number, attr.model_number_len,
+                                     1) ||
+           wps_validate_serial_number(attr.serial_number,
+                                      attr.serial_number_len, 1) ||
+           wps_validate_primary_dev_type(attr.primary_dev_type, 1) ||
+           wps_validate_dev_name(attr.dev_name, attr.dev_name_len, 1) ||
+           wps_validate_rf_bands(attr.rf_bands, 1) ||
+           wps_validate_assoc_state(attr.assoc_state, 1) ||
+           wps_validate_config_error(attr.config_error, 1) ||
+           wps_validate_os_version(attr.os_version, 1) ||
+           wps_validate_version2(attr.version2, wps2)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M2D");
+#ifdef WPS_STRICT_WPS2
+               if (wps2)
+                       return -1;
+#else /* WPS_STRICT_WPS2 */
+               return -1;
+#endif /* WPS_STRICT_WPS2 */
+       }
+
+       return 0;
+}
+
+
+int wps_validate_m3(const struct wpabuf *tlvs)
+{
+       struct wps_parse_attr attr;
+       int wps2;
+
+       if (tlvs == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M3");
+               return -1;
+       }
+       if (wps_parse_msg(tlvs, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+                          "in M3");
+               return -1;
+       }
+
+       wps2 = attr.version2 != NULL;
+       if (wps_validate_version(attr.version, 1) ||
+           wps_validate_msg_type(attr.msg_type, 1) ||
+           wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+           wps_validate_e_hash1(attr.e_hash1, 1) ||
+           wps_validate_e_hash2(attr.e_hash2, 1) ||
+           wps_validate_version2(attr.version2, wps2) ||
+           wps_validate_authenticator(attr.authenticator, 1)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M3");
+#ifdef WPS_STRICT_WPS2
+               if (wps2)
+                       return -1;
+#else /* WPS_STRICT_WPS2 */
+               return -1;
+#endif /* WPS_STRICT_WPS2 */
+       }
+
+       return 0;
+}
+
+
+int wps_validate_m4(const struct wpabuf *tlvs)
+{
+       struct wps_parse_attr attr;
+       int wps2;
+
+       if (tlvs == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M4");
+               return -1;
+       }
+       if (wps_parse_msg(tlvs, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+                          "in M4");
+               return -1;
+       }
+
+       wps2 = attr.version2 != NULL;
+       if (wps_validate_version(attr.version, 1) ||
+           wps_validate_msg_type(attr.msg_type, 1) ||
+           wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+           wps_validate_r_hash1(attr.r_hash1, 1) ||
+           wps_validate_r_hash2(attr.r_hash2, 1) ||
+           wps_validate_encr_settings(attr.encr_settings,
+                                      attr.encr_settings_len, 1) ||
+           wps_validate_version2(attr.version2, wps2) ||
+           wps_validate_authenticator(attr.authenticator, 1)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M4");
+#ifdef WPS_STRICT_WPS2
+               if (wps2)
+                       return -1;
+#else /* WPS_STRICT_WPS2 */
+               return -1;
+#endif /* WPS_STRICT_WPS2 */
+       }
+
+       return 0;
+}
+
+
+int wps_validate_m4_encr(const struct wpabuf *tlvs, int wps2)
+{
+       struct wps_parse_attr attr;
+
+       if (tlvs == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M4 encrypted "
+                          "settings");
+               return -1;
+       }
+       if (wps_parse_msg(tlvs, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+                          "in M4 encrypted settings");
+               return -1;
+       }
+
+       if (wps_validate_r_snonce1(attr.r_snonce1, 1) ||
+           wps_validate_key_wrap_auth(attr.key_wrap_auth, 1)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M4 encrypted "
+                          "settings");
+#ifdef WPS_STRICT_WPS2
+               if (wps2)
+                       return -1;
+#else /* WPS_STRICT_WPS2 */
+               return -1;
+#endif /* WPS_STRICT_WPS2 */
+       }
+
+       return 0;
+}
+
+
+int wps_validate_m5(const struct wpabuf *tlvs)
+{
+       struct wps_parse_attr attr;
+       int wps2;
+
+       if (tlvs == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M5");
+               return -1;
+       }
+       if (wps_parse_msg(tlvs, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+                          "in M5");
+               return -1;
+       }
+
+       wps2 = attr.version2 != NULL;
+       if (wps_validate_version(attr.version, 1) ||
+           wps_validate_msg_type(attr.msg_type, 1) ||
+           wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+           wps_validate_encr_settings(attr.encr_settings,
+                                      attr.encr_settings_len, 1) ||
+           wps_validate_version2(attr.version2, wps2) ||
+           wps_validate_authenticator(attr.authenticator, 1)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M5");
+#ifdef WPS_STRICT_WPS2
+               if (wps2)
+                       return -1;
+#else /* WPS_STRICT_WPS2 */
+               return -1;
+#endif /* WPS_STRICT_WPS2 */
+       }
+
+       return 0;
+}
+
+
+int wps_validate_m5_encr(const struct wpabuf *tlvs, int wps2)
+{
+       struct wps_parse_attr attr;
+
+       if (tlvs == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M5 encrypted "
+                          "settings");
+               return -1;
+       }
+       if (wps_parse_msg(tlvs, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+                          "in M5 encrypted settings");
+               return -1;
+       }
+
+       if (wps_validate_e_snonce1(attr.e_snonce1, 1) ||
+           wps_validate_key_wrap_auth(attr.key_wrap_auth, 1)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M5 encrypted "
+                          "settings");
+#ifdef WPS_STRICT_WPS2
+               if (wps2)
+                       return -1;
+#else /* WPS_STRICT_WPS2 */
+               return -1;
+#endif /* WPS_STRICT_WPS2 */
+       }
+
+       return 0;
+}
+
+
+int wps_validate_m6(const struct wpabuf *tlvs)
+{
+       struct wps_parse_attr attr;
+       int wps2;
+
+       if (tlvs == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M6");
+               return -1;
+       }
+       if (wps_parse_msg(tlvs, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+                          "in M6");
+               return -1;
+       }
+
+       wps2 = attr.version2 != NULL;
+       if (wps_validate_version(attr.version, 1) ||
+           wps_validate_msg_type(attr.msg_type, 1) ||
+           wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+           wps_validate_encr_settings(attr.encr_settings,
+                                      attr.encr_settings_len, 1) ||
+           wps_validate_version2(attr.version2, wps2) ||
+           wps_validate_authenticator(attr.authenticator, 1)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M6");
+#ifdef WPS_STRICT_WPS2
+               if (wps2)
+                       return -1;
+#else /* WPS_STRICT_WPS2 */
+               return -1;
+#endif /* WPS_STRICT_WPS2 */
+       }
+
+       return 0;
+}
+
+
+int wps_validate_m6_encr(const struct wpabuf *tlvs, int wps2)
+{
+       struct wps_parse_attr attr;
+
+       if (tlvs == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M6 encrypted "
+                          "settings");
+               return -1;
+       }
+       if (wps_parse_msg(tlvs, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+                          "in M6 encrypted settings");
+               return -1;
+       }
+
+       if (wps_validate_r_snonce2(attr.r_snonce2, 1) ||
+           wps_validate_key_wrap_auth(attr.key_wrap_auth, 1)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M6 encrypted "
+                          "settings");
+#ifdef WPS_STRICT_WPS2
+               if (wps2)
+                       return -1;
+#else /* WPS_STRICT_WPS2 */
+               return -1;
+#endif /* WPS_STRICT_WPS2 */
+       }
+
+       return 0;
+}
+
+
+int wps_validate_m7(const struct wpabuf *tlvs)
+{
+       struct wps_parse_attr attr;
+       int wps2;
+
+       if (tlvs == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M7");
+               return -1;
+       }
+       if (wps_parse_msg(tlvs, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+                          "in M7");
+               return -1;
+       }
+
+       wps2 = attr.version2 != NULL;
+       if (wps_validate_version(attr.version, 1) ||
+           wps_validate_msg_type(attr.msg_type, 1) ||
+           wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+           wps_validate_encr_settings(attr.encr_settings,
+                                      attr.encr_settings_len, 1) ||
+           wps_validate_settings_delay_time(attr.settings_delay_time, 0) ||
+           wps_validate_version2(attr.version2, wps2) ||
+           wps_validate_authenticator(attr.authenticator, 1)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M7");
+#ifdef WPS_STRICT_WPS2
+               if (wps2)
+                       return -1;
+#else /* WPS_STRICT_WPS2 */
+               return -1;
+#endif /* WPS_STRICT_WPS2 */
+       }
+
+       return 0;
+}
+
+
+int wps_validate_m7_encr(const struct wpabuf *tlvs, int ap, int wps2)
+{
+       struct wps_parse_attr attr;
+
+       if (tlvs == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M7 encrypted "
+                          "settings");
+               return -1;
+       }
+       if (wps_parse_msg(tlvs, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+                          "in M7 encrypted settings");
+               return -1;
+       }
+
+       if (wps_validate_e_snonce2(attr.e_snonce2, 1) ||
+           wps_validate_ssid(attr.ssid, attr.ssid_len, !ap) ||
+           wps_validate_mac_addr(attr.mac_addr, !ap) ||
+           wps_validate_auth_type(attr.auth_type, !ap) ||
+           wps_validate_encr_type(attr.encr_type, !ap) ||
+           wps_validate_network_key_index(attr.network_key_idx, 0) ||
+           wps_validate_network_key(attr.network_key, attr.network_key_len,
+                                    attr.encr_type, !ap) ||
+           wps_validate_key_wrap_auth(attr.key_wrap_auth, 1)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M7 encrypted "
+                          "settings");
+#ifdef WPS_STRICT_WPS2
+               if (wps2)
+                       return -1;
+#else /* WPS_STRICT_WPS2 */
+               return -1;
+#endif /* WPS_STRICT_WPS2 */
+       }
+
+       return 0;
+}
+
+
+int wps_validate_m8(const struct wpabuf *tlvs)
+{
+       struct wps_parse_attr attr;
+       int wps2;
+
+       if (tlvs == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M8");
+               return -1;
+       }
+       if (wps_parse_msg(tlvs, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+                          "in M8");
+               return -1;
+       }
+
+       wps2 = attr.version2 != NULL;
+       if (wps_validate_version(attr.version, 1) ||
+           wps_validate_msg_type(attr.msg_type, 1) ||
+           wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+           wps_validate_encr_settings(attr.encr_settings,
+                                      attr.encr_settings_len, 1) ||
+           wps_validate_version2(attr.version2, wps2) ||
+           wps_validate_authenticator(attr.authenticator, 1)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M8");
+#ifdef WPS_STRICT_WPS2
+               if (wps2)
+                       return -1;
+#else /* WPS_STRICT_WPS2 */
+               return -1;
+#endif /* WPS_STRICT_WPS2 */
+       }
+
+       return 0;
+}
+
+
+int wps_validate_m8_encr(const struct wpabuf *tlvs, int ap, int wps2)
+{
+       struct wps_parse_attr attr;
+
+       if (tlvs == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M8 encrypted "
+                          "settings");
+               return -1;
+       }
+       if (wps_parse_msg(tlvs, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+                          "in M8 encrypted settings");
+               return -1;
+       }
+
+       if (wps_validate_ssid(attr.ssid, attr.ssid_len, ap) ||
+           wps_validate_auth_type(attr.auth_type, ap) ||
+           wps_validate_encr_type(attr.encr_type, ap) ||
+           wps_validate_network_key_index(attr.network_key_idx, 0) ||
+           wps_validate_mac_addr(attr.mac_addr, ap) ||
+           wps_validate_credential(attr.cred, attr.cred_len, attr.num_cred,
+                                   !ap) ||
+           wps_validate_key_wrap_auth(attr.key_wrap_auth, 1)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M8 encrypted "
+                          "settings");
+#ifdef WPS_STRICT_WPS2
+               if (wps2)
+                       return -1;
+#else /* WPS_STRICT_WPS2 */
+               return -1;
+#endif /* WPS_STRICT_WPS2 */
+       }
+
+       return 0;
+}
+
+
+int wps_validate_wsc_ack(const struct wpabuf *tlvs)
+{
+       struct wps_parse_attr attr;
+       int wps2;
+
+       if (tlvs == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in WSC_ACK");
+               return -1;
+       }
+       if (wps_parse_msg(tlvs, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+                          "in WSC_ACK");
+               return -1;
+       }
+
+       wps2 = attr.version2 != NULL;
+       if (wps_validate_version(attr.version, 1) ||
+           wps_validate_msg_type(attr.msg_type, 1) ||
+           wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+           wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+           wps_validate_version2(attr.version2, wps2)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC_ACK");
+#ifdef WPS_STRICT_WPS2
+               if (wps2)
+                       return -1;
+#else /* WPS_STRICT_WPS2 */
+               return -1;
+#endif /* WPS_STRICT_WPS2 */
+       }
+
+       return 0;
+}
+
+
+int wps_validate_wsc_nack(const struct wpabuf *tlvs)
+{
+       struct wps_parse_attr attr;
+       int wps2;
+
+       if (tlvs == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in WSC_NACK");
+               return -1;
+       }
+       if (wps_parse_msg(tlvs, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+                          "in WSC_NACK");
+               return -1;
+       }
+
+       wps2 = attr.version2 != NULL;
+       if (wps_validate_version(attr.version, 1) ||
+           wps_validate_msg_type(attr.msg_type, 1) ||
+           wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+           wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+           wps_validate_config_error(attr.config_error, 1) ||
+           wps_validate_version2(attr.version2, wps2)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC_NACK");
+#ifdef WPS_STRICT_WPS2
+               if (wps2)
+                       return -1;
+#else /* WPS_STRICT_WPS2 */
+               return -1;
+#endif /* WPS_STRICT_WPS2 */
+       }
+
+       return 0;
+}
+
+
+int wps_validate_wsc_done(const struct wpabuf *tlvs)
+{
+       struct wps_parse_attr attr;
+       int wps2;
+
+       if (tlvs == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in WSC_Done");
+               return -1;
+       }
+       if (wps_parse_msg(tlvs, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+                          "in WSC_Done");
+               return -1;
+       }
+
+       wps2 = attr.version2 != NULL;
+       if (wps_validate_version(attr.version, 1) ||
+           wps_validate_msg_type(attr.msg_type, 1) ||
+           wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+           wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+           wps_validate_version2(attr.version2, wps2)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC_Done");
+#ifdef WPS_STRICT_WPS2
+               if (wps2)
+                       return -1;
+#else /* WPS_STRICT_WPS2 */
+               return -1;
+#endif /* WPS_STRICT_WPS2 */
+       }
+
+       return 0;
+}
+
+
+int wps_validate_upnp_set_selected_registrar(const struct wpabuf *tlvs)
+{
+       struct wps_parse_attr attr;
+       int wps2;
+       int sel_reg;
+
+       if (tlvs == NULL) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in "
+                          "SetSelectedRegistrar");
+               return -1;
+       }
+       if (wps_parse_msg(tlvs, &attr) < 0) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+                          "in SetSelectedRegistrar");
+               return -1;
+       }
+
+       wps2 = attr.version2 != NULL;
+       sel_reg = attr.selected_registrar != NULL &&
+               *attr.selected_registrar != 0;
+       if (wps_validate_version(attr.version, 1) ||
+           wps_validate_dev_password_id(attr.dev_password_id, sel_reg) ||
+           wps_validate_sel_reg_config_methods(attr.sel_reg_config_methods,
+                                               wps2, sel_reg) ||
+           wps_validate_version2(attr.version2, wps2) ||
+           wps_validate_authorized_macs(attr.authorized_macs,
+                                        attr.authorized_macs_len, wps2) ||
+           wps_validate_uuid_r(attr.uuid_r, wps2)) {
+               wpa_printf(MSG_INFO, "WPS-STRICT: Invalid "
+                          "SetSelectedRegistrar");
+#ifdef WPS_STRICT_WPS2
+               if (wps2)
+                       return -1;
+#else /* WPS_STRICT_WPS2 */
+               return -1;
+#endif /* WPS_STRICT_WPS2 */
+       }
+
+       return 0;
+}
diff --git a/tests/Makefile b/tests/Makefile
new file mode 100644 (file)
index 0000000..91b10c5
--- /dev/null
@@ -0,0 +1,99 @@
+TESTS=test-base64 test-md4 test-md5 test-milenage test-ms_funcs test-sha1 \
+       test-sha256 test-aes test-asn1 test-x509 test-x509v3 test-list test-rc4
+
+all: $(TESTS)
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+CFLAGS += -I../src
+CFLAGS += -I../src/utils
+
+SLIBS = ../src/utils/libutils.a
+
+DLIBS = ../src/crypto/libcrypto.a \
+       ../src/tls/libtls.a
+
+LIBS = $(SLIBS) $(DLIBS)
+LLIBS = -Wl,--start-group $(DLIBS) -Wl,--end-group $(SLIBS)
+
+../src/utils/libutils.a:
+       $(MAKE) -C ../src/utils
+
+../src/crypto/libcrypto.a:
+       $(MAKE) -C ../src/crypto
+
+../src/tls/libtls.a:
+       $(MAKE) -C ../src/tls
+
+
+test-aes: test-aes.o $(LIBS)
+       $(LDO) $(LDFLAGS) -o $@ $^
+
+test-asn1: test-asn1.o $(LIBS)
+       $(LDO) $(LDFLAGS) -o $@ $^
+
+test-base64: test-base64.o $(LIBS)
+       $(LDO) $(LDFLAGS) -o $@ $^
+
+test-https: test-https.o $(LIBS)
+       $(LDO) $(LDFLAGS) -o $@ $< $(LLIBS)
+
+test-list: test-list.o $(LIBS)
+       $(LDO) $(LDFLAGS) -o $@ $^
+
+test-md4: test-md4.o $(LIBS)
+       $(LDO) $(LDFLAGS) -o $@ $^
+
+test-md5: test-md5.o $(LIBS)
+       $(LDO) $(LDFLAGS) -o $@ $^
+
+test-milenage: test-milenage.o $(LIBS)
+       $(LDO) $(LDFLAGS) -o $@ $^
+
+test-ms_funcs: test-ms_funcs.o $(LIBS)
+       $(LDO) $(LDFLAGS) -o $@ $^
+
+test-rc4: test-rc4.o $(LIBS)
+       $(LDO) $(LDFLAGS) -o $@ $^
+
+test-sha1: test-sha1.o $(LIBS)
+       $(LDO) $(LDFLAGS) -o $@ $^
+
+test-sha256: test-sha256.o $(LIBS)
+       $(LDO) $(LDFLAGS) -o $@ $^
+
+test-x509: test-x509.o $(LIBS)
+       $(LDO) $(LDFLAGS) -o $@ $< $(LLIBS)
+
+test-x509v3: test-x509v3.o $(LIBS)
+       $(LDO) $(LDFLAGS) -o $@ $< $(LLIBS)
+
+
+run-tests: $(TESTS)
+       ./test-aes
+       ./test-list
+       ./test-md4
+       ./test-md5
+       ./test-milenage
+       ./test-sha1
+       ./test-sha256
+       @echo
+       @echo All tests completed successfully.
+
+clean:
+       $(MAKE) -C ../src clean
+       rm -f $(TESTS) *~ *.o *.d
+       rm -f test_x509v3_nist.out.*
+       rm -f test_x509v3_nist2.out.*
+
+-include $(OBJS:%.o=%.d)
diff --git a/tests/test-aes.c b/tests/test-aes.c
new file mode 100644 (file)
index 0000000..f596a1e
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * Test program for AES
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/crypto.h"
+#include "crypto/aes_wrap.h"
+
+#define BLOCK_SIZE 16
+
+static void test_aes_perf(void)
+{
+#if 0 /* this did not seem to work with new compiler?! */
+#ifdef __i386__
+#define rdtscll(val) \
+     __asm__ __volatile__("rdtsc" : "=A" (val))
+       const int num_iters = 10;
+       int i;
+       unsigned int start, end;
+       u8 key[16], pt[16], ct[16];
+       void *ctx;
+
+       printf("keySetupEnc:");
+       for (i = 0; i < num_iters; i++) {
+               rdtscll(start);
+               ctx = aes_encrypt_init(key, 16);
+               rdtscll(end);
+               aes_encrypt_deinit(ctx);
+               printf(" %d", end - start);
+       }
+       printf("\n");
+
+       printf("Encrypt:");
+       ctx = aes_encrypt_init(key, 16);
+       for (i = 0; i < num_iters; i++) {
+               rdtscll(start);
+               aes_encrypt(ctx, pt, ct);
+               rdtscll(end);
+               printf(" %d", end - start);
+       }
+       aes_encrypt_deinit(ctx);
+       printf("\n");
+#endif /* __i386__ */
+#endif
+}
+
+
+static int test_eax(void)
+{
+       u8 msg[] = { 0xF7, 0xFB };
+       u8 key[] = { 0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B,
+                    0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4 };
+       u8 nonce[] = { 0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84,
+                      0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD };
+       u8 hdr[] = { 0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA };
+       u8 cipher[] = { 0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D,
+                       0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79,
+                       0x67, 0xE5 };
+       u8 data[sizeof(msg)], tag[BLOCK_SIZE];
+
+       memcpy(data, msg, sizeof(msg));
+       if (aes_128_eax_encrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
+                               data, sizeof(data), tag)) {
+               printf("AES-128 EAX mode encryption failed\n");
+               return 1;
+       }
+       if (memcmp(data, cipher, sizeof(data)) != 0) {
+               printf("AES-128 EAX mode encryption returned invalid cipher "
+                      "text\n");
+               return 1;
+       }
+       if (memcmp(tag, cipher + sizeof(data), BLOCK_SIZE) != 0) {
+               printf("AES-128 EAX mode encryption returned invalid tag\n");
+               return 1;
+       }
+
+       if (aes_128_eax_decrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
+                               data, sizeof(data), tag)) {
+               printf("AES-128 EAX mode decryption failed\n");
+               return 1;
+       }
+       if (memcmp(data, msg, sizeof(data)) != 0) {
+               printf("AES-128 EAX mode decryption returned invalid plain "
+                      "text\n");
+               return 1;
+       }
+
+       return 0;
+}
+
+
+static int test_cbc(void)
+{
+       struct cbc_test_vector {
+               u8 key[16];
+               u8 iv[16];
+               u8 plain[32];
+               u8 cipher[32];
+               size_t len;
+       } vectors[] = {
+               {
+                       { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
+                         0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 },
+                       { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
+                         0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 },
+                       "Single block msg",
+                       { 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8,
+                         0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a },
+                       16
+               },
+               {
+                       { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0,
+                         0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a },
+                       { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28,
+                         0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 },
+                       { 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 },
+                       { 0xd2, 0x96, 0xcd, 0x94, 0xc2, 0xcc, 0xcf, 0x8a,
+                         0x3a, 0x86, 0x30, 0x28, 0xb5, 0xe1, 0xdc, 0x0a,
+                         0x75, 0x86, 0x60, 0x2d, 0x25, 0x3c, 0xff, 0xf9,
+                         0x1b, 0x82, 0x66, 0xbe, 0xa6, 0xd6, 0x1a, 0xb1 },
+                       32
+               }
+       };
+       int ret = 0;
+       u8 *buf;
+       unsigned int i;
+
+       for (i = 0; i < sizeof(vectors) / sizeof(vectors[0]); i++) {
+               struct cbc_test_vector *tv = &vectors[i];
+               buf = malloc(tv->len);
+               if (buf == NULL) {
+                       ret++;
+                       break;
+               }
+               memcpy(buf, tv->plain, tv->len);
+               if (aes_128_cbc_encrypt(tv->key, tv->iv, buf, tv->len) ||
+                   memcmp(buf, tv->cipher, tv->len) != 0) {
+                       printf("AES-CBC encrypt %d failed\n", i);
+                       ret++;
+               }
+               memcpy(buf, tv->cipher, tv->len);
+               if (aes_128_cbc_decrypt(tv->key, tv->iv, buf, tv->len) ||
+                   memcmp(buf, tv->plain, tv->len) != 0) {
+                       printf("AES-CBC decrypt %d failed\n", i);
+                       ret++;
+               }
+               free(buf);
+       }
+
+       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
+ * http://csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38B.pdf
+ */
+
+struct omac1_test_vector {
+       u8 k[16];
+       u8 msg[64];
+       int msg_len;
+       u8 tag[16];
+};
+
+static struct omac1_test_vector test_vectors[] =
+{
+       {
+               { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+                 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+               { },
+               0,
+               { 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
+                 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 }
+       },
+       {
+               { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+                 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+               { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+                 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
+               16,
+               { 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
+                 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c }
+       },
+       {
+               { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+                 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+               { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+                 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+                 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+                 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+                 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 },
+               40,
+               { 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
+                 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 }
+       },
+       {
+               { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+                 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+               { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+                 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+                 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+                 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+                 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+                 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+                 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+                 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
+               64,
+               { 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92,
+                 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe }
+       },
+};
+
+
+int main(int argc, char *argv[])
+{
+       u8 kek[] = {
+               0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+               0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
+       };
+       u8 plain[] = {
+               0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+               0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+       };
+       u8 crypt[] = {
+               0x1F, 0xA6, 0x8B, 0x0A, 0x81, 0x12, 0xB4, 0x47,
+               0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82,
+               0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5
+       };
+       u8 result[24];
+       int ret = 0;
+       unsigned int i;
+       struct omac1_test_vector *tv;
+
+       if (aes_wrap(kek, 2, plain, result)) {
+               printf("AES-WRAP-128-128 reported failure\n");
+               ret++;
+       }
+       if (memcmp(result, crypt, 24) != 0) {
+               printf("AES-WRAP-128-128 failed\n");
+               ret++;
+       }
+       if (aes_unwrap(kek, 2, crypt, result)) {
+               printf("AES-UNWRAP-128-128 reported failure\n");
+               ret++;
+       }
+       if (memcmp(result, plain, 16) != 0) {
+               printf("AES-UNWRAP-128-128 failed\n");
+               ret++;
+               for (i = 0; i < 16; i++)
+                       printf(" %02x", result[i]);
+               printf("\n");
+       }
+
+       test_aes_perf();
+
+       for (i = 0; i < sizeof(test_vectors) / sizeof(test_vectors[0]); i++) {
+               tv = &test_vectors[i];
+               if (omac1_aes_128(tv->k, tv->msg, tv->msg_len, result) ||
+                   memcmp(result, tv->tag, 16) != 0) {
+                       printf("OMAC1-AES-128 test vector %d failed\n", i);
+                       ret++;
+               }
+
+               if (tv->msg_len > 1) {
+                       const u8 *addr[2];
+                       size_t len[2];
+
+                       addr[0] = tv->msg;
+                       len[0] = 1;
+                       addr[1] = tv->msg + 1;
+                       len[1] = tv->msg_len - 1;
+
+                       if (omac1_aes_128_vector(tv->k, 2, addr, len,
+                                                result) ||
+                           memcmp(result, tv->tag, 16) != 0) {
+                               printf("OMAC1-AES-128(vector) test vector %d "
+                                      "failed\n", i);
+                               ret++;
+                       }
+               }
+       }
+
+       ret += test_eax();
+
+       ret += test_cbc();
+
+       if (ret)
+               printf("FAILED!\n");
+
+       return ret;
+}
diff --git a/tests/test-asn1.c b/tests/test-asn1.c
new file mode 100644 (file)
index 0000000..e59aa49
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "tls/asn1.h"
+
+extern int wpa_debug_level;
+
+
+static const char * asn1_class_str(int class)
+{
+       switch (class) {
+       case ASN1_CLASS_UNIVERSAL:
+               return "Universal";
+       case ASN1_CLASS_APPLICATION:
+               return "Application";
+       case ASN1_CLASS_CONTEXT_SPECIFIC:
+               return "Context-specific";
+       case ASN1_CLASS_PRIVATE:
+               return "Private";
+       default:
+               return "?";
+       }
+}
+
+
+int asn1_parse(const u8 *buf, size_t len, int level)
+{
+       const u8 *pos, *prev, *end;
+       char prefix[10], str[100];
+       int _level;
+       struct asn1_hdr hdr;
+       struct asn1_oid oid;
+       u8 tmp;
+
+       _level = level;
+       if ((size_t) _level > sizeof(prefix) - 1)
+               _level = sizeof(prefix) - 1;
+       memset(prefix, ' ', _level);
+       prefix[_level] = '\0';
+
+       pos = buf;
+       end = buf + len;
+
+       while (pos < end) {
+               if (asn1_get_next(pos, end - pos, &hdr) < 0)
+                       return -1;
+
+               prev = pos;
+               pos = hdr.payload;
+
+               wpa_printf(MSG_MSGDUMP, "ASN.1:%s Class %d(%s) P/C %d(%s) "
+                          "Tag %u Length %u",
+                          prefix, hdr.class, asn1_class_str(hdr.class),
+                          hdr.constructed,
+                          hdr.constructed ? "Constructed" : "Primitive",
+                          hdr.tag, hdr.length);
+
+               if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC &&
+                   hdr.constructed) {
+                       if (asn1_parse(pos, hdr.length, level + 1) < 0)
+                               return -1;
+                       pos += hdr.length;
+               }
+
+               if (hdr.class != ASN1_CLASS_UNIVERSAL)
+                       continue;
+
+               switch (hdr.tag) {
+               case ASN1_TAG_EOC:
+                       if (hdr.length) {
+                               wpa_printf(MSG_DEBUG, "ASN.1: Non-zero "
+                                          "end-of-contents length (%u)",
+                                          hdr.length);
+                               return -1;
+                       }
+                       wpa_printf(MSG_MSGDUMP, "ASN.1:%s EOC", prefix);
+                       break;
+               case ASN1_TAG_BOOLEAN:
+                       if (hdr.length != 1) {
+                               wpa_printf(MSG_DEBUG, "ASN.1: Unexpected "
+                                          "Boolean length (%u)", hdr.length);
+                               return -1;
+                       }
+                       tmp = *pos++;
+                       wpa_printf(MSG_MSGDUMP, "ASN.1:%s Boolean %s",
+                                  prefix, tmp ? "TRUE" : "FALSE");
+                       break;
+               case ASN1_TAG_INTEGER:
+                       wpa_hexdump(MSG_MSGDUMP, "ASN.1: INTEGER",
+                                   pos, hdr.length);
+                       pos += hdr.length;
+                       break;
+               case ASN1_TAG_BITSTRING:
+                       wpa_hexdump(MSG_MSGDUMP, "ASN.1: BitString",
+                                   pos, hdr.length);
+                       pos += hdr.length;
+                       break;
+               case ASN1_TAG_OCTETSTRING:
+                       wpa_hexdump(MSG_MSGDUMP, "ASN.1: OctetString",
+                                   pos, hdr.length);
+                       pos += hdr.length;
+                       break;
+               case ASN1_TAG_NULL:
+                       if (hdr.length) {
+                               wpa_printf(MSG_DEBUG, "ASN.1: Non-zero Null "
+                                          "length (%u)", hdr.length);
+                               return -1;
+                       }
+                       wpa_printf(MSG_MSGDUMP, "ASN.1:%s Null", prefix);
+                       break;
+               case ASN1_TAG_OID:
+                       if (asn1_get_oid(prev, end - prev, &oid, &prev) < 0) {
+                               wpa_printf(MSG_DEBUG, "ASN.1: Invalid OID");
+                               return -1;
+                       }
+                       asn1_oid_to_str(&oid, str, sizeof(str));
+                       wpa_printf(MSG_DEBUG, "ASN.1:%s OID %s", prefix, str);
+                       pos += hdr.length;
+                       break;
+               case ANS1_TAG_RELATIVE_OID:
+                       wpa_hexdump(MSG_MSGDUMP, "ASN.1: Relative OID",
+                                   pos, hdr.length);
+                       pos += hdr.length;
+                       break;
+               case ASN1_TAG_SEQUENCE:
+                       wpa_printf(MSG_MSGDUMP, "ASN.1:%s SEQUENCE", prefix);
+                       if (asn1_parse(pos, hdr.length, level + 1) < 0)
+                               return -1;
+                       pos += hdr.length;
+                       break;
+               case ASN1_TAG_SET:
+                       wpa_printf(MSG_MSGDUMP, "ASN.1:%s SET", prefix);
+                       if (asn1_parse(pos, hdr.length, level + 1) < 0)
+                               return -1;
+                       pos += hdr.length;
+                       break;
+               case ASN1_TAG_PRINTABLESTRING:
+                       wpa_hexdump_ascii(MSG_MSGDUMP,
+                                         "ASN.1: PrintableString",
+                                         pos, hdr.length);
+                       pos += hdr.length;
+                       break;
+               case ASN1_TAG_IA5STRING:
+                       wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: IA5String",
+                                         pos, hdr.length);
+                       pos += hdr.length;
+                       break;
+               case ASN1_TAG_UTCTIME:
+                       wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: UTCTIME",
+                                         pos, hdr.length);
+                       pos += hdr.length;
+                       break;
+               case ASN1_TAG_VISIBLESTRING:
+                       wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: VisibleString",
+                                         pos, hdr.length);
+                       pos += hdr.length;
+                       break;
+               default:
+                       wpa_printf(MSG_DEBUG, "ASN.1: Unknown tag %d",
+                                  hdr.tag);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+       FILE *f;
+       u8 buf[3000];
+       size_t len;
+
+       wpa_debug_level = 0;
+
+       f = fopen(argv[1], "rb");
+       if (f == NULL)
+               return -1;
+       len = fread(buf, 1, sizeof(buf), f);
+       fclose(f);
+
+       if (asn1_parse(buf, len, 0) < 0)
+               printf("Failed to parse DER ASN.1\n");
+
+       printf("\n\n");
+
+       return 0;
+}
diff --git a/tests/test-base64.c b/tests/test-base64.c
new file mode 100644 (file)
index 0000000..747290e
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+#include "utils/os.h"
+#include "utils/base64.h"
+
+int main(int argc, char *argv[])
+{
+       FILE *f;
+       size_t len, elen;
+       unsigned char *buf, *e;
+
+       if (argc != 4) {
+               printf("Usage: base64 <encode|decode> <in file> <out file>\n");
+               return -1;
+       }
+
+       buf = (unsigned char *) os_readfile(argv[2], &len);
+       if (buf == NULL)
+               return -1;
+
+       if (strcmp(argv[1], "encode") == 0)
+               e = base64_encode(buf, len, &elen);
+       else
+               e = base64_decode(buf, len, &elen);
+       if (e == NULL)
+               return -2;
+       f = fopen(argv[3], "w");
+       if (f == NULL)
+               return -3;
+       fwrite(e, 1, elen, f);
+       fclose(f);
+       free(e);
+
+       return 0;
+}
diff --git a/tests/test-https.c b/tests/test-https.c
new file mode 100644 (file)
index 0000000..96e894d
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+#include <netdb.h>
+
+#include "common.h"
+#include "crypto/tls.h"
+
+extern int wpa_debug_level;
+extern int wpa_debug_show_keys;
+
+
+static void https_tls_event_cb(void *ctx, enum tls_event ev,
+                              union tls_event_data *data)
+{
+       wpa_printf(MSG_DEBUG, "HTTPS: TLS event %d", ev);
+}
+
+
+static struct wpabuf * https_recv(int s)
+{
+       struct wpabuf *in;
+       int len, ret;
+       fd_set rfds;
+       struct timeval tv;
+
+       in = wpabuf_alloc(20000);
+       if (in == NULL)
+               return NULL;
+
+       FD_ZERO(&rfds);
+       FD_SET(s, &rfds);
+       tv.tv_sec = 5;
+       tv.tv_usec = 0;
+
+       wpa_printf(MSG_DEBUG, "Waiting for more data");
+       ret = select(s + 1, &rfds, NULL, NULL, &tv);
+       if (ret < 0) {
+               wpa_printf(MSG_ERROR, "select: %s", strerror(errno));
+               wpabuf_free(in);
+               return NULL;
+       }
+       if (ret == 0) {
+               /* timeout */
+               wpa_printf(MSG_INFO, "Timeout on waiting for data");
+               wpabuf_free(in);
+               return NULL;
+       }
+
+       len = recv(s, wpabuf_put(in, 0), wpabuf_tailroom(in), 0);
+       if (len < 0) {
+               wpa_printf(MSG_ERROR, "recv: %s", strerror(errno));
+               wpabuf_free(in);
+               return NULL;
+       }
+       if (len == 0) {
+               wpa_printf(MSG_DEBUG, "No more data available");
+               wpabuf_free(in);
+               return NULL;
+       }
+       wpa_printf(MSG_DEBUG, "Received %d bytes", len);
+       wpabuf_put(in, len);
+
+       return in;
+}
+
+
+static int https_client(int s, const char *path)
+{
+       struct tls_config conf;
+       void *tls;
+       struct tls_connection *conn;
+       struct wpabuf *in, *out, *appl;
+       int res = -1;
+       int need_more_data;
+
+       os_memset(&conf, 0, sizeof(conf));
+       conf.event_cb = https_tls_event_cb;
+       tls = tls_init(&conf);
+       if (tls == NULL)
+               return -1;
+
+       conn = tls_connection_init(tls);
+       if (conn == NULL) {
+               tls_deinit(tls);
+               return -1;
+       }
+
+       in = NULL;
+
+       for (;;) {
+               appl = NULL;
+               out = tls_connection_handshake2(tls, conn, in, &appl,
+                                               &need_more_data);
+               wpabuf_free(in);
+               in = NULL;
+               if (out == NULL) {
+                       if (need_more_data)
+                               goto read_more;
+                       goto done;
+               }
+               if (tls_connection_get_failed(tls, conn)) {
+                       wpa_printf(MSG_ERROR, "TLS handshake failed");
+                       goto done;
+               }
+               if (tls_connection_established(tls, conn))
+                       break;
+               wpa_printf(MSG_DEBUG, "Sending %d bytes",
+                          (int) wpabuf_len(out));
+               if (send(s, wpabuf_head(out), wpabuf_len(out), 0) < 0) {
+                       wpa_printf(MSG_ERROR, "send: %s", strerror(errno));
+                       goto done;
+               }
+               wpabuf_free(out);
+               out = NULL;
+
+       read_more:
+               in = https_recv(s);
+               if (in == NULL)
+                       goto done;
+       }
+       wpabuf_free(out);
+       out = NULL;
+
+       wpa_printf(MSG_INFO, "TLS connection established");
+       if (appl)
+               wpa_hexdump_buf(MSG_DEBUG, "Received application data", appl);
+
+       in = wpabuf_alloc(100 + os_strlen(path));
+       if (in == NULL)
+               goto done;
+       wpabuf_put_str(in, "GET ");
+       wpabuf_put_str(in, path);
+       wpabuf_put_str(in, " HTTP/1.0\r\n\r\n");
+       out = tls_connection_encrypt(tls, conn, in);
+       wpabuf_free(in);
+       in = NULL;
+       if (out == NULL)
+               goto done;
+
+       wpa_printf(MSG_INFO, "Sending HTTP request: %d bytes",
+                  (int) wpabuf_len(out));
+       if (send(s, wpabuf_head(out), wpabuf_len(out), 0) < 0) {
+               wpa_printf(MSG_ERROR, "send: %s", strerror(errno));
+               goto done;
+       }
+       wpabuf_free(out);
+       out = NULL;
+
+       wpa_printf(MSG_INFO, "Reading HTTP response");
+       for (;;) {
+               int need_more_data;
+               in = https_recv(s);
+               if (in == NULL)
+                       goto done;
+               out = tls_connection_decrypt2(tls, conn, in, &need_more_data);
+               if (need_more_data)
+                       wpa_printf(MSG_DEBUG, "HTTP: Need more data");
+               wpabuf_free(in);
+               in = NULL;
+               if (out == NULL)
+                       goto done;
+               wpa_hexdump_ascii(MSG_INFO, "Response", wpabuf_head(out),
+                                 wpabuf_len(out));
+               wpabuf_free(out);
+               out = NULL;
+       }
+
+       res = 0;
+done:
+       wpabuf_free(out);
+       wpabuf_free(in);
+       wpabuf_free(appl);
+       tls_connection_deinit(tls, conn);
+       tls_deinit(tls);
+
+       return res;
+}
+
+
+int main(int argc, char *argv[])
+{
+       struct addrinfo hints, *result, *rp;
+       int res, s;
+
+       wpa_debug_level = 0;
+       wpa_debug_show_keys = 1;
+
+       if (argc < 4) {
+               wpa_printf(MSG_INFO, "usage: test-https server port path");
+               return -1;
+       }
+
+       os_memset(&hints, 0, sizeof(hints));
+       hints.ai_family = AF_UNSPEC;
+       hints.ai_socktype = SOCK_STREAM;
+       res = getaddrinfo(argv[1], argv[2], &hints, &result);
+       if (res) {
+               wpa_printf(MSG_ERROR, "getaddrinfo: %s", gai_strerror(res));
+               return -1;
+       }
+
+       for (rp = result; rp; rp = rp->ai_next) {
+               s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+               if (s < 0)
+                       continue;
+               if (connect(s, rp->ai_addr, rp->ai_addrlen) == 0)
+                       break;
+               close(s);
+       }
+       freeaddrinfo(result);
+
+       if (rp == NULL) {
+               wpa_printf(MSG_ERROR, "Could not connect");
+               return -1;
+       }
+
+       https_client(s, argv[3]);
+       close(s);
+
+       return 0;
+}
diff --git a/tests/test-list.c b/tests/test-list.c
new file mode 100644 (file)
index 0000000..930ce41
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+#include "utils/os.h"
+#include "utils/list.h"
+
+struct test {
+       struct dl_list list;
+       int value;
+};
+
+static void dump_list(struct dl_list *head)
+{
+       struct test *t;
+       printf("dump:");
+       dl_list_for_each(t, head, struct test, list)
+               printf(" %d", t->value);
+       printf(" (len=%d%s)\n", dl_list_len(head),
+              dl_list_empty(head) ? " empty" : "");
+}
+
+int main(int argc, char *argv[])
+{
+       struct dl_list head;
+       struct test *t, *tmp;
+       int i;
+
+       dl_list_init(&head);
+       dump_list(&head);
+
+       for (i = 0; i < 5; i++) {
+               t = os_zalloc(sizeof(*t));
+               if (t == NULL)
+                       return -1;
+               t->value = i;
+               dl_list_add(&head, &t->list);
+               dump_list(&head);
+       }
+
+       for (i = 10; i > 5; i--) {
+               t = os_zalloc(sizeof(*t));
+               if (t == NULL)
+                       return -1;
+               t->value = i;
+               dl_list_add_tail(&head, &t->list);
+               dump_list(&head);
+       }
+
+       i = 0;
+       dl_list_for_each(t, &head, struct test, list)
+               if (++i == 5)
+                       break;
+       printf("move: %d\n", t->value);
+       dl_list_del(&t->list);
+       dl_list_add(&head, &t->list);
+       dump_list(&head);
+
+       dl_list_for_each_safe(t, tmp, &head, struct test, list) {
+               printf("delete: %d\n", t->value);
+               dl_list_del(&t->list);
+               os_free(t);
+               dump_list(&head);
+       }
+
+       return 0;
+}
diff --git a/tests/test-md4.c b/tests/test-md4.c
new file mode 100644 (file)
index 0000000..e390d0f
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/crypto.h"
+
+int main(int argc, char *argv[])
+{
+       struct {
+               char *data;
+               char *hash;
+       } tests[] = {
+               {
+                       "",
+                       "\x31\xd6\xcf\xe0\xd1\x6a\xe9\x31"
+                       "\xb7\x3c\x59\xd7\xe0\xc0\x89\xc0"
+               },
+               {
+                       "a",
+                       "\xbd\xe5\x2c\xb3\x1d\xe3\x3e\x46"
+                       "\x24\x5e\x05\xfb\xdb\xd6\xfb\x24"
+               },
+               {
+                       "abc",
+                       "\xa4\x48\x01\x7a\xaf\x21\xd8\x52"
+                       "\x5f\xc1\x0a\xe8\x7a\xa6\x72\x9d"
+               },
+               {
+                       "message digest",
+                       "\xd9\x13\x0a\x81\x64\x54\x9f\xe8"
+                       "\x18\x87\x48\x06\xe1\xc7\x01\x4b"
+               },
+               {
+                       "abcdefghijklmnopqrstuvwxyz",
+                       "\xd7\x9e\x1c\x30\x8a\xa5\xbb\xcd"
+                       "\xee\xa8\xed\x63\xdf\x41\x2d\xa9"
+               },
+               {
+                       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+                       "0123456789",
+                       "\x04\x3f\x85\x82\xf2\x41\xdb\x35"
+                       "\x1c\xe6\x27\xe1\x53\xe7\xf0\xe4"
+               },
+               {
+                       "12345678901234567890123456789012345678901234567890"
+                       "123456789012345678901234567890",
+                       "\xe3\x3b\x4d\xdc\x9c\x38\xf2\x19"
+                       "\x9c\x3e\x7b\x16\x4f\xcc\x05\x36"
+               }
+       };
+       unsigned int i;
+       u8 hash[16];
+       const u8 *addr[2];
+       size_t len[2];
+       int errors = 0;
+
+       for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+               printf("MD4 test case %d:", i);
+
+               addr[0] = (u8 *) tests[i].data;
+               len[0] = strlen(tests[i].data);
+               md4_vector(1, addr, len, hash);
+               if (memcmp(hash, tests[i].hash, 16) != 0) {
+                       printf(" FAIL");
+                       errors++;
+               } else
+                       printf(" OK");
+
+               if (len[0]) {
+                       addr[0] = (u8 *) tests[i].data;
+                       len[0] = strlen(tests[i].data);
+                       addr[1] = (u8 *) tests[i].data + 1;
+                       len[1] = strlen(tests[i].data) - 1;
+                       md4_vector(1, addr, len, hash);
+                       if (memcmp(hash, tests[i].hash, 16) != 0) {
+                               printf(" FAIL");
+                               errors++;
+                       } else
+                               printf(" OK");
+               }
+
+               printf("\n");
+       }
+
+       return errors;
+}
diff --git a/tests/test-md5.c b/tests/test-md5.c
new file mode 100644 (file)
index 0000000..c33f1c2
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/crypto.h"
+
+int main(int argc, char *argv[])
+{
+       struct {
+               char *data;
+               char *hash;
+       } tests[] = {
+               {
+                       "",
+                       "\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04"
+                       "\xe9\x80\x09\x98\xec\xf8\x42\x7e"
+               },
+               {
+                       "a",
+                       "\x0c\xc1\x75\xb9\xc0\xf1\xb6\xa8"
+                       "\x31\xc3\x99\xe2\x69\x77\x26\x61"
+               },
+               {
+                       "abc",
+                       "\x90\x01\x50\x98\x3c\xd2\x4f\xb0"
+                       "\xd6\x96\x3f\x7d\x28\xe1\x7f\x72"
+               },
+               {
+                       "message digest",
+                       "\xf9\x6b\x69\x7d\x7c\xb7\x93\x8d"
+                       "\x52\x5a\x2f\x31\xaa\xf1\x61\xd0"
+               },
+               {
+                       "abcdefghijklmnopqrstuvwxyz",
+                       "\xc3\xfc\xd3\xd7\x61\x92\xe4\x00"
+                       "\x7d\xfb\x49\x6c\xca\x67\xe1\x3b"
+               },
+               {
+                       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+                       "0123456789",
+                       "\xd1\x74\xab\x98\xd2\x77\xd9\xf5"
+                       "\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f"
+               },
+               {
+                       "12345678901234567890123456789012345678901234567890"
+                       "123456789012345678901234567890",
+                       "\x57\xed\xf4\xa2\x2b\xe3\xc9\x55"
+                       "\xac\x49\xda\x2e\x21\x07\xb6\x7a"
+               }
+       };
+       unsigned int i;
+       u8 hash[16];
+       const u8 *addr[2];
+       size_t len[2];
+       int errors = 0;
+
+       for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+               printf("MD5 test case %d:", i);
+
+               addr[0] = (u8 *) tests[i].data;
+               len[0] = strlen(tests[i].data);
+               md5_vector(1, addr, len, hash);
+               if (memcmp(hash, tests[i].hash, 16) != 0) {
+                       printf(" FAIL");
+                       errors++;
+               } else
+                       printf(" OK");
+
+               if (len[0]) {
+                       addr[0] = (u8 *) tests[i].data;
+                       len[0] = strlen(tests[i].data);
+                       addr[1] = (u8 *) tests[i].data + 1;
+                       len[1] = strlen(tests[i].data) - 1;
+                       md5_vector(1, addr, len, hash);
+                       if (memcmp(hash, tests[i].hash, 16) != 0) {
+                               printf(" FAIL");
+                               errors++;
+                       } else
+                               printf(" OK");
+               }
+
+               printf("\n");
+       }
+
+       return errors;
+}
diff --git a/tests/test-milenage.c b/tests/test-milenage.c
new file mode 100644 (file)
index 0000000..b41e1a7
--- /dev/null
@@ -0,0 +1,817 @@
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/milenage.h"
+
+
+extern int wpa_debug_level;
+
+
+/**
+ * milenage_opc - Determine OPc from OP and K
+ * @op: OP = 128-bit operator variant algorithm configuration field
+ * @k: K = 128-bit subscriber key
+ * @opc: Buffer for OPc = 128-bit value derived from OP and K
+ */
+static int milenage_opc(const u8 *op, const u8 *k, u8 *opc)
+{
+       int i;
+       /* OP_C = OP XOR E_K(OP) */
+       if (aes_128_encrypt_block(k, op, opc) < 0)
+               return -1;
+       for (i = 0; i < 16; i++)
+               opc[i] ^= op[i];
+       return 0;
+}
+
+
+struct gsm_milenage_test_set {
+       u8 ki[16];
+       u8 rand[16];
+       u8 opc[16];
+       u8 sres1[4];
+       u8 sres2[4];
+       u8 kc[8];
+};
+
+static const struct gsm_milenage_test_set gsm_test_sets[] =
+{
+       {
+               /* 3GPP TS 55.205 v6.0.0 - Test Set 1 */
+               { 0x46, 0x5b, 0x5c, 0xe8, 0xb1, 0x99, 0xb4, 0x9f,
+                 0xaa, 0x5f, 0x0a, 0x2e, 0xe2, 0x38, 0xa6, 0xbc },
+               { 0x23, 0x55, 0x3c, 0xbe, 0x96, 0x37, 0xa8, 0x9d,
+                 0x21, 0x8a, 0xe6, 0x4d, 0xae, 0x47, 0xbf, 0x35 },
+               { 0xcd, 0x63, 0xcb, 0x71, 0x95, 0x4a, 0x9f, 0x4e,
+                 0x48, 0xa5, 0x99, 0x4e, 0x37, 0xa0, 0x2b, 0xaf },
+               { 0x46, 0xf8, 0x41, 0x6a },
+               { 0xa5, 0x42, 0x11, 0xd5 },
+               { 0xea, 0xe4, 0xbe, 0x82, 0x3a, 0xf9, 0xa0, 0x8b }
+       }, {
+               /* 3GPP TS 55.205 v6.0.0 - Test Set 2 */
+               { 0xfe, 0xc8, 0x6b, 0xa6, 0xeb, 0x70, 0x7e, 0xd0,
+                 0x89, 0x05, 0x75, 0x7b, 0x1b, 0xb4, 0x4b, 0x8f },
+               { 0x9f, 0x7c, 0x8d, 0x02, 0x1a, 0xcc, 0xf4, 0xdb,
+                 0x21, 0x3c, 0xcf, 0xf0, 0xc7, 0xf7, 0x1a, 0x6a },
+               { 0x10, 0x06, 0x02, 0x0f, 0x0a, 0x47, 0x8b, 0xf6,
+                 0xb6, 0x99, 0xf1, 0x5c, 0x06, 0x2e, 0x42, 0xb3 },
+               { 0x8c, 0x30, 0x8a, 0x5e },
+               { 0x80, 0x11, 0xc4, 0x8c },
+               { 0xaa, 0x01, 0x73, 0x9b, 0x8c, 0xaa, 0x97, 0x6d }
+       }, {
+               /* 3GPP TS 55.205 v6.0.0 - Test Set 3 */
+               { 0x9e, 0x59, 0x44, 0xae, 0xa9, 0x4b, 0x81, 0x16,
+                 0x5c, 0x82, 0xfb, 0xf9, 0xf3, 0x2d, 0xb7, 0x51 },
+               { 0xce, 0x83, 0xdb, 0xc5, 0x4a, 0xc0, 0x27, 0x4a,
+                 0x15, 0x7c, 0x17, 0xf8, 0x0d, 0x01, 0x7b, 0xd6 },
+               { 0xa6, 0x4a, 0x50, 0x7a, 0xe1, 0xa2, 0xa9, 0x8b,
+                 0xb8, 0x8e, 0xb4, 0x21, 0x01, 0x35, 0xdc, 0x87 },
+               { 0xcf, 0xbc, 0xe3, 0xfe },
+               { 0xf3, 0x65, 0xcd, 0x68 },
+               { 0x9a, 0x8e, 0xc9, 0x5f, 0x40, 0x8c, 0xc5, 0x07 }
+       }, {
+               /* 3GPP TS 55.205 v6.0.0 - Test Set 4 */
+               { 0x4a, 0xb1, 0xde, 0xb0, 0x5c, 0xa6, 0xce, 0xb0,
+                 0x51, 0xfc, 0x98, 0xe7, 0x7d, 0x02, 0x6a, 0x84 },
+               { 0x74, 0xb0, 0xcd, 0x60, 0x31, 0xa1, 0xc8, 0x33,
+                 0x9b, 0x2b, 0x6c, 0xe2, 0xb8, 0xc4, 0xa1, 0x86 },
+               { 0xdc, 0xf0, 0x7c, 0xbd, 0x51, 0x85, 0x52, 0x90,
+                 0xb9, 0x2a, 0x07, 0xa9, 0x89, 0x1e, 0x52, 0x3e },
+               { 0x96, 0x55, 0xe2, 0x65 },
+               { 0x58, 0x60, 0xfc, 0x1b },
+               { 0xcd, 0xc1, 0xdc, 0x08, 0x41, 0xb8, 0x1a, 0x22 }
+       }, {
+               /* 3GPP TS 55.205 v6.0.0 - Test Set 5 */
+               { 0x6c, 0x38, 0xa1, 0x16, 0xac, 0x28, 0x0c, 0x45,
+                 0x4f, 0x59, 0x33, 0x2e, 0xe3, 0x5c, 0x8c, 0x4f },
+               { 0xee, 0x64, 0x66, 0xbc, 0x96, 0x20, 0x2c, 0x5a,
+                 0x55, 0x7a, 0xbb, 0xef, 0xf8, 0xba, 0xbf, 0x63 },
+               { 0x38, 0x03, 0xef, 0x53, 0x63, 0xb9, 0x47, 0xc6,
+                 0xaa, 0xa2, 0x25, 0xe5, 0x8f, 0xae, 0x39, 0x34 },
+               { 0x13, 0x68, 0x8f, 0x17 },
+               { 0x16, 0xc8, 0x23, 0x3f },
+               { 0xdf, 0x75, 0xbc, 0x5e, 0xa8, 0x99, 0x87, 0x9f }
+       }, {
+               /* 3GPP TS 55.205 v6.0.0 - Test Set 6 */
+               { 0x2d, 0x60, 0x9d, 0x4d, 0xb0, 0xac, 0x5b, 0xf0,
+                 0xd2, 0xc0, 0xde, 0x26, 0x70, 0x14, 0xde, 0x0d },
+               { 0x19, 0x4a, 0xa7, 0x56, 0x01, 0x38, 0x96, 0xb7,
+                 0x4b, 0x4a, 0x2a, 0x3b, 0x0a, 0xf4, 0x53, 0x9e },
+               { 0xc3, 0x5a, 0x0a, 0xb0, 0xbc, 0xbf, 0xc9, 0x25,
+                 0x2c, 0xaf, 0xf1, 0x5f, 0x24, 0xef, 0xbd, 0xe0 },
+               { 0x55, 0x3d, 0x00, 0xb3 },
+               { 0x8c, 0x25, 0xa1, 0x6c },
+               { 0x84, 0xb4, 0x17, 0xae, 0x3a, 0xea, 0xb4, 0xf3 }
+       }, {
+               /* 3GPP TS 55.205 v6.0.0 - Test Set 7 */
+               { 0xa5, 0x30, 0xa7, 0xfe, 0x42, 0x8f, 0xad, 0x10,
+                 0x82, 0xc4, 0x5e, 0xdd, 0xfc, 0xe1, 0x38, 0x84 },
+               { 0x3a, 0x4c, 0x2b, 0x32, 0x45, 0xc5, 0x0e, 0xb5,
+                 0xc7, 0x1d, 0x08, 0x63, 0x93, 0x95, 0x76, 0x4d },
+               { 0x27, 0x95, 0x3e, 0x49, 0xbc, 0x8a, 0xf6, 0xdc,
+                 0xc6, 0xe7, 0x30, 0xeb, 0x80, 0x28, 0x6b, 0xe3 },
+               { 0x59, 0xf1, 0xa4, 0x4a },
+               { 0xa6, 0x32, 0x41, 0xe1 },
+               { 0x3b, 0x4e, 0x24, 0x4c, 0xdc, 0x60, 0xce, 0x03 }
+       }, {
+               /* 3GPP TS 55.205 v6.0.0 - Test Set 8 */
+               { 0xd9, 0x15, 0x1c, 0xf0, 0x48, 0x96, 0xe2, 0x58,
+                 0x30, 0xbf, 0x2e, 0x08, 0x26, 0x7b, 0x83, 0x60 },
+               { 0xf7, 0x61, 0xe5, 0xe9, 0x3d, 0x60, 0x3f, 0xeb,
+                 0x73, 0x0e, 0x27, 0x55, 0x6c, 0xb8, 0xa2, 0xca },
+               { 0xc4, 0xc9, 0x3e, 0xff, 0xe8, 0xa0, 0x81, 0x38,
+                 0xc2, 0x03, 0xd4, 0xc2, 0x7c, 0xe4, 0xe3, 0xd9 },
+               { 0x50, 0x58, 0x88, 0x61 },
+               { 0x4a, 0x90, 0xb2, 0x17 },
+               { 0x8d, 0x4e, 0xc0, 0x1d, 0xe5, 0x97, 0xac, 0xfe }
+       }, {
+               /* 3GPP TS 55.205 v6.0.0 - Test Set 9 */
+               { 0xa0, 0xe2, 0x97, 0x1b, 0x68, 0x22, 0xe8, 0xd3,
+                 0x54, 0xa1, 0x8c, 0xc2, 0x35, 0x62, 0x4e, 0xcb },
+               { 0x08, 0xef, 0xf8, 0x28, 0xb1, 0x3f, 0xdb, 0x56,
+                 0x27, 0x22, 0xc6, 0x5c, 0x7f, 0x30, 0xa9, 0xb2 },
+               { 0x82, 0xa2, 0x6f, 0x22, 0xbb, 0xa9, 0xe9, 0x48,
+                 0x8f, 0x94, 0x9a, 0x10, 0xd9, 0x8e, 0x9c, 0xc4 },
+               { 0xcd, 0xe6, 0xb0, 0x27 },
+               { 0x4b, 0xc2, 0x21, 0x2d },
+               { 0xd8, 0xde, 0xbc, 0x4f, 0xfb, 0xcd, 0x60, 0xaa }
+       }, {
+               /* 3GPP TS 55.205 v6.0.0 - Test Set 10 */
+               { 0x0d, 0xa6, 0xf7, 0xba, 0x86, 0xd5, 0xea, 0xc8,
+                 0xa1, 0x9c, 0xf5, 0x63, 0xac, 0x58, 0x64, 0x2d },
+               { 0x67, 0x9a, 0xc4, 0xdb, 0xac, 0xd7, 0xd2, 0x33,
+                 0xff, 0x9d, 0x68, 0x06, 0xf4, 0x14, 0x9c, 0xe3 },
+               { 0x0d, 0xb1, 0x07, 0x1f, 0x87, 0x67, 0x56, 0x2c,
+                 0xa4, 0x3a, 0x0a, 0x64, 0xc4, 0x1e, 0x8d, 0x08 },
+               { 0x02, 0xd1, 0x3a, 0xcd },
+               { 0x6f, 0xc3, 0x0f, 0xee },
+               { 0xf0, 0xea, 0xa5, 0x0a, 0x1e, 0xdc, 0xeb, 0xb7 }
+       }, {
+               /* 3GPP TS 55.205 v6.0.0 - Test Set 11 */
+               { 0x77, 0xb4, 0x58, 0x43, 0xc8, 0x8e, 0x58, 0xc1,
+                 0x0d, 0x20, 0x26, 0x84, 0x51, 0x5e, 0xd4, 0x30 },
+               { 0x4c, 0x47, 0xeb, 0x30, 0x76, 0xdc, 0x55, 0xfe,
+                 0x51, 0x06, 0xcb, 0x20, 0x34, 0xb8, 0xcd, 0x78 },
+               { 0xd4, 0x83, 0xaf, 0xae, 0x56, 0x24, 0x09, 0xa3,
+                 0x26, 0xb5, 0xbb, 0x0b, 0x20, 0xc4, 0xd7, 0x62 },
+               { 0x44, 0x38, 0x9d, 0x01 },
+               { 0xae, 0xfa, 0x35, 0x7b },
+               { 0x82, 0xdb, 0xab, 0x7f, 0x83, 0xf0, 0x63, 0xda }
+       }, {
+               /* 3GPP TS 55.205 v6.0.0 - Test Set 12 */
+               { 0x72, 0x9b, 0x17, 0x72, 0x92, 0x70, 0xdd, 0x87,
+                 0xcc, 0xdf, 0x1b, 0xfe, 0x29, 0xb4, 0xe9, 0xbb },
+               { 0x31, 0x1c, 0x4c, 0x92, 0x97, 0x44, 0xd6, 0x75,
+                 0xb7, 0x20, 0xf3, 0xb7, 0xe9, 0xb1, 0xcb, 0xd0 },
+               { 0x22, 0x8c, 0x2f, 0x2f, 0x06, 0xac, 0x32, 0x68,
+                 0xa9, 0xe6, 0x16, 0xee, 0x16, 0xdb, 0x4b, 0xa1 },
+               { 0x03, 0xe0, 0xfd, 0x84 },
+               { 0x98, 0xdb, 0xbd, 0x09 },
+               { 0x3c, 0x66, 0xcb, 0x98, 0xca, 0xb2, 0xd3, 0x3d }
+       }, {
+               /* 3GPP TS 55.205 v6.0.0 - Test Set 13 */
+               { 0xd3, 0x2d, 0xd2, 0x3e, 0x89, 0xdc, 0x66, 0x23,
+                 0x54, 0xca, 0x12, 0xeb, 0x79, 0xdd, 0x32, 0xfa },
+               { 0xcf, 0x7d, 0x0a, 0xb1, 0xd9, 0x43, 0x06, 0x95,
+                 0x0b, 0xf1, 0x20, 0x18, 0xfb, 0xd4, 0x68, 0x87 },
+               { 0xd2, 0x2a, 0x4b, 0x41, 0x80, 0xa5, 0x32, 0x57,
+                 0x08, 0xa5, 0xff, 0x70, 0xd9, 0xf6, 0x7e, 0xc7 },
+               { 0xbe, 0x73, 0xb3, 0xdc },
+               { 0xaf, 0x4a, 0x41, 0x1e },
+               { 0x96, 0x12, 0xb5, 0xd8, 0x8a, 0x41, 0x30, 0xbb }
+       }, {
+               /* 3GPP TS 55.205 v6.0.0 - Test Set 14 */
+               { 0xaf, 0x7c, 0x65, 0xe1, 0x92, 0x72, 0x21, 0xde,
+                 0x59, 0x11, 0x87, 0xa2, 0xc5, 0x98, 0x7a, 0x53 },
+               { 0x1f, 0x0f, 0x85, 0x78, 0x46, 0x4f, 0xd5, 0x9b,
+                 0x64, 0xbe, 0xd2, 0xd0, 0x94, 0x36, 0xb5, 0x7a },
+               { 0xa4, 0xcf, 0x5c, 0x81, 0x55, 0xc0, 0x8a, 0x7e,
+                 0xff, 0x41, 0x8e, 0x54, 0x43, 0xb9, 0x8e, 0x55 },
+               { 0x8f, 0xe0, 0x19, 0xc7 },
+               { 0x7b, 0xff, 0xa5, 0xc2 },
+               { 0x75, 0xa1, 0x50, 0xdf, 0x3c, 0x6a, 0xed, 0x08 }
+       }, {
+               /* 3GPP TS 55.205 v6.0.0 - Test Set 15 */
+               { 0x5b, 0xd7, 0xec, 0xd3, 0xd3, 0x12, 0x7a, 0x41,
+                 0xd1, 0x25, 0x39, 0xbe, 0xd4, 0xe7, 0xcf, 0x71 },
+               { 0x59, 0xb7, 0x5f, 0x14, 0x25, 0x1c, 0x75, 0x03,
+                 0x1d, 0x0b, 0xcb, 0xac, 0x1c, 0x2c, 0x04, 0xc7 },
+               { 0x76, 0x08, 0x9d, 0x3c, 0x0f, 0xf3, 0xef, 0xdc,
+                 0x6e, 0x36, 0x72, 0x1d, 0x4f, 0xce, 0xb7, 0x47 },
+               { 0x27, 0x20, 0x2b, 0x82 },
+               { 0x7e, 0x3f, 0x44, 0xc7 },
+               { 0xb7, 0xf9, 0x2e, 0x42, 0x6a, 0x36, 0xfe, 0xc5 }
+       }, {
+               /* 3GPP TS 55.205 v6.0.0 - Test Set 16 */
+               { 0x6c, 0xd1, 0xc6, 0xce, 0xb1, 0xe0, 0x1e, 0x14,
+                 0xf1, 0xb8, 0x23, 0x16, 0xa9, 0x0b, 0x7f, 0x3d },
+               { 0xf6, 0x9b, 0x78, 0xf3, 0x00, 0xa0, 0x56, 0x8b,
+                 0xce, 0x9f, 0x0c, 0xb9, 0x3c, 0x4b, 0xe4, 0xc9 },
+               { 0xa2, 0x19, 0xdc, 0x37, 0xf1, 0xdc, 0x7d, 0x66,
+                 0x73, 0x8b, 0x58, 0x43, 0xc7, 0x99, 0xf2, 0x06 },
+               { 0xdd, 0xd7, 0xef, 0xe6 },
+               { 0x70, 0xf6, 0xbd, 0xb9 },
+               { 0x88, 0xd9, 0xde, 0x10, 0xa2, 0x20, 0x04, 0xc5 }
+       }, {
+               /* 3GPP TS 55.205 v6.0.0 - Test Set 17 */
+               { 0xb7, 0x3a, 0x90, 0xcb, 0xcf, 0x3a, 0xfb, 0x62,
+                 0x2d, 0xba, 0x83, 0xc5, 0x8a, 0x84, 0x15, 0xdf },
+               { 0xb1, 0x20, 0xf1, 0xc1, 0xa0, 0x10, 0x2a, 0x2f,
+                 0x50, 0x7d, 0xd5, 0x43, 0xde, 0x68, 0x28, 0x1f },
+               { 0xdf, 0x0c, 0x67, 0x86, 0x8f, 0xa2, 0x5f, 0x74,
+                 0x8b, 0x70, 0x44, 0xc6, 0xe7, 0xc2, 0x45, 0xb8 },
+               { 0x67, 0xe4, 0xff, 0x3f },
+               { 0x47, 0x9d, 0xd2, 0x5c },
+               { 0xa8, 0x19, 0xe5, 0x77, 0xa8, 0xd6, 0x17, 0x5b }
+       }, {
+               /* 3GPP TS 55.205 v6.0.0 - Test Set 18 */
+               { 0x51, 0x22, 0x25, 0x02, 0x14, 0xc3, 0x3e, 0x72,
+                 0x3a, 0x5d, 0xd5, 0x23, 0xfc, 0x14, 0x5f, 0xc0 },
+               { 0x81, 0xe9, 0x2b, 0x6c, 0x0e, 0xe0, 0xe1, 0x2e,
+                 0xbc, 0xeb, 0xa8, 0xd9, 0x2a, 0x99, 0xdf, 0xa5 },
+               { 0x98, 0x1d, 0x46, 0x4c, 0x7c, 0x52, 0xeb, 0x6e,
+                 0x50, 0x36, 0x23, 0x49, 0x84, 0xad, 0x0b, 0xcf },
+               { 0x8a, 0x3b, 0x8d, 0x17 },
+               { 0x28, 0xd7, 0xb0, 0xf2 },
+               { 0x9a, 0x8d, 0x0e, 0x88, 0x3f, 0xf0, 0x88, 0x7a }
+       }, {
+               /* 3GPP TS 55.205 v6.0.0 - Test Set 19 */
+               { 0x90, 0xdc, 0xa4, 0xed, 0xa4, 0x5b, 0x53, 0xcf,
+                 0x0f, 0x12, 0xd7, 0xc9, 0xc3, 0xbc, 0x6a, 0x89 },
+               { 0x9f, 0xdd, 0xc7, 0x20, 0x92, 0xc6, 0xad, 0x03,
+                 0x6b, 0x6e, 0x46, 0x47, 0x89, 0x31, 0x5b, 0x78 },
+               { 0xcb, 0x9c, 0xcc, 0xc4, 0xb9, 0x25, 0x8e, 0x6d,
+                 0xca, 0x47, 0x60, 0x37, 0x9f, 0xb8, 0x25, 0x81 },
+               { 0xdf, 0x58, 0x52, 0x2f },
+               { 0xa9, 0x51, 0x00, 0xe2 },
+               { 0xed, 0x29, 0xb2, 0xf1, 0xc2, 0x7f, 0x9f, 0x34 }
+       }
+};
+
+#define NUM_GSM_TESTS (sizeof(gsm_test_sets) / sizeof(gsm_test_sets[0]))
+
+
+struct milenage_test_set {
+       u8 k[16];
+       u8 rand[16];
+       u8 sqn[6];
+       u8 amf[2];
+       u8 op[16];
+       u8 opc[16];
+       u8 f1[8];
+       u8 f1star[8];
+       u8 f2[8];
+       u8 f3[16];
+       u8 f4[16];
+       u8 f5[6];
+       u8 f5star[6];
+};
+
+static const struct milenage_test_set test_sets[] =
+{
+       {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.1 Test Set 1 */
+               { 0x46, 0x5b, 0x5c, 0xe8, 0xb1, 0x99, 0xb4, 0x9f,
+                 0xaa, 0x5f, 0x0a, 0x2e, 0xe2, 0x38, 0xa6, 0xbc },
+               { 0x23, 0x55, 0x3c, 0xbe, 0x96, 0x37, 0xa8, 0x9d,
+                 0x21, 0x8a, 0xe6, 0x4d, 0xae, 0x47, 0xbf, 0x35 },
+               { 0xff, 0x9b, 0xb4, 0xd0, 0xb6, 0x07 },
+               { 0xb9, 0xb9 },
+               { 0xcd, 0xc2, 0x02, 0xd5, 0x12, 0x3e, 0x20, 0xf6,
+                 0x2b, 0x6d, 0x67, 0x6a, 0xc7, 0x2c, 0xb3, 0x18 },
+               { 0xcd, 0x63, 0xcb, 0x71, 0x95, 0x4a, 0x9f, 0x4e,
+                 0x48, 0xa5, 0x99, 0x4e, 0x37, 0xa0, 0x2b, 0xaf },
+               { 0x4a, 0x9f, 0xfa, 0xc3, 0x54, 0xdf, 0xaf, 0xb3 },
+               { 0x01, 0xcf, 0xaf, 0x9e, 0xc4, 0xe8, 0x71, 0xe9 },
+               { 0xa5, 0x42, 0x11, 0xd5, 0xe3, 0xba, 0x50, 0xbf },
+               { 0xb4, 0x0b, 0xa9, 0xa3, 0xc5, 0x8b, 0x2a, 0x05,
+                 0xbb, 0xf0, 0xd9, 0x87, 0xb2, 0x1b, 0xf8, 0xcb },
+               { 0xf7, 0x69, 0xbc, 0xd7, 0x51, 0x04, 0x46, 0x04,
+                 0x12, 0x76, 0x72, 0x71, 0x1c, 0x6d, 0x34, 0x41 },
+               { 0xaa, 0x68, 0x9c, 0x64, 0x83, 0x70 },
+               { 0x45, 0x1e, 0x8b, 0xec, 0xa4, 0x3b }
+       }, {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.2 Test Set 2 */
+               { 0x46, 0x5b, 0x5c, 0xe8, 0xb1, 0x99, 0xb4, 0x9f,
+                 0xaa, 0x5f, 0x0a, 0x2e, 0xe2, 0x38, 0xa6, 0xbc },
+               { 0x23, 0x55, 0x3c, 0xbe, 0x96, 0x37, 0xa8, 0x9d,
+                 0x21, 0x8a, 0xe6, 0x4d, 0xae, 0x47, 0xbf, 0x35 },
+               { 0xff, 0x9b, 0xb4, 0xd0, 0xb6, 0x07 },
+               { 0xb9, 0xb9 },
+               { 0xcd, 0xc2, 0x02, 0xd5, 0x12, 0x3e, 0x20, 0xf6,
+                 0x2b, 0x6d, 0x67, 0x6a, 0xc7, 0x2c, 0xb3, 0x18 },
+               { 0xcd, 0x63, 0xcb, 0x71, 0x95, 0x4a, 0x9f, 0x4e,
+                 0x48, 0xa5, 0x99, 0x4e, 0x37, 0xa0, 0x2b, 0xaf },
+               { 0x4a, 0x9f, 0xfa, 0xc3, 0x54, 0xdf, 0xaf, 0xb3 },
+               { 0x01, 0xcf, 0xaf, 0x9e, 0xc4, 0xe8, 0x71, 0xe9 },
+               { 0xa5, 0x42, 0x11, 0xd5, 0xe3, 0xba, 0x50, 0xbf },
+               { 0xb4, 0x0b, 0xa9, 0xa3, 0xc5, 0x8b, 0x2a, 0x05,
+                 0xbb, 0xf0, 0xd9, 0x87, 0xb2, 0x1b, 0xf8, 0xcb },
+               { 0xf7, 0x69, 0xbc, 0xd7, 0x51, 0x04, 0x46, 0x04,
+                 0x12, 0x76, 0x72, 0x71, 0x1c, 0x6d, 0x34, 0x41 },
+               { 0xaa, 0x68, 0x9c, 0x64, 0x83, 0x70 },
+               { 0x45, 0x1e, 0x8b, 0xec, 0xa4, 0x3b }
+       }, {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.3 Test Set 3 */
+               { 0xfe, 0xc8, 0x6b, 0xa6, 0xeb, 0x70, 0x7e, 0xd0,
+                 0x89, 0x05, 0x75, 0x7b, 0x1b, 0xb4, 0x4b, 0x8f },
+               { 0x9f, 0x7c, 0x8d, 0x02, 0x1a, 0xcc, 0xf4, 0xdb,
+                 0x21, 0x3c, 0xcf, 0xf0, 0xc7, 0xf7, 0x1a, 0x6a },
+               { 0x9d, 0x02, 0x77, 0x59, 0x5f, 0xfc },
+               { 0x72, 0x5c },
+               { 0xdb, 0xc5, 0x9a, 0xdc, 0xb6, 0xf9, 0xa0, 0xef,
+                 0x73, 0x54, 0x77, 0xb7, 0xfa, 0xdf, 0x83, 0x74 },
+               { 0x10, 0x06, 0x02, 0x0f, 0x0a, 0x47, 0x8b, 0xf6,
+                 0xb6, 0x99, 0xf1, 0x5c, 0x06, 0x2e, 0x42, 0xb3 },
+               { 0x9c, 0xab, 0xc3, 0xe9, 0x9b, 0xaf, 0x72, 0x81 },
+               { 0x95, 0x81, 0x4b, 0xa2, 0xb3, 0x04, 0x43, 0x24 },
+               { 0x80, 0x11, 0xc4, 0x8c, 0x0c, 0x21, 0x4e, 0xd2 },
+               { 0x5d, 0xbd, 0xbb, 0x29, 0x54, 0xe8, 0xf3, 0xcd,
+                 0xe6, 0x65, 0xb0, 0x46, 0x17, 0x9a, 0x50, 0x98 },
+               { 0x59, 0xa9, 0x2d, 0x3b, 0x47, 0x6a, 0x04, 0x43,
+                 0x48, 0x70, 0x55, 0xcf, 0x88, 0xb2, 0x30, 0x7b },
+               { 0x33, 0x48, 0x4d, 0xc2, 0x13, 0x6b },
+               { 0xde, 0xac, 0xdd, 0x84, 0x8c, 0xc6 }
+       }, {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.4 Test Set 4 */
+               { 0x9e, 0x59, 0x44, 0xae, 0xa9, 0x4b, 0x81, 0x16,
+                 0x5c, 0x82, 0xfb, 0xf9, 0xf3, 0x2d, 0xb7, 0x51 },
+               { 0xce, 0x83, 0xdb, 0xc5, 0x4a, 0xc0, 0x27, 0x4a,
+                 0x15, 0x7c, 0x17, 0xf8, 0x0d, 0x01, 0x7b, 0xd6 },
+               { 0x0b, 0x60, 0x4a, 0x81, 0xec, 0xa8 },
+               { 0x9e, 0x09 },
+               { 0x22, 0x30, 0x14, 0xc5, 0x80, 0x66, 0x94, 0xc0,
+                 0x07, 0xca, 0x1e, 0xee, 0xf5, 0x7f, 0x00, 0x4f },
+               { 0xa6, 0x4a, 0x50, 0x7a, 0xe1, 0xa2, 0xa9, 0x8b,
+                 0xb8, 0x8e, 0xb4, 0x21, 0x01, 0x35, 0xdc, 0x87 },
+               { 0x74, 0xa5, 0x82, 0x20, 0xcb, 0xa8, 0x4c, 0x49 },
+               { 0xac, 0x2c, 0xc7, 0x4a, 0x96, 0x87, 0x18, 0x37 },
+               { 0xf3, 0x65, 0xcd, 0x68, 0x3c, 0xd9, 0x2e, 0x96 },
+               { 0xe2, 0x03, 0xed, 0xb3, 0x97, 0x15, 0x74, 0xf5,
+                 0xa9, 0x4b, 0x0d, 0x61, 0xb8, 0x16, 0x34, 0x5d },
+               { 0x0c, 0x45, 0x24, 0xad, 0xea, 0xc0, 0x41, 0xc4,
+                 0xdd, 0x83, 0x0d, 0x20, 0x85, 0x4f, 0xc4, 0x6b },
+               { 0xf0, 0xb9, 0xc0, 0x8a, 0xd0, 0x2e },
+               { 0x60, 0x85, 0xa8, 0x6c, 0x6f, 0x63 }
+       }, {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.5 Test Set 5 */
+               { 0x4a, 0xb1, 0xde, 0xb0, 0x5c, 0xa6, 0xce, 0xb0,
+                 0x51, 0xfc, 0x98, 0xe7, 0x7d, 0x02, 0x6a, 0x84 },
+               { 0x74, 0xb0, 0xcd, 0x60, 0x31, 0xa1, 0xc8, 0x33,
+                 0x9b, 0x2b, 0x6c, 0xe2, 0xb8, 0xc4, 0xa1, 0x86 },
+               { 0xe8, 0x80, 0xa1, 0xb5, 0x80, 0xb6 },
+               { 0x9f, 0x07 },
+               { 0x2d, 0x16, 0xc5, 0xcd, 0x1f, 0xdf, 0x6b, 0x22,
+                 0x38, 0x35, 0x84, 0xe3, 0xbe, 0xf2, 0xa8, 0xd8 },
+               { 0xdc, 0xf0, 0x7c, 0xbd, 0x51, 0x85, 0x52, 0x90,
+                 0xb9, 0x2a, 0x07, 0xa9, 0x89, 0x1e, 0x52, 0x3e },
+               { 0x49, 0xe7, 0x85, 0xdd, 0x12, 0x62, 0x6e, 0xf2 },
+               { 0x9e, 0x85, 0x79, 0x03, 0x36, 0xbb, 0x3f, 0xa2 },
+               { 0x58, 0x60, 0xfc, 0x1b, 0xce, 0x35, 0x1e, 0x7e },
+               { 0x76, 0x57, 0x76, 0x6b, 0x37, 0x3d, 0x1c, 0x21,
+                 0x38, 0xf3, 0x07, 0xe3, 0xde, 0x92, 0x42, 0xf9 },
+               { 0x1c, 0x42, 0xe9, 0x60, 0xd8, 0x9b, 0x8f, 0xa9,
+                 0x9f, 0x27, 0x44, 0xe0, 0x70, 0x8c, 0xcb, 0x53 },
+               { 0x31, 0xe1, 0x1a, 0x60, 0x91, 0x18 },
+               { 0xfe, 0x25, 0x55, 0xe5, 0x4a, 0xa9 }
+       }, {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.6 Test Set 6 */
+               { 0x6c, 0x38, 0xa1, 0x16, 0xac, 0x28, 0x0c, 0x45,
+                 0x4f, 0x59, 0x33, 0x2e, 0xe3, 0x5c, 0x8c, 0x4f },
+               { 0xee, 0x64, 0x66, 0xbc, 0x96, 0x20, 0x2c, 0x5a,
+                 0x55, 0x7a, 0xbb, 0xef, 0xf8, 0xba, 0xbf, 0x63 },
+               { 0x41, 0x4b, 0x98, 0x22, 0x21, 0x81 },
+               { 0x44, 0x64 },
+               { 0x1b, 0xa0, 0x0a, 0x1a, 0x7c, 0x67, 0x00, 0xac,
+                 0x8c, 0x3f, 0xf3, 0xe9, 0x6a, 0xd0, 0x87, 0x25 },
+               { 0x38, 0x03, 0xef, 0x53, 0x63, 0xb9, 0x47, 0xc6,
+                 0xaa, 0xa2, 0x25, 0xe5, 0x8f, 0xae, 0x39, 0x34 },
+               { 0x07, 0x8a, 0xdf, 0xb4, 0x88, 0x24, 0x1a, 0x57 },
+               { 0x80, 0x24, 0x6b, 0x8d, 0x01, 0x86, 0xbc, 0xf1 },
+               { 0x16, 0xc8, 0x23, 0x3f, 0x05, 0xa0, 0xac, 0x28 },
+               { 0x3f, 0x8c, 0x75, 0x87, 0xfe, 0x8e, 0x4b, 0x23,
+                 0x3a, 0xf6, 0x76, 0xae, 0xde, 0x30, 0xba, 0x3b },
+               { 0xa7, 0x46, 0x6c, 0xc1, 0xe6, 0xb2, 0xa1, 0x33,
+                 0x7d, 0x49, 0xd3, 0xb6, 0x6e, 0x95, 0xd7, 0xb4 },
+               { 0x45, 0xb0, 0xf6, 0x9a, 0xb0, 0x6c },
+               { 0x1f, 0x53, 0xcd, 0x2b, 0x11, 0x13 }
+       }, {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.7 Test Set 7 */
+               { 0x2d, 0x60, 0x9d, 0x4d, 0xb0, 0xac, 0x5b, 0xf0,
+                 0xd2, 0xc0, 0xde, 0x26, 0x70, 0x14, 0xde, 0x0d },
+               { 0x19, 0x4a, 0xa7, 0x56, 0x01, 0x38, 0x96, 0xb7,
+                 0x4b, 0x4a, 0x2a, 0x3b, 0x0a, 0xf4, 0x53, 0x9e },
+               { 0x6b, 0xf6, 0x94, 0x38, 0xc2, 0xe4 },
+               { 0x5f, 0x67 },
+               { 0x46, 0x0a, 0x48, 0x38, 0x54, 0x27, 0xaa, 0x39,
+                 0x26, 0x4a, 0xac, 0x8e, 0xfc, 0x9e, 0x73, 0xe8 },
+               { 0xc3, 0x5a, 0x0a, 0xb0, 0xbc, 0xbf, 0xc9, 0x25,
+                 0x2c, 0xaf, 0xf1, 0x5f, 0x24, 0xef, 0xbd, 0xe0 },
+               { 0xbd, 0x07, 0xd3, 0x00, 0x3b, 0x9e, 0x5c, 0xc3 },
+               { 0xbc, 0xb6, 0xc2, 0xfc, 0xad, 0x15, 0x22, 0x50 },
+               { 0x8c, 0x25, 0xa1, 0x6c, 0xd9, 0x18, 0xa1, 0xdf },
+               { 0x4c, 0xd0, 0x84, 0x60, 0x20, 0xf8, 0xfa, 0x07,
+                 0x31, 0xdd, 0x47, 0xcb, 0xdc, 0x6b, 0xe4, 0x11 },
+               { 0x88, 0xab, 0x80, 0xa4, 0x15, 0xf1, 0x5c, 0x73,
+                 0x71, 0x12, 0x54, 0xa1, 0xd3, 0x88, 0xf6, 0x96 },
+               { 0x7e, 0x64, 0x55, 0xf3, 0x4c, 0xf3 },
+               { 0xdc, 0x6d, 0xd0, 0x1e, 0x8f, 0x15 }
+       }, {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.8 Test Set 8 */
+               { 0xa5, 0x30, 0xa7, 0xfe, 0x42, 0x8f, 0xad, 0x10,
+                 0x82, 0xc4, 0x5e, 0xdd, 0xfc, 0xe1, 0x38, 0x84 },
+               { 0x3a, 0x4c, 0x2b, 0x32, 0x45, 0xc5, 0x0e, 0xb5,
+                 0xc7, 0x1d, 0x08, 0x63, 0x93, 0x95, 0x76, 0x4d },
+               { 0xf6, 0x3f, 0x5d, 0x76, 0x87, 0x84 },
+               { 0xb9, 0x0e },
+               { 0x51, 0x1c, 0x6c, 0x4e, 0x83, 0xe3, 0x8c, 0x89,
+                 0xb1, 0xc5, 0xd8, 0xdd, 0xe6, 0x24, 0x26, 0xfa },
+               { 0x27, 0x95, 0x3e, 0x49, 0xbc, 0x8a, 0xf6, 0xdc,
+                 0xc6, 0xe7, 0x30, 0xeb, 0x80, 0x28, 0x6b, 0xe3 },
+               { 0x53, 0x76, 0x1f, 0xbd, 0x67, 0x9b, 0x0b, 0xad },
+               { 0x21, 0xad, 0xfd, 0x33, 0x4a, 0x10, 0xe7, 0xce },
+               { 0xa6, 0x32, 0x41, 0xe1, 0xff, 0xc3, 0xe5, 0xab },
+               { 0x10, 0xf0, 0x5b, 0xab, 0x75, 0xa9, 0x9a, 0x5f,
+                 0xbb, 0x98, 0xa9, 0xc2, 0x87, 0x67, 0x9c, 0x3b },
+               { 0xf9, 0xec, 0x08, 0x65, 0xeb, 0x32, 0xf2, 0x23,
+                 0x69, 0xca, 0xde, 0x40, 0xc5, 0x9c, 0x3a, 0x44 },
+               { 0x88, 0x19, 0x6c, 0x47, 0x98, 0x6f },
+               { 0xc9, 0x87, 0xa3, 0xd2, 0x31, 0x15 }
+       }, {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.9 Test Set 9 */
+               { 0xd9, 0x15, 0x1c, 0xf0, 0x48, 0x96, 0xe2, 0x58,
+                 0x30, 0xbf, 0x2e, 0x08, 0x26, 0x7b, 0x83, 0x60 },
+               { 0xf7, 0x61, 0xe5, 0xe9, 0x3d, 0x60, 0x3f, 0xeb,
+                 0x73, 0x0e, 0x27, 0x55, 0x6c, 0xb8, 0xa2, 0xca },
+               { 0x47, 0xee, 0x01, 0x99, 0x82, 0x0a },
+               { 0x91, 0x13 },
+               { 0x75, 0xfc, 0x22, 0x33, 0xa4, 0x42, 0x94, 0xee,
+                 0x8e, 0x6d, 0xe2, 0x5c, 0x43, 0x53, 0xd2, 0x6b },
+               { 0xc4, 0xc9, 0x3e, 0xff, 0xe8, 0xa0, 0x81, 0x38,
+                 0xc2, 0x03, 0xd4, 0xc2, 0x7c, 0xe4, 0xe3, 0xd9 },
+               { 0x66, 0xcc, 0x4b, 0xe4, 0x48, 0x62, 0xaf, 0x1f },
+               { 0x7a, 0x4b, 0x8d, 0x7a, 0x87, 0x53, 0xf2, 0x46 },
+               { 0x4a, 0x90, 0xb2, 0x17, 0x1a, 0xc8, 0x3a, 0x76 },
+               { 0x71, 0x23, 0x6b, 0x71, 0x29, 0xf9, 0xb2, 0x2a,
+                 0xb7, 0x7e, 0xa7, 0xa5, 0x4c, 0x96, 0xda, 0x22 },
+               { 0x90, 0x52, 0x7e, 0xba, 0xa5, 0x58, 0x89, 0x68,
+                 0xdb, 0x41, 0x72, 0x73, 0x25, 0xa0, 0x4d, 0x9e },
+               { 0x82, 0xa0, 0xf5, 0x28, 0x7a, 0x71 },
+               { 0x52, 0x7d, 0xbf, 0x41, 0xf3, 0x5f }
+       }, {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.10 Test Set 10 */
+               { 0xa0, 0xe2, 0x97, 0x1b, 0x68, 0x22, 0xe8, 0xd3,
+                 0x54, 0xa1, 0x8c, 0xc2, 0x35, 0x62, 0x4e, 0xcb },
+               { 0x08, 0xef, 0xf8, 0x28, 0xb1, 0x3f, 0xdb, 0x56,
+                 0x27, 0x22, 0xc6, 0x5c, 0x7f, 0x30, 0xa9, 0xb2 },
+               { 0xdb, 0x5c, 0x06, 0x64, 0x81, 0xe0 },
+               { 0x71, 0x6b },
+               { 0x32, 0x37, 0x92, 0xfa, 0xca, 0x21, 0xfb, 0x4d,
+                 0x5d, 0x6f, 0x13, 0xc1, 0x45, 0xa9, 0xd2, 0xc1 },
+               { 0x82, 0xa2, 0x6f, 0x22, 0xbb, 0xa9, 0xe9, 0x48,
+                 0x8f, 0x94, 0x9a, 0x10, 0xd9, 0x8e, 0x9c, 0xc4 },
+               { 0x94, 0x85, 0xfe, 0x24, 0x62, 0x1c, 0xb9, 0xf6 },
+               { 0xbc, 0xe3, 0x25, 0xce, 0x03, 0xe2, 0xe9, 0xb9 },
+               { 0x4b, 0xc2, 0x21, 0x2d, 0x86, 0x24, 0x91, 0x0a },
+               { 0x08, 0xce, 0xf6, 0xd0, 0x04, 0xec, 0x61, 0x47,
+                 0x1a, 0x3c, 0x3c, 0xda, 0x04, 0x81, 0x37, 0xfa },
+               { 0xed, 0x03, 0x18, 0xca, 0x5d, 0xeb, 0x92, 0x06,
+                 0x27, 0x2f, 0x6e, 0x8f, 0xa6, 0x4b, 0xa4, 0x11 },
+               { 0xa2, 0xf8, 0x58, 0xaa, 0x9e, 0x5d },
+               { 0x74, 0xe7, 0x6f, 0xbb, 0xec, 0x38 }
+       }, {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.11 Test Set 11 */
+               { 0x0d, 0xa6, 0xf7, 0xba, 0x86, 0xd5, 0xea, 0xc8,
+                 0xa1, 0x9c, 0xf5, 0x63, 0xac, 0x58, 0x64, 0x2d },
+               { 0x67, 0x9a, 0xc4, 0xdb, 0xac, 0xd7, 0xd2, 0x33,
+                 0xff, 0x9d, 0x68, 0x06, 0xf4, 0x14, 0x9c, 0xe3 },
+               { 0x6e, 0x23, 0x31, 0xd6, 0x92, 0xad },
+               { 0x22, 0x4a },
+               { 0x4b, 0x9a, 0x26, 0xfa, 0x45, 0x9e, 0x3a, 0xcb,
+                 0xff, 0x36, 0xf4, 0x01, 0x5d, 0xe3, 0xbd, 0xc1 },
+               { 0x0d, 0xb1, 0x07, 0x1f, 0x87, 0x67, 0x56, 0x2c,
+                 0xa4, 0x3a, 0x0a, 0x64, 0xc4, 0x1e, 0x8d, 0x08 },
+               { 0x28, 0x31, 0xd7, 0xae, 0x90, 0x88, 0xe4, 0x92 },
+               { 0x9b, 0x2e, 0x16, 0x95, 0x11, 0x35, 0xd5, 0x23 },
+               { 0x6f, 0xc3, 0x0f, 0xee, 0x6d, 0x12, 0x35, 0x23 },
+               { 0x69, 0xb1, 0xca, 0xe7, 0xc7, 0x42, 0x9d, 0x97,
+                 0x5e, 0x24, 0x5c, 0xac, 0xb0, 0x5a, 0x51, 0x7c },
+               { 0x74, 0xf2, 0x4e, 0x8c, 0x26, 0xdf, 0x58, 0xe1,
+                 0xb3, 0x8d, 0x7d, 0xcd, 0x4f, 0x1b, 0x7f, 0xbd },
+               { 0x4c, 0x53, 0x9a, 0x26, 0xe1, 0xfa },
+               { 0x07, 0x86, 0x1e, 0x12, 0x69, 0x28 }
+       }, {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.12 Test Set 12 */
+               { 0x77, 0xb4, 0x58, 0x43, 0xc8, 0x8e, 0x58, 0xc1,
+                 0x0d, 0x20, 0x26, 0x84, 0x51, 0x5e, 0xd4, 0x30 },
+               { 0x4c, 0x47, 0xeb, 0x30, 0x76, 0xdc, 0x55, 0xfe,
+                 0x51, 0x06, 0xcb, 0x20, 0x34, 0xb8, 0xcd, 0x78 },
+               { 0xfe, 0x1a, 0x87, 0x31, 0x00, 0x5d },
+               { 0xad, 0x25 },
+               { 0xbf, 0x32, 0x86, 0xc7, 0xa5, 0x14, 0x09, 0xce,
+                 0x95, 0x72, 0x4d, 0x50, 0x3b, 0xfe, 0x6e, 0x70 },
+               { 0xd4, 0x83, 0xaf, 0xae, 0x56, 0x24, 0x09, 0xa3,
+                 0x26, 0xb5, 0xbb, 0x0b, 0x20, 0xc4, 0xd7, 0x62 },
+               { 0x08, 0x33, 0x2d, 0x7e, 0x9f, 0x48, 0x45, 0x70 },
+               { 0xed, 0x41, 0xb7, 0x34, 0x48, 0x9d, 0x52, 0x07 },
+               { 0xae, 0xfa, 0x35, 0x7b, 0xea, 0xc2, 0xa8, 0x7a },
+               { 0x90, 0x8c, 0x43, 0xf0, 0x56, 0x9c, 0xb8, 0xf7,
+                 0x4b, 0xc9, 0x71, 0xe7, 0x06, 0xc3, 0x6c, 0x5f },
+               { 0xc2, 0x51, 0xdf, 0x0d, 0x88, 0x8d, 0xd9, 0x32,
+                 0x9b, 0xcf, 0x46, 0x65, 0x5b, 0x22, 0x6e, 0x40 },
+               { 0x30, 0xff, 0x25, 0xcd, 0xad, 0xf6 },
+               { 0xe8, 0x4e, 0xd0, 0xd4, 0x67, 0x7e }
+       }, {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.13 Test Set 13 */
+               { 0x72, 0x9b, 0x17, 0x72, 0x92, 0x70, 0xdd, 0x87,
+                 0xcc, 0xdf, 0x1b, 0xfe, 0x29, 0xb4, 0xe9, 0xbb },
+               { 0x31, 0x1c, 0x4c, 0x92, 0x97, 0x44, 0xd6, 0x75,
+                 0xb7, 0x20, 0xf3, 0xb7, 0xe9, 0xb1, 0xcb, 0xd0 },
+               { 0xc8, 0x5c, 0x4c, 0xf6, 0x59, 0x16 },
+               { 0x5b, 0xb2 },
+               { 0xd0, 0x4c, 0x9c, 0x35, 0xbd, 0x22, 0x62, 0xfa,
+                 0x81, 0x0d, 0x29, 0x24, 0xd0, 0x36, 0xfd, 0x13 },
+               { 0x22, 0x8c, 0x2f, 0x2f, 0x06, 0xac, 0x32, 0x68,
+                 0xa9, 0xe6, 0x16, 0xee, 0x16, 0xdb, 0x4b, 0xa1 },
+               { 0xff, 0x79, 0x4f, 0xe2, 0xf8, 0x27, 0xeb, 0xf8 },
+               { 0x24, 0xfe, 0x4d, 0xc6, 0x1e, 0x87, 0x4b, 0x52 },
+               { 0x98, 0xdb, 0xbd, 0x09, 0x9b, 0x3b, 0x40, 0x8d },
+               { 0x44, 0xc0, 0xf2, 0x3c, 0x54, 0x93, 0xcf, 0xd2,
+                 0x41, 0xe4, 0x8f, 0x19, 0x7e, 0x1d, 0x10, 0x12 },
+               { 0x0c, 0x9f, 0xb8, 0x16, 0x13, 0x88, 0x4c, 0x25,
+                 0x35, 0xdd, 0x0e, 0xab, 0xf3, 0xb4, 0x40, 0xd8 },
+               { 0x53, 0x80, 0xd1, 0x58, 0xcf, 0xe3 },
+               { 0x87, 0xac, 0x3b, 0x55, 0x9f, 0xb6 }
+       }, {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.14 Test Set 14 */
+               { 0xd3, 0x2d, 0xd2, 0x3e, 0x89, 0xdc, 0x66, 0x23,
+                 0x54, 0xca, 0x12, 0xeb, 0x79, 0xdd, 0x32, 0xfa },
+               { 0xcf, 0x7d, 0x0a, 0xb1, 0xd9, 0x43, 0x06, 0x95,
+                 0x0b, 0xf1, 0x20, 0x18, 0xfb, 0xd4, 0x68, 0x87 },
+               { 0x48, 0x41, 0x07, 0xe5, 0x6a, 0x43 },
+               { 0xb5, 0xe6 },
+               { 0xfe, 0x75, 0x90, 0x5b, 0x9d, 0xa4, 0x7d, 0x35,
+                 0x62, 0x36, 0xd0, 0x31, 0x4e, 0x09, 0xc3, 0x2e },
+               { 0xd2, 0x2a, 0x4b, 0x41, 0x80, 0xa5, 0x32, 0x57,
+                 0x08, 0xa5, 0xff, 0x70, 0xd9, 0xf6, 0x7e, 0xc7 },
+               { 0xcf, 0x19, 0xd6, 0x2b, 0x6a, 0x80, 0x98, 0x66 },
+               { 0x5d, 0x26, 0x95, 0x37, 0xe4, 0x5e, 0x2c, 0xe6 },
+               { 0xaf, 0x4a, 0x41, 0x1e, 0x11, 0x39, 0xf2, 0xc2 },
+               { 0x5a, 0xf8, 0x6b, 0x80, 0xed, 0xb7, 0x0d, 0xf5,
+                 0x29, 0x2c, 0xc1, 0x12, 0x1c, 0xba, 0xd5, 0x0c },
+               { 0x7f, 0x4d, 0x6a, 0xe7, 0x44, 0x0e, 0x18, 0x78,
+                 0x9a, 0x8b, 0x75, 0xad, 0x3f, 0x42, 0xf0, 0x3a },
+               { 0x21, 0x7a, 0xf4, 0x92, 0x72, 0xad },
+               { 0x90, 0x0e, 0x10, 0x1c, 0x67, 0x7e }
+       }, {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.15 Test Set 15 */
+               { 0xaf, 0x7c, 0x65, 0xe1, 0x92, 0x72, 0x21, 0xde,
+                 0x59, 0x11, 0x87, 0xa2, 0xc5, 0x98, 0x7a, 0x53 },
+               { 0x1f, 0x0f, 0x85, 0x78, 0x46, 0x4f, 0xd5, 0x9b,
+                 0x64, 0xbe, 0xd2, 0xd0, 0x94, 0x36, 0xb5, 0x7a },
+               { 0x3d, 0x62, 0x7b, 0x01, 0x41, 0x8d },
+               { 0x84, 0xf6 },
+               { 0x0c, 0x7a, 0xcb, 0x8d, 0x95, 0xb7, 0xd4, 0xa3,
+                 0x1c, 0x5a, 0xca, 0x6d, 0x26, 0x34, 0x5a, 0x88 },
+               { 0xa4, 0xcf, 0x5c, 0x81, 0x55, 0xc0, 0x8a, 0x7e,
+                 0xff, 0x41, 0x8e, 0x54, 0x43, 0xb9, 0x8e, 0x55 },
+               { 0xc3, 0x7c, 0xae, 0x78, 0x05, 0x64, 0x20, 0x32 },
+               { 0x68, 0xcd, 0x09, 0xa4, 0x52, 0xd8, 0xdb, 0x7c },
+               { 0x7b, 0xff, 0xa5, 0xc2, 0xf4, 0x1f, 0xbc, 0x05 },
+               { 0x3f, 0x8c, 0x3f, 0x3c, 0xcf, 0x76, 0x25, 0xbf,
+                 0x77, 0xfc, 0x94, 0xbc, 0xfd, 0x22, 0xfd, 0x26 },
+               { 0xab, 0xcb, 0xae, 0x8f, 0xd4, 0x61, 0x15, 0xe9,
+                 0x96, 0x1a, 0x55, 0xd0, 0xda, 0x5f, 0x20, 0x78 },
+               { 0x83, 0x7f, 0xd7, 0xb7, 0x44, 0x19 },
+               { 0x56, 0xe9, 0x7a, 0x60, 0x90, 0xb1 }
+       }, {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.16 Test Set 16 */
+               { 0x5b, 0xd7, 0xec, 0xd3, 0xd3, 0x12, 0x7a, 0x41,
+                 0xd1, 0x25, 0x39, 0xbe, 0xd4, 0xe7, 0xcf, 0x71 },
+               { 0x59, 0xb7, 0x5f, 0x14, 0x25, 0x1c, 0x75, 0x03,
+                 0x1d, 0x0b, 0xcb, 0xac, 0x1c, 0x2c, 0x04, 0xc7 },
+               { 0xa2, 0x98, 0xae, 0x89, 0x29, 0xdc },
+               { 0xd0, 0x56 },
+               { 0xf9, 0x67, 0xf7, 0x60, 0x38, 0xb9, 0x20, 0xa9,
+                 0xcd, 0x25, 0xe1, 0x0c, 0x08, 0xb4, 0x99, 0x24 },
+               { 0x76, 0x08, 0x9d, 0x3c, 0x0f, 0xf3, 0xef, 0xdc,
+                 0x6e, 0x36, 0x72, 0x1d, 0x4f, 0xce, 0xb7, 0x47 },
+               { 0xc3, 0xf2, 0x5c, 0xd9, 0x43, 0x09, 0x10, 0x7e },
+               { 0xb0, 0xc8, 0xba, 0x34, 0x36, 0x65, 0xaf, 0xcc },
+               { 0x7e, 0x3f, 0x44, 0xc7, 0x59, 0x1f, 0x6f, 0x45 },
+               { 0xd4, 0x2b, 0x2d, 0x61, 0x5e, 0x49, 0xa0, 0x3a,
+                 0xc2, 0x75, 0xa5, 0xae, 0xf9, 0x7a, 0xf8, 0x92 },
+               { 0x0b, 0x3f, 0x8d, 0x02, 0x4f, 0xe6, 0xbf, 0xaf,
+                 0xaa, 0x98, 0x2b, 0x8f, 0x82, 0xe3, 0x19, 0xc2 },
+               { 0x5b, 0xe1, 0x14, 0x95, 0x52, 0x5d },
+               { 0x4d, 0x6a, 0x34, 0xa1, 0xe4, 0xeb }
+       }, {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.17 Test Set 17 */
+               { 0x6c, 0xd1, 0xc6, 0xce, 0xb1, 0xe0, 0x1e, 0x14,
+                 0xf1, 0xb8, 0x23, 0x16, 0xa9, 0x0b, 0x7f, 0x3d },
+               { 0xf6, 0x9b, 0x78, 0xf3, 0x00, 0xa0, 0x56, 0x8b,
+                 0xce, 0x9f, 0x0c, 0xb9, 0x3c, 0x4b, 0xe4, 0xc9 },
+               { 0xb4, 0xfc, 0xe5, 0xfe, 0xb0, 0x59 },
+               { 0xe4, 0xbb },
+               { 0x07, 0x8b, 0xfc, 0xa9, 0x56, 0x46, 0x59, 0xec,
+                 0xd8, 0x85, 0x1e, 0x84, 0xe6, 0xc5, 0x9b, 0x48 },
+               { 0xa2, 0x19, 0xdc, 0x37, 0xf1, 0xdc, 0x7d, 0x66,
+                 0x73, 0x8b, 0x58, 0x43, 0xc7, 0x99, 0xf2, 0x06 },
+               { 0x69, 0xa9, 0x08, 0x69, 0xc2, 0x68, 0xcb, 0x7b },
+               { 0x2e, 0x0f, 0xdc, 0xf9, 0xfd, 0x1c, 0xfa, 0x6a },
+               { 0x70, 0xf6, 0xbd, 0xb9, 0xad, 0x21, 0x52, 0x5f },
+               { 0x6e, 0xda, 0xf9, 0x9e, 0x5b, 0xd9, 0xf8, 0x5d,
+                 0x5f, 0x36, 0xd9, 0x1c, 0x12, 0x72, 0xfb, 0x4b },
+               { 0xd6, 0x1c, 0x85, 0x3c, 0x28, 0x0d, 0xd9, 0xc4,
+                 0x6f, 0x29, 0x7b, 0xae, 0xc3, 0x86, 0xde, 0x17 },
+               { 0x1c, 0x40, 0x8a, 0x85, 0x8b, 0x3e },
+               { 0xaa, 0x4a, 0xe5, 0x2d, 0xaa, 0x30 }
+       }, {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.18 Test Set 18 */
+               { 0xb7, 0x3a, 0x90, 0xcb, 0xcf, 0x3a, 0xfb, 0x62,
+                 0x2d, 0xba, 0x83, 0xc5, 0x8a, 0x84, 0x15, 0xdf },
+               { 0xb1, 0x20, 0xf1, 0xc1, 0xa0, 0x10, 0x2a, 0x2f,
+                 0x50, 0x7d, 0xd5, 0x43, 0xde, 0x68, 0x28, 0x1f },
+               { 0xf1, 0xe8, 0xa5, 0x23, 0xa3, 0x6d },
+               { 0x47, 0x1b },
+               { 0xb6, 0x72, 0x04, 0x7e, 0x00, 0x3b, 0xb9, 0x52,
+                 0xdc, 0xa6, 0xcb, 0x8a, 0xf0, 0xe5, 0xb7, 0x79 },
+               { 0xdf, 0x0c, 0x67, 0x86, 0x8f, 0xa2, 0x5f, 0x74,
+                 0x8b, 0x70, 0x44, 0xc6, 0xe7, 0xc2, 0x45, 0xb8 },
+               { 0xeb, 0xd7, 0x03, 0x41, 0xbc, 0xd4, 0x15, 0xb0 },
+               { 0x12, 0x35, 0x9f, 0x5d, 0x82, 0x22, 0x0c, 0x14 },
+               { 0x47, 0x9d, 0xd2, 0x5c, 0x20, 0x79, 0x2d, 0x63 },
+               { 0x66, 0x19, 0x5d, 0xbe, 0xd0, 0x31, 0x32, 0x74,
+                 0xc5, 0xca, 0x77, 0x66, 0x61, 0x5f, 0xa2, 0x5e },
+               { 0x66, 0xbe, 0xc7, 0x07, 0xeb, 0x2a, 0xfc, 0x47,
+                 0x6d, 0x74, 0x08, 0xa8, 0xf2, 0x92, 0x7b, 0x36 },
+               { 0xae, 0xfd, 0xaa, 0x5d, 0xdd, 0x99 },
+               { 0x12, 0xec, 0x2b, 0x87, 0xfb, 0xb1 }
+       }, {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.19 Test Set 19 */
+               { 0x51, 0x22, 0x25, 0x02, 0x14, 0xc3, 0x3e, 0x72,
+                 0x3a, 0x5d, 0xd5, 0x23, 0xfc, 0x14, 0x5f, 0xc0 },
+               { 0x81, 0xe9, 0x2b, 0x6c, 0x0e, 0xe0, 0xe1, 0x2e,
+                 0xbc, 0xeb, 0xa8, 0xd9, 0x2a, 0x99, 0xdf, 0xa5 },
+               { 0x16, 0xf3, 0xb3, 0xf7, 0x0f, 0xc2 },
+               { 0xc3, 0xab },
+               { 0xc9, 0xe8, 0x76, 0x32, 0x86, 0xb5, 0xb9, 0xff,
+                 0xbd, 0xf5, 0x6e, 0x12, 0x97, 0xd0, 0x88, 0x7b },
+               { 0x98, 0x1d, 0x46, 0x4c, 0x7c, 0x52, 0xeb, 0x6e,
+                 0x50, 0x36, 0x23, 0x49, 0x84, 0xad, 0x0b, 0xcf },
+               { 0x2a, 0x5c, 0x23, 0xd1, 0x5e, 0xe3, 0x51, 0xd5 },
+               { 0x62, 0xda, 0xe3, 0x85, 0x3f, 0x3a, 0xf9, 0xd2 },
+               { 0x28, 0xd7, 0xb0, 0xf2, 0xa2, 0xec, 0x3d, 0xe5 },
+               { 0x53, 0x49, 0xfb, 0xe0, 0x98, 0x64, 0x9f, 0x94,
+                 0x8f, 0x5d, 0x2e, 0x97, 0x3a, 0x81, 0xc0, 0x0f },
+               { 0x97, 0x44, 0x87, 0x1a, 0xd3, 0x2b, 0xf9, 0xbb,
+                 0xd1, 0xdd, 0x5c, 0xe5, 0x4e, 0x3e, 0x2e, 0x5a },
+               { 0xad, 0xa1, 0x5a, 0xeb, 0x7b, 0xb8 },
+               { 0xd4, 0x61, 0xbc, 0x15, 0x47, 0x5d }
+       }, {
+               /* 3GPP TS 35.208 v6.0.0 - 4.3.20 Test Set 20 */
+               { 0x90, 0xdc, 0xa4, 0xed, 0xa4, 0x5b, 0x53, 0xcf,
+                 0x0f, 0x12, 0xd7, 0xc9, 0xc3, 0xbc, 0x6a, 0x89 },
+               { 0x9f, 0xdd, 0xc7, 0x20, 0x92, 0xc6, 0xad, 0x03,
+                 0x6b, 0x6e, 0x46, 0x47, 0x89, 0x31, 0x5b, 0x78 },
+               { 0x20, 0xf8, 0x13, 0xbd, 0x41, 0x41 },
+               { 0x61, 0xdf },
+               { 0x3f, 0xfc, 0xfe, 0x5b, 0x7b, 0x11, 0x11, 0x58,
+                 0x99, 0x20, 0xd3, 0x52, 0x8e, 0x84, 0xe6, 0x55 },
+               { 0xcb, 0x9c, 0xcc, 0xc4, 0xb9, 0x25, 0x8e, 0x6d,
+                 0xca, 0x47, 0x60, 0x37, 0x9f, 0xb8, 0x25, 0x81 },
+               { 0x09, 0xdb, 0x94, 0xea, 0xb4, 0xf8, 0x14, 0x9e },
+               { 0xa2, 0x94, 0x68, 0xaa, 0x97, 0x75, 0xb5, 0x27 },
+               { 0xa9, 0x51, 0x00, 0xe2, 0x76, 0x09, 0x52, 0xcd },
+               { 0xb5, 0xf2, 0xda, 0x03, 0x88, 0x3b, 0x69, 0xf9,
+                 0x6b, 0xf5, 0x2e, 0x02, 0x9e, 0xd9, 0xac, 0x45 },
+               { 0xb4, 0x72, 0x13, 0x68, 0xbc, 0x16, 0xea, 0x67,
+                 0x87, 0x5c, 0x55, 0x98, 0x68, 0x8b, 0xb0, 0xef },
+               { 0x83, 0xcf, 0xd5, 0x4d, 0xb9, 0x13 },
+               { 0x4f, 0x20, 0x39, 0x39, 0x2d, 0xdc }
+       }
+};
+
+#define NUM_TESTS (sizeof(test_sets) / sizeof(test_sets[0]))
+
+
+int main(int argc, char *argv[])
+{
+       u8 buf[16], buf2[16], buf3[16], buf4[16], buf5[16], opc[16];
+       u8 auts[14], sqn[6], _rand[16];
+       int ret = 0, res, i;
+       const struct milenage_test_set *t;
+       size_t res_len;
+
+       wpa_debug_level = 0;
+
+       printf("Milenage test sets\n");
+       for (i = 0; i < NUM_TESTS; i++) {
+               t = &test_sets[i];
+               printf("Test Set %d\n", i + 1);
+
+               milenage_opc(t->op, t->k, opc);
+               if (memcmp(opc, t->opc, 16) != 0) {
+                       printf("- milenage_opc failed\n");
+                       ret++;
+               }
+
+               if (milenage_f1(opc, t->k, t->rand, t->sqn, t->amf, buf, buf2)
+                   ||  memcmp(buf, t->f1, 8) != 0) {
+                       printf("- milenage_f1 failed\n");
+                       ret++;
+               }
+               if (memcmp(buf2, t->f1star, 8) != 0) {
+                       printf("- milenage_f1* failed\n");
+                       ret++;
+               }
+
+               if (milenage_f2345(opc, t->k, t->rand, buf, buf2, buf3, buf4,
+                                  buf5) ||
+                   memcmp(buf, t->f2, 8) != 0) {
+                       printf("- milenage_f2 failed\n");
+                       ret++;
+               }
+               if (memcmp(buf2, t->f3, 16) != 0) {
+                       printf("- milenage_f3 failed\n");
+                       ret++;
+               }
+               if (memcmp(buf3, t->f4, 16) != 0) {
+                       printf("- milenage_f4 failed\n");
+                       ret++;
+               }
+               if (memcmp(buf4, t->f5, 6) != 0) {
+                       printf("- milenage_f5 failed\n");
+                       ret++;
+               }
+               if (memcmp(buf5, t->f5star, 6) != 0) {
+                       printf("- milenage_f5* failed\n");
+                       ret++;
+               }
+       }
+
+       printf("milenage_auts test:\n");
+       os_memcpy(auts, "\x4f\x20\x39\x39\x2d\xdd", 6);
+       os_memcpy(auts + 6, "\x4b\xb4\x31\x6e\xd4\xa1\x46\x88", 8);
+       res = milenage_auts(t->opc, t->k, t->rand, auts, buf);
+       printf("AUTS for test set %d: %d / SQN=%02x%02x%02x%02x%02x%02x\n",
+              i, res, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+       if (res)
+               ret++;
+
+       os_memset(_rand, 0xaa, sizeof(_rand));
+       os_memcpy(auts,
+                 "\x43\x68\x1a\xd3\xda\xf0\x06\xbc\xde\x40\x5a\x20\x72\x67",
+                 14);
+       res = milenage_auts(t->opc, t->k, _rand, auts, buf);
+       printf("AUTS from a test USIM: %d / SQN=%02x%02x%02x%02x%02x%02x\n",
+              res, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+       if (res)
+               ret++;
+
+       printf("milenage_generate test:\n");
+       os_memcpy(sqn, "\x00\x00\x00\x00\x40\x44", 6);
+       os_memcpy(_rand, "\x12\x69\xb8\x23\x41\x39\x35\x66\xfb\x99\x41\xe9\x84"
+                 "\x4f\xe6\x2f", 16);
+       res_len = 8;
+       milenage_generate(t->opc, t->amf, t->k, sqn, _rand, buf, buf2, buf3,
+                         buf4, &res_len);
+       wpa_hexdump(MSG_DEBUG, "SQN", sqn, 6);
+       wpa_hexdump(MSG_DEBUG, "RAND", _rand, 16);
+       wpa_hexdump(MSG_DEBUG, "AUTN", buf, 16);
+       wpa_hexdump(MSG_DEBUG, "IK", buf2, 16);
+       wpa_hexdump(MSG_DEBUG, "CK", buf3, 16);
+       wpa_hexdump(MSG_DEBUG, "RES", buf4, res_len);
+
+       printf("GSM-Milenage test sets\n");
+       for (i = 0; i < NUM_GSM_TESTS; i++) {
+               const struct gsm_milenage_test_set *g;
+               u8 sres[4], kc[8];
+               g = &gsm_test_sets[i];
+               printf("Test Set %d\n", i + 1);
+               gsm_milenage(g->opc, g->ki, g->rand, sres, kc);
+               if (memcmp(g->kc, kc, 8) != 0) {
+                       printf("- gsm_milenage Kc failed\n");
+                       ret++;
+               }
+#ifdef GSM_MILENAGE_ALT_SRES
+               if (memcmp(g->sres2, sres, 4) != 0) {
+                       printf("- gsm_milenage SRES#2 failed\n");
+                       ret++;
+               }
+#else /* GSM_MILENAGE_ALT_SRES */
+               if (memcmp(g->sres1, sres, 4) != 0) {
+                       printf("- gsm_milenage SRES#1 failed\n");
+                       ret++;
+               }
+#endif /* GSM_MILENAGE_ALT_SRES */
+       }
+
+       if (ret)
+               printf("Something failed\n");
+       else
+               printf("OK\n");
+
+       return ret;
+}
diff --git a/tests/test-ms_funcs.c b/tests/test-ms_funcs.c
new file mode 100644 (file)
index 0000000..ae36171
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+#include "crypto/ms_funcs.c"
+
+
+int main(int argc, char *argv[])
+{
+       /* Test vector from RFC2759 example */
+       char *username = "User";
+       char *password = "clientPass";
+       u8 auth_challenge[] = {
+               0x5B, 0x5D, 0x7C, 0x7D, 0x7B, 0x3F, 0x2F, 0x3E,
+               0x3C, 0x2C, 0x60, 0x21, 0x32, 0x26, 0x26, 0x28
+       };
+       u8 peer_challenge[] = {
+               0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A,
+               0x28, 0x29, 0x5F, 0x2B, 0x3A, 0x33, 0x7C, 0x7E
+       };
+       u8 challenge[] = { 0xD0, 0x2E, 0x43, 0x86, 0xBC, 0xE9, 0x12, 0x26 };
+       u8 password_hash[] = {
+               0x44, 0xEB, 0xBA, 0x8D, 0x53, 0x12, 0xB8, 0xD6,
+               0x11, 0x47, 0x44, 0x11, 0xF5, 0x69, 0x89, 0xAE
+       };
+       u8 nt_response[] = {
+               0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E,
+               0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54,
+               0x42, 0x33, 0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF
+       };
+       u8 password_hash_hash[] = {
+               0x41, 0xC0, 0x0C, 0x58, 0x4B, 0xD2, 0xD9, 0x1C,
+               0x40, 0x17, 0xA2, 0xA1, 0x2F, 0xA5, 0x9F, 0x3F
+       };
+       u8 authenticator_response[] = {
+               0x40, 0x7A, 0x55, 0x89, 0x11, 0x5F, 0xD0, 0xD6,
+               0x20, 0x9F, 0x51, 0x0F, 0xE9, 0xC0, 0x45, 0x66,
+               0x93, 0x2C, 0xDA, 0x56
+       };
+       u8 master_key[] = {
+               0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C,
+               0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31
+       };
+       u8 send_start_key[] = {
+               0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B,
+               0xA1, 0x18, 0xCB, 0x15, 0x3F, 0x56, 0xDC, 0xCB
+       };
+       u8 buf[32];
+
+       int errors = 0;
+
+       printf("Testing ms_funcs.c\n");
+
+       if (challenge_hash(peer_challenge, auth_challenge,
+                          (u8 *) username, strlen(username),
+                          buf) ||
+           memcmp(challenge, buf, sizeof(challenge)) != 0) {
+               printf("challenge_hash failed\n");
+               errors++;
+       }
+
+       if (nt_password_hash((u8 *) password, strlen(password), buf) ||
+           memcmp(password_hash, buf, sizeof(password_hash)) != 0) {
+               printf("nt_password_hash failed\n");
+               errors++;
+       }
+
+       if (generate_nt_response(auth_challenge, peer_challenge,
+                                (u8 *) username, strlen(username),
+                                (u8 *) password, strlen(password),
+                                buf) ||
+           memcmp(nt_response, buf, sizeof(nt_response)) != 0) {
+               printf("generate_nt_response failed\n");
+               errors++;
+       }
+
+       if (hash_nt_password_hash(password_hash, buf) ||
+           memcmp(password_hash_hash, buf, sizeof(password_hash_hash)) != 0) {
+               printf("hash_nt_password_hash failed\n");
+               errors++;
+       }
+
+       if (generate_authenticator_response((u8 *) password, strlen(password),
+                                           peer_challenge, auth_challenge,
+                                           (u8 *) username, strlen(username),
+                                           nt_response, buf) ||
+           memcmp(authenticator_response, buf, sizeof(authenticator_response))
+           != 0) {
+               printf("generate_authenticator_response failed\n");
+               errors++;
+       }
+
+       if (get_master_key(password_hash_hash, nt_response, buf) ||
+           memcmp(master_key, buf, sizeof(master_key)) != 0) {
+               printf("get_master_key failed\n");
+               errors++;
+       }
+
+       if (get_asymetric_start_key(master_key, buf, sizeof(send_start_key),
+                                   1, 1) ||
+           memcmp(send_start_key, buf, sizeof(send_start_key)) != 0) {
+               printf("get_asymetric_start_key failed\n");
+               errors++;
+       }
+
+       if (errors)
+               printf("FAILED! %d errors\n", errors);
+
+       return errors;
+}
diff --git a/tests/test-rc4.c b/tests/test-rc4.c
new file mode 100644 (file)
index 0000000..cbe2aeb
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/crypto.h"
+
+
+struct rc4_test_vector {
+       size_t key_len;
+       const u8 *key;
+       const u8 *stream0;
+       const u8 *stream240;
+       const u8 *stream496;
+       const u8 *stream752;
+       const u8 *stream1008;
+       const u8 *stream1520;
+       const u8 *stream2032;
+       const u8 *stream3056;
+       const u8 *stream4080;
+};
+
+/* RFC 6229 test vectors */
+static const struct rc4_test_vector tests[] = {
+       {
+               5, (u8 *) "\x01\x02\x03\x04\x05",
+               (u8 *) "\xb2\x39\x63\x05\xf0\x3d\xc0\x27\xcc\xc3\x52\x4a\x0a\x11\x18\xa8\x69\x82\x94\x4f\x18\xfc\x82\xd5\x89\xc4\x03\xa4\x7a\x0d\x09\x19",
+               (u8 *) "\x28\xcb\x11\x32\xc9\x6c\xe2\x86\x42\x1d\xca\xad\xb8\xb6\x9e\xae\x1c\xfc\xf6\x2b\x03\xed\xdb\x64\x1d\x77\xdf\xcf\x7f\x8d\x8c\x93",
+               (u8 *) "\x42\xb7\xd0\xcd\xd9\x18\xa8\xa3\x3d\xd5\x17\x81\xc8\x1f\x40\x41\x64\x59\x84\x44\x32\xa7\xda\x92\x3c\xfb\x3e\xb4\x98\x06\x61\xf6",
+               (u8 *) "\xec\x10\x32\x7b\xde\x2b\xee\xfd\x18\xf9\x27\x76\x80\x45\x7e\x22\xeb\x62\x63\x8d\x4f\x0b\xa1\xfe\x9f\xca\x20\xe0\x5b\xf8\xff\x2b",
+               (u8 *) "\x45\x12\x90\x48\xe6\xa0\xed\x0b\x56\xb4\x90\x33\x8f\x07\x8d\xa5\x30\xab\xbc\xc7\xc2\x0b\x01\x60\x9f\x23\xee\x2d\x5f\x6b\xb7\xdf",
+               (u8 *) "\x32\x94\xf7\x44\xd8\xf9\x79\x05\x07\xe7\x0f\x62\xe5\xbb\xce\xea\xd8\x72\x9d\xb4\x18\x82\x25\x9b\xee\x4f\x82\x53\x25\xf5\xa1\x30",
+               (u8 *) "\x1e\xb1\x4a\x0c\x13\xb3\xbf\x47\xfa\x2a\x0b\xa9\x3a\xd4\x5b\x8b\xcc\x58\x2f\x8b\xa9\xf2\x65\xe2\xb1\xbe\x91\x12\xe9\x75\xd2\xd7",
+               (u8 *) "\xf2\xe3\x0f\x9b\xd1\x02\xec\xbf\x75\xaa\xad\xe9\xbc\x35\xc4\x3c\xec\x0e\x11\xc4\x79\xdc\x32\x9d\xc8\xda\x79\x68\xfe\x96\x56\x81",
+               (u8 *) "\x06\x83\x26\xa2\x11\x84\x16\xd2\x1f\x9d\x04\xb2\xcd\x1c\xa0\x50\xff\x25\xb5\x89\x95\x99\x67\x07\xe5\x1f\xbd\xf0\x8b\x34\xd8\x75"
+       },
+       {
+               7, (u8 *) "\x01\x02\x03\x04\x05\x06\x07",
+               (u8 *) "\x29\x3f\x02\xd4\x7f\x37\xc9\xb6\x33\xf2\xaf\x52\x85\xfe\xb4\x6b\xe6\x20\xf1\x39\x0d\x19\xbd\x84\xe2\xe0\xfd\x75\x20\x31\xaf\xc1",
+               (u8 *) "\x91\x4f\x02\x53\x1c\x92\x18\x81\x0d\xf6\x0f\x67\xe3\x38\x15\x4c\xd0\xfd\xb5\x83\x07\x3c\xe8\x5a\xb8\x39\x17\x74\x0e\xc0\x11\xd5",
+               (u8 *) "\x75\xf8\x14\x11\xe8\x71\xcf\xfa\x70\xb9\x0c\x74\xc5\x92\xe4\x54\x0b\xb8\x72\x02\x93\x8d\xad\x60\x9e\x87\xa5\xa1\xb0\x79\xe5\xe4",
+               (u8 *) "\xc2\x91\x12\x46\xb6\x12\xe7\xe7\xb9\x03\xdf\xed\xa1\xda\xd8\x66\x32\x82\x8f\x91\x50\x2b\x62\x91\x36\x8d\xe8\x08\x1d\xe3\x6f\xc2",
+               (u8 *) "\xf3\xb9\xa7\xe3\xb2\x97\xbf\x9a\xd8\x04\x51\x2f\x90\x63\xef\xf1\x8e\xcb\x67\xa9\xba\x1f\x55\xa5\xa0\x67\xe2\xb0\x26\xa3\x67\x6f",
+               (u8 *) "\xd2\xaa\x90\x2b\xd4\x2d\x0d\x7c\xfd\x34\x0c\xd4\x58\x10\x52\x9f\x78\xb2\x72\xc9\x6e\x42\xea\xb4\xc6\x0b\xd9\x14\xe3\x9d\x06\xe3",
+               (u8 *) "\xf4\x33\x2f\xd3\x1a\x07\x93\x96\xee\x3c\xee\x3f\x2a\x4f\xf0\x49\x05\x45\x97\x81\xd4\x1f\xda\x7f\x30\xc1\xbe\x7e\x12\x46\xc6\x23",
+               (u8 *) "\xad\xfd\x38\x68\xb8\xe5\x14\x85\xd5\xe6\x10\x01\x7e\x3d\xd6\x09\xad\x26\x58\x1c\x0c\x5b\xe4\x5f\x4c\xea\x01\xdb\x2f\x38\x05\xd5",
+               (u8 *) "\xf3\x17\x2c\xef\xfc\x3b\x3d\x99\x7c\x85\xcc\xd5\xaf\x1a\x95\x0c\xe7\x4b\x0b\x97\x31\x22\x7f\xd3\x7c\x0e\xc0\x8a\x47\xdd\xd8\xb8"
+       },
+       {
+               8, (u8 *) "\x01\x02\x03\x04\x05\x06\x07\x08",
+               (u8 *) "\x97\xab\x8a\x1b\xf0\xaf\xb9\x61\x32\xf2\xf6\x72\x58\xda\x15\xa8\x82\x63\xef\xdb\x45\xc4\xa1\x86\x84\xef\x87\xe6\xb1\x9e\x5b\x09",
+               (u8 *) "\x96\x36\xeb\xc9\x84\x19\x26\xf4\xf7\xd1\xf3\x62\xbd\xdf\x6e\x18\xd0\xa9\x90\xff\x2c\x05\xfe\xf5\xb9\x03\x73\xc9\xff\x4b\x87\x0a",
+               (u8 *) "\x73\x23\x9f\x1d\xb7\xf4\x1d\x80\xb6\x43\xc0\xc5\x25\x18\xec\x63\x16\x3b\x31\x99\x23\xa6\xbd\xb4\x52\x7c\x62\x61\x26\x70\x3c\x0f",
+               (u8 *) "\x49\xd6\xc8\xaf\x0f\x97\x14\x4a\x87\xdf\x21\xd9\x14\x72\xf9\x66\x44\x17\x3a\x10\x3b\x66\x16\xc5\xd5\xad\x1c\xee\x40\xc8\x63\xd0",
+               (u8 *) "\x27\x3c\x9c\x4b\x27\xf3\x22\xe4\xe7\x16\xef\x53\xa4\x7d\xe7\xa4\xc6\xd0\xe7\xb2\x26\x25\x9f\xa9\x02\x34\x90\xb2\x61\x67\xad\x1d",
+               (u8 *) "\x1f\xe8\x98\x67\x13\xf0\x7c\x3d\x9a\xe1\xc1\x63\xff\x8c\xf9\xd3\x83\x69\xe1\xa9\x65\x61\x0b\xe8\x87\xfb\xd0\xc7\x91\x62\xaa\xfb",
+               (u8 *) "\x0a\x01\x27\xab\xb4\x44\x84\xb9\xfb\xef\x5a\xbc\xae\x1b\x57\x9f\xc2\xcd\xad\xc6\x40\x2e\x8e\xe8\x66\xe1\xf3\x7b\xdb\x47\xe4\x2c",
+               (u8 *) "\x26\xb5\x1e\xa3\x7d\xf8\xe1\xd6\xf7\x6f\xc3\xb6\x6a\x74\x29\xb3\xbc\x76\x83\x20\x5d\x4f\x44\x3d\xc1\xf2\x9d\xda\x33\x15\xc8\x7b",
+               (u8 *) "\xd5\xfa\x5a\x34\x69\xd2\x9a\xaa\xf8\x3d\x23\x58\x9d\xb8\xc8\x5b\x3f\xb4\x6e\x2c\x8f\x0f\x06\x8e\xdc\xe8\xcd\xcd\x7d\xfc\x58\x62"
+       },
+       {
+               10, (u8 *) "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a",
+               (u8 *) "\xed\xe3\xb0\x46\x43\xe5\x86\xcc\x90\x7d\xc2\x18\x51\x70\x99\x02\x03\x51\x6b\xa7\x8f\x41\x3b\xeb\x22\x3a\xa5\xd4\xd2\xdf\x67\x11",
+               (u8 *) "\x3c\xfd\x6c\xb5\x8e\xe0\xfd\xde\x64\x01\x76\xad\x00\x00\x04\x4d\x48\x53\x2b\x21\xfb\x60\x79\xc9\x11\x4c\x0f\xfd\x9c\x04\xa1\xad",
+               (u8 *) "\x3e\x8c\xea\x98\x01\x71\x09\x97\x90\x84\xb1\xef\x92\xf9\x9d\x86\xe2\x0f\xb4\x9b\xdb\x33\x7e\xe4\x8b\x8d\x8d\xc0\xf4\xaf\xef\xfe",
+               (u8 *) "\x5c\x25\x21\xea\xcd\x79\x66\xf1\x5e\x05\x65\x44\xbe\xa0\xd3\x15\xe0\x67\xa7\x03\x19\x31\xa2\x46\xa6\xc3\x87\x5d\x2f\x67\x8a\xcb",
+               (u8 *) "\xa6\x4f\x70\xaf\x88\xae\x56\xb6\xf8\x75\x81\xc0\xe2\x3e\x6b\x08\xf4\x49\x03\x1d\xe3\x12\x81\x4e\xc6\xf3\x19\x29\x1f\x4a\x05\x16",
+               (u8 *) "\xbd\xae\x85\x92\x4b\x3c\xb1\xd0\xa2\xe3\x3a\x30\xc6\xd7\x95\x99\x8a\x0f\xed\xdb\xac\x86\x5a\x09\xbc\xd1\x27\xfb\x56\x2e\xd6\x0a",
+               (u8 *) "\xb5\x5a\x0a\x5b\x51\xa1\x2a\x8b\xe3\x48\x99\xc3\xe0\x47\x51\x1a\xd9\xa0\x9c\xea\x3c\xe7\x5f\xe3\x96\x98\x07\x03\x17\xa7\x13\x39",
+               (u8 *) "\x55\x22\x25\xed\x11\x77\xf4\x45\x84\xac\x8c\xfa\x6c\x4e\xb5\xfc\x7e\x82\xcb\xab\xfc\x95\x38\x1b\x08\x09\x98\x44\x21\x29\xc2\xf8",
+               (u8 *) "\x1f\x13\x5e\xd1\x4c\xe6\x0a\x91\x36\x9d\x23\x22\xbe\xf2\x5e\x3c\x08\xb6\xbe\x45\x12\x4a\x43\xe2\xeb\x77\x95\x3f\x84\xdc\x85\x53"
+       },
+       {
+               16, (u8 *) "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10",
+               (u8 *) "\x9a\xc7\xcc\x9a\x60\x9d\x1e\xf7\xb2\x93\x28\x99\xcd\xe4\x1b\x97\x52\x48\xc4\x95\x90\x14\x12\x6a\x6e\x8a\x84\xf1\x1d\x1a\x9e\x1c",
+               (u8 *) "\x06\x59\x02\xe4\xb6\x20\xf6\xcc\x36\xc8\x58\x9f\x66\x43\x2f\x2b\xd3\x9d\x56\x6b\xc6\xbc\xe3\x01\x07\x68\x15\x15\x49\xf3\x87\x3f",
+               (u8 *) "\xb6\xd1\xe6\xc4\xa5\xe4\x77\x1c\xad\x79\x53\x8d\xf2\x95\xfb\x11\xc6\x8c\x1d\x5c\x55\x9a\x97\x41\x23\xdf\x1d\xbc\x52\xa4\x3b\x89",
+               (u8 *) "\xc5\xec\xf8\x8d\xe8\x97\xfd\x57\xfe\xd3\x01\x70\x1b\x82\xa2\x59\xec\xcb\xe1\x3d\xe1\xfc\xc9\x1c\x11\xa0\xb2\x6c\x0b\xc8\xfa\x4d",
+               (u8 *) "\xe7\xa7\x25\x74\xf8\x78\x2a\xe2\x6a\xab\xcf\x9e\xbc\xd6\x60\x65\xbd\xf0\x32\x4e\x60\x83\xdc\xc6\xd3\xce\xdd\x3c\xa8\xc5\x3c\x16",
+               (u8 *) "\xb4\x01\x10\xc4\x19\x0b\x56\x22\xa9\x61\x16\xb0\x01\x7e\xd2\x97\xff\xa0\xb5\x14\x64\x7e\xc0\x4f\x63\x06\xb8\x92\xae\x66\x11\x81",
+               (u8 *) "\xd0\x3d\x1b\xc0\x3c\xd3\x3d\x70\xdf\xf9\xfa\x5d\x71\x96\x3e\xbd\x8a\x44\x12\x64\x11\xea\xa7\x8b\xd5\x1e\x8d\x87\xa8\x87\x9b\xf5",
+               (u8 *) "\xfa\xbe\xb7\x60\x28\xad\xe2\xd0\xe4\x87\x22\xe4\x6c\x46\x15\xa3\xc0\x5d\x88\xab\xd5\x03\x57\xf9\x35\xa6\x3c\x59\xee\x53\x76\x23",
+               (u8 *) "\xff\x38\x26\x5c\x16\x42\xc1\xab\xe8\xd3\xc2\xfe\x5e\x57\x2b\xf8\xa3\x6a\x4c\x30\x1a\xe8\xac\x13\x61\x0c\xcb\xc1\x22\x56\xca\xcc"
+       },
+       {
+               24, (u8 *) "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18",
+               (u8 *) "\x05\x95\xe5\x7f\xe5\xf0\xbb\x3c\x70\x6e\xda\xc8\xa4\xb2\xdb\x11\xdf\xde\x31\x34\x4a\x1a\xf7\x69\xc7\x4f\x07\x0a\xee\x9e\x23\x26",
+               (u8 *) "\xb0\x6b\x9b\x1e\x19\x5d\x13\xd8\xf4\xa7\x99\x5c\x45\x53\xac\x05\x6b\xd2\x37\x8e\xc3\x41\xc9\xa4\x2f\x37\xba\x79\xf8\x8a\x32\xff",
+               (u8 *) "\xe7\x0b\xce\x1d\xf7\x64\x5a\xdb\x5d\x2c\x41\x30\x21\x5c\x35\x22\x9a\x57\x30\xc7\xfc\xb4\xc9\xaf\x51\xff\xda\x89\xc7\xf1\xad\x22",
+               (u8 *) "\x04\x85\x05\x5f\xd4\xf6\xf0\xd9\x63\xef\x5a\xb9\xa5\x47\x69\x82\x59\x1f\xc6\x6b\xcd\xa1\x0e\x45\x2b\x03\xd4\x55\x1f\x6b\x62\xac",
+               (u8 *) "\x27\x53\xcc\x83\x98\x8a\xfa\x3e\x16\x88\xa1\xd3\xb4\x2c\x9a\x02\x93\x61\x0d\x52\x3d\x1d\x3f\x00\x62\xb3\xc2\xa3\xbb\xc7\xc7\xf0",
+               (u8 *) "\x96\xc2\x48\x61\x0a\xad\xed\xfe\xaf\x89\x78\xc0\x3d\xe8\x20\x5a\x0e\x31\x7b\x3d\x1c\x73\xb9\xe9\xa4\x68\x8f\x29\x6d\x13\x3a\x19",
+               (u8 *) "\xbd\xf0\xe6\xc3\xcc\xa5\xb5\xb9\xd5\x33\xb6\x9c\x56\xad\xa1\x20\x88\xa2\x18\xb6\xe2\xec\xe1\xe6\x24\x6d\x44\xc7\x59\xd1\x9b\x10",
+               (u8 *) "\x68\x66\x39\x7e\x95\xc1\x40\x53\x4f\x94\x26\x34\x21\x00\x6e\x40\x32\xcb\x0a\x1e\x95\x42\xc6\xb3\xb8\xb3\x98\xab\xc3\xb0\xf1\xd5",
+               (u8 *) "\x29\xa0\xb8\xae\xd5\x4a\x13\x23\x24\xc6\x2e\x42\x3f\x54\xb4\xc8\x3c\xb0\xf3\xb5\x02\x0a\x98\xb8\x2a\xf9\xfe\x15\x44\x84\xa1\x68"
+       },
+       {
+               32, (u8 *) "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20",
+               (u8 *) "\xea\xa6\xbd\x25\x88\x0b\xf9\x3d\x3f\x5d\x1e\x4c\xa2\x61\x1d\x91\xcf\xa4\x5c\x9f\x7e\x71\x4b\x54\xbd\xfa\x80\x02\x7c\xb1\x43\x80",
+               (u8 *) "\x11\x4a\xe3\x44\xde\xd7\x1b\x35\xf2\xe6\x0f\xeb\xad\x72\x7f\xd8\x02\xe1\xe7\x05\x6b\x0f\x62\x39\x00\x49\x64\x22\x94\x3e\x97\xb6",
+               (u8 *) "\x91\xcb\x93\xc7\x87\x96\x4e\x10\xd9\x52\x7d\x99\x9c\x6f\x93\x6b\x49\xb1\x8b\x42\xf8\xe8\x36\x7c\xbe\xb5\xef\x10\x4b\xa1\xc7\xcd",
+               (u8 *) "\x87\x08\x4b\x3b\xa7\x00\xba\xde\x95\x56\x10\x67\x27\x45\xb3\x74\xe7\xa7\xb9\xe9\xec\x54\x0d\x5f\xf4\x3b\xdb\x12\x79\x2d\x1b\x35",
+               (u8 *) "\xc7\x99\xb5\x96\x73\x8f\x6b\x01\x8c\x76\xc7\x4b\x17\x59\xbd\x90\x7f\xec\x5b\xfd\x9f\x9b\x89\xce\x65\x48\x30\x90\x92\xd7\xe9\x58",
+               (u8 *) "\x40\xf2\x50\xb2\x6d\x1f\x09\x6a\x4a\xfd\x4c\x34\x0a\x58\x88\x15\x3e\x34\x13\x5c\x79\xdb\x01\x02\x00\x76\x76\x51\xcf\x26\x30\x73",
+               (u8 *) "\xf6\x56\xab\xcc\xf8\x8d\xd8\x27\x02\x7b\x2c\xe9\x17\xd4\x64\xec\x18\xb6\x25\x03\xbf\xbc\x07\x7f\xba\xbb\x98\xf2\x0d\x98\xab\x34",
+               (u8 *) "\x8a\xed\x95\xee\x5b\x0d\xcb\xfb\xef\x4e\xb2\x1d\x3a\x3f\x52\xf9\x62\x5a\x1a\xb0\x0e\xe3\x9a\x53\x27\x34\x6b\xdd\xb0\x1a\x9c\x18",
+               (u8 *) "\xa1\x3a\x7c\x79\xc7\xe1\x19\xb5\xab\x02\x96\xab\x28\xc3\x00\xb9\xf3\xe4\xc0\xa2\xe0\x2d\x1d\x01\xf7\xf0\xa7\x46\x18\xaf\x2b\x48"
+       },
+       {
+               5, (u8 *) "\x83\x32\x22\x77\x2a",
+               (u8 *) "\x80\xad\x97\xbd\xc9\x73\xdf\x8a\x2e\x87\x9e\x92\xa4\x97\xef\xda\x20\xf0\x60\xc2\xf2\xe5\x12\x65\x01\xd3\xd4\xfe\xa1\x0d\x5f\xc0",
+               (u8 *) "\xfa\xa1\x48\xe9\x90\x46\x18\x1f\xec\x6b\x20\x85\xf3\xb2\x0e\xd9\xf0\xda\xf5\xba\xb3\xd5\x96\x83\x98\x57\x84\x6f\x73\xfb\xfe\x5a",
+               (u8 *) "\x1c\x7e\x2f\xc4\x63\x92\x32\xfe\x29\x75\x84\xb2\x96\x99\x6b\xc8\x3d\xb9\xb2\x49\x40\x6c\xc8\xed\xff\xac\x55\xcc\xd3\x22\xba\x12",
+               (u8 *) "\xe4\xf9\xf7\xe0\x06\x61\x54\xbb\xd1\x25\xb7\x45\x56\x9b\xc8\x97\x75\xd5\xef\x26\x2b\x44\xc4\x1a\x9c\xf6\x3a\xe1\x45\x68\xe1\xb9",
+               (u8 *) "\x6d\xa4\x53\xdb\xf8\x1e\x82\x33\x4a\x3d\x88\x66\xcb\x50\xa1\xe3\x78\x28\xd0\x74\x11\x9c\xab\x5c\x22\xb2\x94\xd7\xa9\xbf\xa0\xbb",
+               (u8 *) "\xad\xb8\x9c\xea\x9a\x15\xfb\xe6\x17\x29\x5b\xd0\x4b\x8c\xa0\x5c\x62\x51\xd8\x7f\xd4\xaa\xae\x9a\x7e\x4a\xd5\xc2\x17\xd3\xf3\x00",
+               (u8 *) "\xe7\x11\x9b\xd6\xdd\x9b\x22\xaf\xe8\xf8\x95\x85\x43\x28\x81\xe2\x78\x5b\x60\xfd\x7e\xc4\xe9\xfc\xb6\x54\x5f\x35\x0d\x66\x0f\xab",
+               (u8 *) "\xaf\xec\xc0\x37\xfd\xb7\xb0\x83\x8e\xb3\xd7\x0b\xcd\x26\x83\x82\xdb\xc1\xa7\xb4\x9d\x57\x35\x8c\xc9\xfa\x6d\x61\xd7\x3b\x7c\xf0",
+               (u8 *) "\x63\x49\xd1\x26\xa3\x7a\xfc\xba\x89\x79\x4f\x98\x04\x91\x4f\xdc\xbf\x42\xc3\x01\x8c\x2f\x7c\x66\xbf\xde\x52\x49\x75\x76\x81\x15"
+       },
+       {
+               7, (u8 *) "\x19\x10\x83\x32\x22\x77\x2a",
+               (u8 *) "\xbc\x92\x22\xdb\xd3\x27\x4d\x8f\xc6\x6d\x14\xcc\xbd\xa6\x69\x0b\x7a\xe6\x27\x41\x0c\x9a\x2b\xe6\x93\xdf\x5b\xb7\x48\x5a\x63\xe3",
+               (u8 *) "\x3f\x09\x31\xaa\x03\xde\xfb\x30\x0f\x06\x01\x03\x82\x6f\x2a\x64\xbe\xaa\x9e\xc8\xd5\x9b\xb6\x81\x29\xf3\x02\x7c\x96\x36\x11\x81",
+               (u8 *) "\x74\xe0\x4d\xb4\x6d\x28\x64\x8d\x7d\xee\x8a\x00\x64\xb0\x6c\xfe\x9b\x5e\x81\xc6\x2f\xe0\x23\xc5\x5b\xe4\x2f\x87\xbb\xf9\x32\xb8",
+               (u8 *) "\xce\x17\x8f\xc1\x82\x6e\xfe\xcb\xc1\x82\xf5\x79\x99\xa4\x61\x40\x8b\xdf\x55\xcd\x55\x06\x1c\x06\xdb\xa6\xbe\x11\xde\x4a\x57\x8a",
+               (u8 *) "\x62\x6f\x5f\x4d\xce\x65\x25\x01\xf3\x08\x7d\x39\xc9\x2c\xc3\x49\x42\xda\xac\x6a\x8f\x9a\xb9\xa7\xfd\x13\x7c\x60\x37\x82\x56\x82",
+               (u8 *) "\xcc\x03\xfd\xb7\x91\x92\xa2\x07\x31\x2f\x53\xf5\xd4\xdc\x33\xd9\xf7\x0f\x14\x12\x2a\x1c\x98\xa3\x15\x5d\x28\xb8\xa0\xa8\xa4\x1d",
+               (u8 *) "\x2a\x3a\x30\x7a\xb2\x70\x8a\x9c\x00\xfe\x0b\x42\xf9\xc2\xd6\xa1\x86\x26\x17\x62\x7d\x22\x61\xea\xb0\xb1\x24\x65\x97\xca\x0a\xe9",
+               (u8 *) "\x55\xf8\x77\xce\x4f\x2e\x1d\xdb\xbf\x8e\x13\xe2\xcd\xe0\xfd\xc8\x1b\x15\x56\xcb\x93\x5f\x17\x33\x37\x70\x5f\xbb\x5d\x50\x1f\xc1",
+               (u8 *) "\xec\xd0\xe9\x66\x02\xbe\x7f\x8d\x50\x92\x81\x6c\xcc\xf2\xc2\xe9\x02\x78\x81\xfa\xb4\x99\x3a\x1c\x26\x20\x24\xa9\x4f\xff\x3f\x61"
+       },
+       {
+               8, (u8 *) "\x64\x19\x10\x83\x32\x22\x77\x2a",
+               (u8 *) "\xbb\xf6\x09\xde\x94\x13\x17\x2d\x07\x66\x0c\xb6\x80\x71\x69\x26\x46\x10\x1a\x6d\xab\x43\x11\x5d\x6c\x52\x2b\x4f\xe9\x36\x04\xa9",
+               (u8 *) "\xcb\xe1\xff\xf2\x1c\x96\xf3\xee\xf6\x1e\x8f\xe0\x54\x2c\xbd\xf0\x34\x79\x38\xbf\xfa\x40\x09\xc5\x12\xcf\xb4\x03\x4b\x0d\xd1\xa7",
+               (u8 *) "\x78\x67\xa7\x86\xd0\x0a\x71\x47\x90\x4d\x76\xdd\xf1\xe5\x20\xe3\x8d\x3e\x9e\x1c\xae\xfc\xcc\xb3\xfb\xf8\xd1\x8f\x64\x12\x0b\x32",
+               (u8 *) "\x94\x23\x37\xf8\xfd\x76\xf0\xfa\xe8\xc5\x2d\x79\x54\x81\x06\x72\xb8\x54\x8c\x10\xf5\x16\x67\xf6\xe6\x0e\x18\x2f\xa1\x9b\x30\xf7",
+               (u8 *) "\x02\x11\xc7\xc6\x19\x0c\x9e\xfd\x12\x37\xc3\x4c\x8f\x2e\x06\xc4\xbd\xa6\x4f\x65\x27\x6d\x2a\xac\xb8\xf9\x02\x12\x20\x3a\x80\x8e",
+               (u8 *) "\xbd\x38\x20\xf7\x32\xff\xb5\x3e\xc1\x93\xe7\x9d\x33\xe2\x7c\x73\xd0\x16\x86\x16\x86\x19\x07\xd4\x82\xe3\x6c\xda\xc8\xcf\x57\x49",
+               (u8 *) "\x97\xb0\xf0\xf2\x24\xb2\xd2\x31\x71\x14\x80\x8f\xb0\x3a\xf7\xa0\xe5\x96\x16\xe4\x69\x78\x79\x39\xa0\x63\xce\xea\x9a\xf9\x56\xd1",
+               (u8 *) "\xc4\x7e\x0d\xc1\x66\x09\x19\xc1\x11\x01\x20\x8f\x9e\x69\xaa\x1f\x5a\xe4\xf1\x28\x96\xb8\x37\x9a\x2a\xad\x89\xb5\xb5\x53\xd6\xb0",
+               (u8 *) "\x6b\x6b\x09\x8d\x0c\x29\x3b\xc2\x99\x3d\x80\xbf\x05\x18\xb6\xd9\x81\x70\xcc\x3c\xcd\x92\xa6\x98\x62\x1b\x93\x9d\xd3\x8f\xe7\xb9"
+       },
+       {
+               10, (u8 *) "\x8b\x37\x64\x19\x10\x83\x32\x22\x77\x2a",
+               (u8 *) "\xab\x65\xc2\x6e\xdd\xb2\x87\x60\x0d\xb2\xfd\xa1\x0d\x1e\x60\x5c\xbb\x75\x90\x10\xc2\x96\x58\xf2\xc7\x2d\x93\xa2\xd1\x6d\x29\x30",
+               (u8 *) "\xb9\x01\xe8\x03\x6e\xd1\xc3\x83\xcd\x3c\x4c\x4d\xd0\xa6\xab\x05\x3d\x25\xce\x49\x22\x92\x4c\x55\xf0\x64\x94\x33\x53\xd7\x8a\x6c",
+               (u8 *) "\x12\xc1\xaa\x44\xbb\xf8\x7e\x75\xe6\x11\xf6\x9b\x2c\x38\xf4\x9b\x28\xf2\xb3\x43\x4b\x65\xc0\x98\x77\x47\x00\x44\xc6\xea\x17\x0d",
+               (u8 *) "\xbd\x9e\xf8\x22\xde\x52\x88\x19\x61\x34\xcf\x8a\xf7\x83\x93\x04\x67\x55\x9c\x23\xf0\x52\x15\x84\x70\xa2\x96\xf7\x25\x73\x5a\x32",
+               (u8 *) "\x8b\xab\x26\xfb\xc2\xc1\x2b\x0f\x13\xe2\xab\x18\x5e\xab\xf2\x41\x31\x18\x5a\x6d\x69\x6f\x0c\xfa\x9b\x42\x80\x8b\x38\xe1\x32\xa2",
+               (u8 *) "\x56\x4d\x3d\xae\x18\x3c\x52\x34\xc8\xaf\x1e\x51\x06\x1c\x44\xb5\x3c\x07\x78\xa7\xb5\xf7\x2d\x3c\x23\xa3\x13\x5c\x7d\x67\xb9\xf4",
+               (u8 *) "\xf3\x43\x69\x89\x0f\xcf\x16\xfb\x51\x7d\xca\xae\x44\x63\xb2\xdd\x02\xf3\x1c\x81\xe8\x20\x07\x31\xb8\x99\xb0\x28\xe7\x91\xbf\xa7",
+               (u8 *) "\x72\xda\x64\x62\x83\x22\x8c\x14\x30\x08\x53\x70\x17\x95\x61\x6f\x4e\x0a\x8c\x6f\x79\x34\xa7\x88\xe2\x26\x5e\x81\xd6\xd0\xc8\xf4",
+               (u8 *) "\x43\x8d\xd5\xea\xfe\xa0\x11\x1b\x6f\x36\xb4\xb9\x38\xda\x2a\x68\x5f\x6b\xfc\x73\x81\x58\x74\xd9\x71\x00\xf0\x86\x97\x93\x57\xd8"
+       },
+       {
+               16, (u8 *) "\xeb\xb4\x62\x27\xc6\xcc\x8b\x37\x64\x19\x10\x83\x32\x22\x77\x2a",
+               (u8 *) "\x72\x0c\x94\xb6\x3e\xdf\x44\xe1\x31\xd9\x50\xca\x21\x1a\x5a\x30\xc3\x66\xfd\xea\xcf\x9c\xa8\x04\x36\xbe\x7c\x35\x84\x24\xd2\x0b",
+               (u8 *) "\xb3\x39\x4a\x40\xaa\xbf\x75\xcb\xa4\x22\x82\xef\x25\xa0\x05\x9f\x48\x47\xd8\x1d\xa4\x94\x2d\xbc\x24\x9d\xef\xc4\x8c\x92\x2b\x9f",
+               (u8 *) "\x08\x12\x8c\x46\x9f\x27\x53\x42\xad\xda\x20\x2b\x2b\x58\xda\x95\x97\x0d\xac\xef\x40\xad\x98\x72\x3b\xac\x5d\x69\x55\xb8\x17\x61",
+               (u8 *) "\x3c\xb8\x99\x93\xb0\x7b\x0c\xed\x93\xde\x13\xd2\xa1\x10\x13\xac\xef\x2d\x67\x6f\x15\x45\xc2\xc1\x3d\xc6\x80\xa0\x2f\x4a\xdb\xfe",
+               (u8 *) "\xb6\x05\x95\x51\x4f\x24\xbc\x9f\xe5\x22\xa6\xca\xd7\x39\x36\x44\xb5\x15\xa8\xc5\x01\x17\x54\xf5\x90\x03\x05\x8b\xdb\x81\x51\x4e",
+               (u8 *) "\x3c\x70\x04\x7e\x8c\xbc\x03\x8e\x3b\x98\x20\xdb\x60\x1d\xa4\x95\x11\x75\xda\x6e\xe7\x56\xde\x46\xa5\x3e\x2b\x07\x56\x60\xb7\x70",
+               (u8 *) "\x00\xa5\x42\xbb\xa0\x21\x11\xcc\x2c\x65\xb3\x8e\xbd\xba\x58\x7e\x58\x65\xfd\xbb\x5b\x48\x06\x41\x04\xe8\x30\xb3\x80\xf2\xae\xde",
+               (u8 *) "\x34\xb2\x1a\xd2\xad\x44\xe9\x99\xdb\x2d\x7f\x08\x63\xf0\xd9\xb6\x84\xa9\x21\x8f\xc3\x6e\x8a\x5f\x2c\xcf\xbe\xae\x53\xa2\x7d\x25",
+               (u8 *) "\xa2\x22\x1a\x11\xb8\x33\xcc\xb4\x98\xa5\x95\x40\xf0\x54\x5f\x4a\x5b\xbe\xb4\x78\x7d\x59\xe5\x37\x3f\xdb\xea\x6c\x6f\x75\xc2\x9b"
+       },
+       {
+               24, (u8 *) "\xc1\x09\x16\x39\x08\xeb\xe5\x1d\xeb\xb4\x62\x27\xc6\xcc\x8b\x37\x64\x19\x10\x83\x32\x22\x77\x2a",
+               (u8 *) "\x54\xb6\x4e\x6b\x5a\x20\xb5\xe2\xec\x84\x59\x3d\xc7\x98\x9d\xa7\xc1\x35\xee\xe2\x37\xa8\x54\x65\xff\x97\xdc\x03\x92\x4f\x45\xce",
+               (u8 *) "\xcf\xcc\x92\x2f\xb4\xa1\x4a\xb4\x5d\x61\x75\xaa\xbb\xf2\xd2\x01\x83\x7b\x87\xe2\xa4\x46\xad\x0e\xf7\x98\xac\xd0\x2b\x94\x12\x4f",
+               (u8 *) "\x17\xa6\xdb\xd6\x64\x92\x6a\x06\x36\xb3\xf4\xc3\x7a\x4f\x46\x94\x4a\x5f\x9f\x26\xae\xee\xd4\xd4\xa2\x5f\x63\x2d\x30\x52\x33\xd9",
+               (u8 *) "\x80\xa3\xd0\x1e\xf0\x0c\x8e\x9a\x42\x09\xc1\x7f\x4e\xeb\x35\x8c\xd1\x5e\x7d\x5f\xfa\xaa\xbc\x02\x07\xbf\x20\x0a\x11\x77\x93\xa2",
+               (u8 *) "\x34\x96\x82\xbf\x58\x8e\xaa\x52\xd0\xaa\x15\x60\x34\x6a\xea\xfa\xf5\x85\x4c\xdb\x76\xc8\x89\xe3\xad\x63\x35\x4e\x5f\x72\x75\xe3",
+               (u8 *) "\x53\x2c\x7c\xec\xcb\x39\xdf\x32\x36\x31\x84\x05\xa4\xb1\x27\x9c\xba\xef\xe6\xd9\xce\xb6\x51\x84\x22\x60\xe0\xd1\xe0\x5e\x3b\x90",
+               (u8 *) "\xe8\x2d\x8c\x6d\xb5\x4e\x3c\x63\x3f\x58\x1c\x95\x2b\xa0\x42\x07\x4b\x16\xe5\x0a\xbd\x38\x1b\xd7\x09\x00\xa9\xcd\x9a\x62\xcb\x23",
+               (u8 *) "\x36\x82\xee\x33\xbd\x14\x8b\xd9\xf5\x86\x56\xcd\x8f\x30\xd9\xfb\x1e\x5a\x0b\x84\x75\x04\x5d\x9b\x20\xb2\x62\x86\x24\xed\xfd\x9e",
+               (u8 *) "\x63\xed\xd6\x84\xfb\x82\x62\x82\xfe\x52\x8f\x9c\x0e\x92\x37\xbc\xe4\xdd\x2e\x98\xd6\x96\x0f\xae\x0b\x43\x54\x54\x56\x74\x33\x91"
+       },
+       {
+               32, (u8 *) "\x1a\xda\x31\xd5\xcf\x68\x82\x21\xc1\x09\x16\x39\x08\xeb\xe5\x1d\xeb\xb4\x62\x27\xc6\xcc\x8b\x37\x64\x19\x10\x83\x32\x22\x77\x2a",
+               (u8 *) "\xdd\x5b\xcb\x00\x18\xe9\x22\xd4\x94\x75\x9d\x7c\x39\x5d\x02\xd3\xc8\x44\x6f\x8f\x77\xab\xf7\x37\x68\x53\x53\xeb\x89\xa1\xc9\xeb",
+               (u8 *) "\xaf\x3e\x30\xf9\xc0\x95\x04\x59\x38\x15\x15\x75\xc3\xfb\x90\x98\xf8\xcb\x62\x74\xdb\x99\xb8\x0b\x1d\x20\x12\xa9\x8e\xd4\x8f\x0e",
+               (u8 *) "\x25\xc3\x00\x5a\x1c\xb8\x5d\xe0\x76\x25\x98\x39\xab\x71\x98\xab\x9d\xcb\xc1\x83\xe8\xcb\x99\x4b\x72\x7b\x75\xbe\x31\x80\x76\x9c",
+               (u8 *) "\xa1\xd3\x07\x8d\xfa\x91\x69\x50\x3e\xd9\xd4\x49\x1d\xee\x4e\xb2\x85\x14\xa5\x49\x58\x58\x09\x6f\x59\x6e\x4b\xcd\x66\xb1\x06\x65",
+               (u8 *) "\x5f\x40\xd5\x9e\xc1\xb0\x3b\x33\x73\x8e\xfa\x60\xb2\x25\x5d\x31\x34\x77\xc7\xf7\x64\xa4\x1b\xac\xef\xf9\x0b\xf1\x4f\x92\xb7\xcc",
+               (u8 *) "\xac\x4e\x95\x36\x8d\x99\xb9\xeb\x78\xb8\xda\x8f\x81\xff\xa7\x95\x8c\x3c\x13\xf8\xc2\x38\x8b\xb7\x3f\x38\x57\x6e\x65\xb7\xc4\x46",
+               (u8 *) "\x13\xc4\xb9\xc1\xdf\xb6\x65\x79\xed\xdd\x8a\x28\x0b\x9f\x73\x16\xdd\xd2\x78\x20\x55\x01\x26\x69\x8e\xfa\xad\xc6\x4b\x64\xf6\x6e",
+               (u8 *) "\xf0\x8f\x2e\x66\xd2\x8e\xd1\x43\xf3\xa2\x37\xcf\x9d\xe7\x35\x59\x9e\xa3\x6c\x52\x55\x31\xb8\x80\xba\x12\x43\x34\xf5\x7b\x0b\x70",
+               (u8 *) "\xd5\xa3\x9e\x3d\xfc\xc5\x02\x80\xba\xc4\xa6\xb5\xaa\x0d\xca\x7d\x37\x0b\x1c\x1f\xe6\x55\x91\x6d\x97\xfd\x0d\x47\xca\x1d\x72\xb8"
+       }
+};
+
+#define NUM_TESTS (sizeof(tests) / sizeof(tests[0]))
+
+
+static int run_test(unsigned int i, const u8 *key, size_t key_len,
+                   const u8 *stream, int offset)
+{
+       u8 res[32];
+       os_memset(res, 0, sizeof(res));
+       if (rc4_skip(key, key_len, offset, res, sizeof(res)) < 0 ||
+           os_memcmp(res, stream, 32) != 0) {
+               printf("RC4 test case %d (offset %d) - FAILED!\n",
+                      i + 1, offset);
+               return 1;
+       }
+       return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+       int ret = 0;
+       unsigned int i;
+
+       for (i = 0; i < NUM_TESTS; i++) {
+               const struct rc4_test_vector *test = &tests[i];
+               ret += run_test(i, test->key, test->key_len,
+                               test->stream0, 0);
+               ret += run_test(i, test->key, test->key_len,
+                               test->stream240, 240);
+               ret += run_test(i, test->key, test->key_len,
+                               test->stream496, 496);
+               ret += run_test(i, test->key, test->key_len,
+                               test->stream752, 752);
+               ret += run_test(i, test->key, test->key_len,
+                               test->stream1008, 1008);
+               ret += run_test(i, test->key, test->key_len,
+                               test->stream1520, 1520);
+               ret += run_test(i, test->key, test->key_len,
+                               test->stream2032, 2032);
+               ret += run_test(i, test->key, test->key_len,
+                               test->stream3056, 3056);
+               ret += run_test(i, test->key, test->key_len,
+                               test->stream4080, 4080);
+       }
+
+       if (ret == 0)
+               printf("All RC4 test cases passed\n");
+
+       return ret;
+}
diff --git a/tests/test-sha1.c b/tests/test-sha1.c
new file mode 100644 (file)
index 0000000..1b390f1
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/crypto.h"
+#include "crypto/md5.h"
+#include "crypto/sha1.h"
+
+
+static int test_eap_fast(void)
+{
+       /* RFC 4851, Appendix B.1 */
+       const u8 pac_key[] = {
+               0x0B, 0x97, 0x39, 0x0F, 0x37, 0x51, 0x78, 0x09,
+               0x81, 0x1E, 0xFD, 0x9C, 0x6E, 0x65, 0x94, 0x2B,
+               0x63, 0x2C, 0xE9, 0x53, 0x89, 0x38, 0x08, 0xBA,
+               0x36, 0x0B, 0x03, 0x7C, 0xD1, 0x85, 0xE4, 0x14
+       };
+       const u8 seed[] = {
+               0x3F, 0xFB, 0x11, 0xC4, 0x6C, 0xBF, 0xA5, 0x7A,
+               0x54, 0x40, 0xDA, 0xE8, 0x22, 0xD3, 0x11, 0xD3,
+               0xF7, 0x6D, 0xE4, 0x1D, 0xD9, 0x33, 0xE5, 0x93,
+               0x70, 0x97, 0xEB, 0xA9, 0xB3, 0x66, 0xF4, 0x2A,
+               0x00, 0x00, 0x00, 0x02, 0x6A, 0x66, 0x43, 0x2A,
+               0x8D, 0x14, 0x43, 0x2C, 0xEC, 0x58, 0x2D, 0x2F,
+               0xC7, 0x9C, 0x33, 0x64, 0xBA, 0x04, 0xAD, 0x3A,
+               0x52, 0x54, 0xD6, 0xA5, 0x79, 0xAD, 0x1E, 0x00
+       };
+       const u8 master_secret[] = {
+               0x4A, 0x1A, 0x51, 0x2C, 0x01, 0x60, 0xBC, 0x02,
+               0x3C, 0xCF, 0xBC, 0x83, 0x3F, 0x03, 0xBC, 0x64,
+               0x88, 0xC1, 0x31, 0x2F, 0x0B, 0xA9, 0xA2, 0x77,
+               0x16, 0xA8, 0xD8, 0xE8, 0xBD, 0xC9, 0xD2, 0x29,
+               0x38, 0x4B, 0x7A, 0x85, 0xBE, 0x16, 0x4D, 0x27,
+               0x33, 0xD5, 0x24, 0x79, 0x87, 0xB1, 0xC5, 0xA2  
+       };
+       const u8 key_block[] = {
+               0x59, 0x59, 0xBE, 0x8E, 0x41, 0x3A, 0x77, 0x74,
+               0x8B, 0xB2, 0xE5, 0xD3, 0x60, 0xAC, 0x4D, 0x35,
+               0xDF, 0xFB, 0xC8, 0x1E, 0x9C, 0x24, 0x9C, 0x8B,
+               0x0E, 0xC3, 0x1D, 0x72, 0xC8, 0x84, 0x9D, 0x57,
+               0x48, 0x51, 0x2E, 0x45, 0x97, 0x6C, 0x88, 0x70,
+               0xBE, 0x5F, 0x01, 0xD3, 0x64, 0xE7, 0x4C, 0xBB,
+               0x11, 0x24, 0xE3, 0x49, 0xE2, 0x3B, 0xCD, 0xEF,
+               0x7A, 0xB3, 0x05, 0x39, 0x5D, 0x64, 0x8A, 0x44,
+               0x11, 0xB6, 0x69, 0x88, 0x34, 0x2E, 0x8E, 0x29,
+               0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05,
+               0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96,
+               0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84,
+               0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98,
+               0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71
+       };
+       const u8 sks[] = {
+               0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05,
+               0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96,
+               0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84,
+               0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98,
+               0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71
+       };
+       const u8 isk[] = {
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+       const u8 imck[] = {
+               0x16, 0x15, 0x3C, 0x3F, 0x21, 0x55, 0xEF, 0xD9,
+               0x7F, 0x34, 0xAE, 0xC8, 0x1A, 0x4E, 0x66, 0x80,
+               0x4C, 0xC3, 0x76, 0xF2, 0x8A, 0xA9, 0x6F, 0x96,
+               0xC2, 0x54, 0x5F, 0x8C, 0xAB, 0x65, 0x02, 0xE1,
+               0x18, 0x40, 0x7B, 0x56, 0xBE, 0xEA, 0xA7, 0xC5,
+               0x76, 0x5D, 0x8F, 0x0B, 0xC5, 0x07, 0xC6, 0xB9,
+               0x04, 0xD0, 0x69, 0x56, 0x72, 0x8B, 0x6B, 0xB8,
+               0x15, 0xEC, 0x57, 0x7B
+       };
+       const u8 msk[] = {
+               0x4D, 0x83, 0xA9, 0xBE, 0x6F, 0x8A, 0x74, 0xED,
+               0x6A, 0x02, 0x66, 0x0A, 0x63, 0x4D, 0x2C, 0x33,
+               0xC2, 0xDA, 0x60, 0x15, 0xC6, 0x37, 0x04, 0x51,
+               0x90, 0x38, 0x63, 0xDA, 0x54, 0x3E, 0x14, 0xB9,
+               0x27, 0x99, 0x18, 0x1E, 0x07, 0xBF, 0x0F, 0x5A,
+               0x5E, 0x3C, 0x32, 0x93, 0x80, 0x8C, 0x6C, 0x49,
+               0x67, 0xED, 0x24, 0xFE, 0x45, 0x40, 0xA0, 0x59,
+               0x5E, 0x37, 0xC2, 0xE9, 0xD0, 0x5D, 0x0A, 0xE3
+       };
+       const u8 emsk[] = {
+               0x3A, 0xD4, 0xAB, 0xDB, 0x76, 0xB2, 0x7F, 0x3B,
+               0xEA, 0x32, 0x2C, 0x2B, 0x74, 0xF4, 0x28, 0x55,
+               0xEF, 0x2D, 0xBA, 0x78, 0xC9, 0x57, 0x2F, 0x0D,
+               0x06, 0xCD, 0x51, 0x7C, 0x20, 0x93, 0x98, 0xA9,
+               0x76, 0xEA, 0x70, 0x21, 0xD7, 0x0E, 0x25, 0x54,
+               0x97, 0xED, 0xB2, 0x8A, 0xF6, 0xED, 0xFD, 0x0A,
+               0x2A, 0xE7, 0xA1, 0x58, 0x90, 0x10, 0x50, 0x44,
+               0xB3, 0x82, 0x85, 0xDB, 0x06, 0x14, 0xD2, 0xF9
+       };
+       /* RFC 4851, Appendix B.2 */
+       u8 tlv[] = {
+               0x80, 0x0C, 0x00, 0x38, 0x00, 0x01, 0x01, 0x00,
+               0xD8, 0x6A, 0x8C, 0x68, 0x3C, 0x32, 0x31, 0xA8,
+               0x56, 0x63, 0xB6, 0x40, 0x21, 0xFE, 0x21, 0x14,
+               0x4E, 0xE7, 0x54, 0x20, 0x79, 0x2D, 0x42, 0x62,
+               0xC9, 0xBF, 0x53, 0x7F, 0x54, 0xFD, 0xAC, 0x58,
+               0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF,
+               0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC,
+               0x05, 0xC5, 0x5B, 0xB7
+       };
+       const u8 compound_mac[] = {
+               0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF,
+               0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC,
+               0x05, 0xC5, 0x5B, 0xB7
+       };
+       u8 buf[512];
+       const u8 *simck, *cmk;
+       int errors = 0;
+
+       printf("EAP-FAST test cases\n");
+
+       printf("- T-PRF (SHA1) test case / master_secret\n");
+       sha1_t_prf(pac_key, sizeof(pac_key), "PAC to master secret label hash",
+                  seed, sizeof(seed), buf, sizeof(master_secret));
+       if (memcmp(master_secret, buf, sizeof(master_secret)) != 0) {
+               printf("T-PRF test - FAILED!\n");
+               errors++;
+       }
+
+       printf("- PRF (TLS, SHA1/MD5) test case / key_block\n");
+       if (tls_prf_sha1_md5(master_secret, sizeof(master_secret),
+                            "key expansion", seed, sizeof(seed),
+                            buf, sizeof(key_block)) ||
+           memcmp(key_block, buf, sizeof(key_block)) != 0) {
+               printf("PRF test - FAILED!\n");
+               errors++;
+       }
+
+       printf("- T-PRF (SHA1) test case / IMCK\n");
+       sha1_t_prf(sks, sizeof(sks), "Inner Methods Compound Keys",
+                  isk, sizeof(isk), buf, sizeof(imck));
+       if (memcmp(imck, buf, sizeof(imck)) != 0) {
+               printf("T-PRF test - FAILED!\n");
+               errors++;
+       }
+
+       simck = imck;
+       cmk = imck + 40;
+
+       printf("- T-PRF (SHA1) test case / MSK\n");
+       sha1_t_prf(simck, 40, "Session Key Generating Function",
+                  (u8 *) "", 0, buf, sizeof(msk));
+       if (memcmp(msk, buf, sizeof(msk)) != 0) {
+               printf("T-PRF test - FAILED!\n");
+               errors++;
+       }
+
+       printf("- T-PRF (SHA1) test case / EMSK\n");
+       sha1_t_prf(simck, 40, "Extended Session Key Generating Function",
+                  (u8 *) "", 0, buf, sizeof(msk));
+       if (memcmp(emsk, buf, sizeof(emsk)) != 0) {
+               printf("T-PRF test - FAILED!\n");
+               errors++;
+       }
+
+       printf("- Compound MAC test case\n");
+       memset(tlv + sizeof(tlv) - 20, 0, 20);
+       hmac_sha1(cmk, 20, tlv, sizeof(tlv), tlv + sizeof(tlv) - 20);
+       if (memcmp(tlv + sizeof(tlv) - 20, compound_mac, sizeof(compound_mac))
+           != 0) {
+               printf("Compound MAC test - FAILED!\n");
+               errors++;
+       }
+
+       return errors;
+}
+
+
+static u8 key0[] =
+{
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b
+};
+static u8 data0[] = "Hi There";
+static u8 prf0[] =
+{
+       0xbc, 0xd4, 0xc6, 0x50, 0xb3, 0x0b, 0x96, 0x84,
+       0x95, 0x18, 0x29, 0xe0, 0xd7, 0x5f, 0x9d, 0x54,
+       0xb8, 0x62, 0x17, 0x5e, 0xd9, 0xf0, 0x06, 0x06,
+       0xe1, 0x7d, 0x8d, 0xa3, 0x54, 0x02, 0xff, 0xee,
+       0x75, 0xdf, 0x78, 0xc3, 0xd3, 0x1e, 0x0f, 0x88,
+       0x9f, 0x01, 0x21, 0x20, 0xc0, 0x86, 0x2b, 0xeb,
+       0x67, 0x75, 0x3e, 0x74, 0x39, 0xae, 0x24, 0x2e,
+       0xdb, 0x83, 0x73, 0x69, 0x83, 0x56, 0xcf, 0x5a
+};
+
+static u8 key1[] = "Jefe";
+static u8 data1[] = "what do ya want for nothing?";
+static u8 prf1[] =
+{
+       0x51, 0xf4, 0xde, 0x5b, 0x33, 0xf2, 0x49, 0xad,
+       0xf8, 0x1a, 0xeb, 0x71, 0x3a, 0x3c, 0x20, 0xf4,
+       0xfe, 0x63, 0x14, 0x46, 0xfa, 0xbd, 0xfa, 0x58,
+       0x24, 0x47, 0x59, 0xae, 0x58, 0xef, 0x90, 0x09,
+       0xa9, 0x9a, 0xbf, 0x4e, 0xac, 0x2c, 0xa5, 0xfa,
+       0x87, 0xe6, 0x92, 0xc4, 0x40, 0xeb, 0x40, 0x02,
+       0x3e, 0x7b, 0xab, 0xb2, 0x06, 0xd6, 0x1d, 0xe7,
+       0xb9, 0x2f, 0x41, 0x52, 0x90, 0x92, 0xb8, 0xfc
+};
+
+
+static u8 key2[] =
+{
+       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+       0xaa, 0xaa, 0xaa, 0xaa
+};
+static u8 data2[] =
+{
+       0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+       0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+       0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+       0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+       0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+       0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+       0xdd, 0xdd
+};
+static u8 prf2[] =
+{
+       0xe1, 0xac, 0x54, 0x6e, 0xc4, 0xcb, 0x63, 0x6f,
+       0x99, 0x76, 0x48, 0x7b, 0xe5, 0xc8, 0x6b, 0xe1,
+       0x7a, 0x02, 0x52, 0xca, 0x5d, 0x8d, 0x8d, 0xf1,
+       0x2c, 0xfb, 0x04, 0x73, 0x52, 0x52, 0x49, 0xce,
+       0x9d, 0xd8, 0xd1, 0x77, 0xea, 0xd7, 0x10, 0xbc,
+       0x9b, 0x59, 0x05, 0x47, 0x23, 0x91, 0x07, 0xae,
+       0xf7, 0xb4, 0xab, 0xd4, 0x3d, 0x87, 0xf0, 0xa6,
+       0x8f, 0x1c, 0xbd, 0x9e, 0x2b, 0x6f, 0x76, 0x07
+};
+
+
+struct passphrase_test {
+       char *passphrase;
+       char *ssid;
+       char psk[32];
+};
+
+static struct passphrase_test passphrase_tests[] =
+{
+       {
+               "password",
+               "IEEE",
+               {
+                       0xf4, 0x2c, 0x6f, 0xc5, 0x2d, 0xf0, 0xeb, 0xef,
+                       0x9e, 0xbb, 0x4b, 0x90, 0xb3, 0x8a, 0x5f, 0x90,
+                       0x2e, 0x83, 0xfe, 0x1b, 0x13, 0x5a, 0x70, 0xe2,
+                       0x3a, 0xed, 0x76, 0x2e, 0x97, 0x10, 0xa1, 0x2e
+               }
+       },
+       {
+               "ThisIsAPassword",
+               "ThisIsASSID",
+               {
+                       0x0d, 0xc0, 0xd6, 0xeb, 0x90, 0x55, 0x5e, 0xd6,
+                       0x41, 0x97, 0x56, 0xb9, 0xa1, 0x5e, 0xc3, 0xe3,
+                       0x20, 0x9b, 0x63, 0xdf, 0x70, 0x7d, 0xd5, 0x08,
+                       0xd1, 0x45, 0x81, 0xf8, 0x98, 0x27, 0x21, 0xaf
+               }
+       },
+       {
+               "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+               "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
+               {
+                       0xbe, 0xcb, 0x93, 0x86, 0x6b, 0xb8, 0xc3, 0x83,
+                       0x2c, 0xb7, 0x77, 0xc2, 0xf5, 0x59, 0x80, 0x7c,
+                       0x8c, 0x59, 0xaf, 0xcb, 0x6e, 0xae, 0x73, 0x48,
+                       0x85, 0x00, 0x13, 0x00, 0xa9, 0x81, 0xcc, 0x62
+               }
+       },
+};
+
+#define NUM_PASSPHRASE_TESTS \
+(sizeof(passphrase_tests) / sizeof(passphrase_tests[0]))
+
+
+struct rfc6070_test {
+       char *p;
+       char *s;
+       int c;
+       char dk[32];
+       size_t dk_len;
+};
+
+static struct rfc6070_test rfc6070_tests[] =
+{
+       {
+               "password",
+               "salt",
+               1,
+               {
+                       0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
+                       0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
+                       0x2f, 0xe0, 0x37, 0xa6
+               },
+               20
+       },
+       {
+               "password",
+               "salt",
+               2,
+               {
+                       0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c,
+                       0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0,
+                       0xd8, 0xde, 0x89, 0x57
+               },
+               20
+       },
+       {
+               "password",
+               "salt",
+               4096,
+               {
+                       0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a,
+                       0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0,
+                       0x65, 0xa4, 0x29, 0xc1
+               },
+               20
+       },
+#if 0 /* This takes quite long to derive.. */
+       {
+               "password",
+               "salt",
+               16777216,
+               {
+                       0xee, 0xfe, 0x3d, 0x61, 0xcd, 0x4d, 0xa4, 0xe4,
+                       0xe9, 0x94, 0x5b, 0x3d, 0x6b, 0xa2, 0x15, 0x8c,
+                       0x26, 0x34, 0xe9, 0x84
+               },
+               20
+       },
+#endif
+       {
+               "passwordPASSWORDpassword",
+               "saltSALTsaltSALTsaltSALTsaltSALTsalt",
+               4096,
+               {
+                       0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b,
+                       0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a,
+                       0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70,
+                       0x38
+               },
+               25
+       },
+#if 0 /* \0 not currently supported in passphrase parameters.. */
+       {
+               "pass\0word",
+               "sa\0lt",
+               4096,
+               {
+                       0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
+                       0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3
+               },
+               16
+       },
+#endif
+};
+
+#define NUM_RFC6070_TESTS \
+(sizeof(rfc6070_tests) / sizeof(rfc6070_tests[0]))
+
+
+int main(int argc, char *argv[])
+{
+       u8 res[512];
+       int ret = 0;
+       unsigned int i;
+
+       printf("PRF-SHA1 test cases:\n");
+
+       sha1_prf(key0, sizeof(key0), "prefix", data0, sizeof(data0) - 1,
+                res, sizeof(prf0));
+       if (memcmp(res, prf0, sizeof(prf0)) == 0)
+               printf("Test case 0 - OK\n");
+       else {
+               printf("Test case 0 - FAILED!\n");
+               ret++;
+       }
+
+       sha1_prf(key1, sizeof(key1) - 1, "prefix", data1, sizeof(data1) - 1,
+                res, sizeof(prf1));
+       if (memcmp(res, prf1, sizeof(prf1)) == 0)
+               printf("Test case 1 - OK\n");
+       else {
+               printf("Test case 1 - FAILED!\n");
+               ret++;
+       }
+
+       sha1_prf(key2, sizeof(key2), "prefix", data2, sizeof(data2),
+                res, sizeof(prf2));
+       if (memcmp(res, prf2, sizeof(prf2)) == 0)
+               printf("Test case 2 - OK\n");
+       else {
+               printf("Test case 2 - FAILED!\n");
+               ret++;
+       }
+
+       ret += test_eap_fast();
+
+       printf("PBKDF2-SHA1 Passphrase test cases:\n");
+       for (i = 0; i < NUM_PASSPHRASE_TESTS; i++) {
+               u8 psk[32];
+               struct passphrase_test *test = &passphrase_tests[i];
+               pbkdf2_sha1(test->passphrase,
+                           test->ssid, strlen(test->ssid),
+                           4096, psk, 32);
+               if (memcmp(psk, test->psk, 32) == 0)
+                       printf("Test case %d - OK\n", i);
+               else {
+                       printf("Test case %d - FAILED!\n", i);
+                       ret++;
+               }
+       }
+
+       printf("PBKDF2-SHA1 test cases (RFC 6070):\n");
+       for (i = 0; i < NUM_RFC6070_TESTS; i++) {
+               u8 dk[25];
+               struct rfc6070_test *test = &rfc6070_tests[i];
+               pbkdf2_sha1(test->p, test->s, strlen(test->s), test->c,
+                           dk, test->dk_len);
+               if (memcmp(dk, test->dk, test->dk_len) == 0)
+                       printf("Test case %d - OK\n", i);
+               else {
+                       printf("Test case %d - FAILED!\n", i);
+                       ret++;
+               }
+       }
+
+       return ret;
+}
diff --git a/tests/test-sha256.c b/tests/test-sha256.c
new file mode 100644 (file)
index 0000000..f194ff9
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/sha256.h"
+#include "crypto/crypto.h"
+
+struct {
+       char *data;
+       u8 hash[32];
+} tests[] = {
+       {
+               "abc",
+               {
+                       0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
+                       0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
+                       0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
+                       0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad
+               }
+       },
+       {
+               "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+               {
+                       0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8,
+                       0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
+                       0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
+                       0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1
+               }
+       }
+};
+
+struct hmac_test {
+       u8 key[80];
+       size_t key_len;
+       u8 data[128];
+       size_t data_len;
+       u8 hash[32];
+} hmac_tests[] = {
+       /* draft-ietf-ipsec-ciph-sha-256-01.txt */
+       {
+               {
+                       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
+               },
+               32,
+               "abc", 3,
+               {
+                       0xa2, 0x1b, 0x1f, 0x5d, 0x4c, 0xf4, 0xf7, 0x3a,
+                       0x4d, 0xd9, 0x39, 0x75, 0x0f, 0x7a, 0x06, 0x6a,
+                       0x7f, 0x98, 0xcc, 0x13, 0x1c, 0xb1, 0x6a, 0x66,
+                       0x92, 0x75, 0x90, 0x21, 0xcf, 0xab, 0x81, 0x81
+               }
+       },
+       {
+               {
+                       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
+               },
+               32,
+               "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+               56,
+               {
+                       0x10, 0x4f, 0xdc, 0x12, 0x57, 0x32, 0x8f, 0x08,
+                       0x18, 0x4b, 0xa7, 0x31, 0x31, 0xc5, 0x3c, 0xae,
+                       0xe6, 0x98, 0xe3, 0x61, 0x19, 0x42, 0x11, 0x49,
+                       0xea, 0x8c, 0x71, 0x24, 0x56, 0x69, 0x7d, 0x30
+               }
+       },
+       {
+               {
+                       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
+               },
+               32,
+               "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+               "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+               112,
+               {
+                       0x47, 0x03, 0x05, 0xfc, 0x7e, 0x40, 0xfe, 0x34,
+                       0xd3, 0xee, 0xb3, 0xe7, 0x73, 0xd9, 0x5a, 0xab,
+                       0x73, 0xac, 0xf0, 0xfd, 0x06, 0x04, 0x47, 0xa5,
+                       0xeb, 0x45, 0x95, 0xbf, 0x33, 0xa9, 0xd1, 0xa3
+               }
+       },
+       {
+               {
+                       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+                       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+                       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+                       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
+               },
+               32,
+               "Hi There",
+               8,
+               {
+                       0x19, 0x8a, 0x60, 0x7e, 0xb4, 0x4b, 0xfb, 0xc6,
+                       0x99, 0x03, 0xa0, 0xf1, 0xcf, 0x2b, 0xbd, 0xc5,
+                       0xba, 0x0a, 0xa3, 0xf3, 0xd9, 0xae, 0x3c, 0x1c,
+                       0x7a, 0x3b, 0x16, 0x96, 0xa0, 0xb6, 0x8c, 0xf7
+               }
+       },
+       {
+               "Jefe",
+               4,
+               "what do ya want for nothing?",
+               28,
+               {
+                       0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e,
+                       0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7,
+                       0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
+                       0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43
+               }
+       },
+       {
+               {
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+               },
+               32,
+               {
+                       0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+                       0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+                       0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+                       0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+                       0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+                       0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+                       0xdd, 0xdd
+               },
+               50,
+               {
+                       0xcd, 0xcb, 0x12, 0x20, 0xd1, 0xec, 0xcc, 0xea,
+                       0x91, 0xe5, 0x3a, 0xba, 0x30, 0x92, 0xf9, 0x62,
+                       0xe5, 0x49, 0xfe, 0x6c, 0xe9, 0xed, 0x7f, 0xdc,
+                       0x43, 0x19, 0x1f, 0xbd, 0xe4, 0x5c, 0x30, 0xb0
+               }
+       },
+       {
+               {
+                       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
+               },
+               37,
+               {
+                       0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+                       0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+                       0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+                       0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+                       0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+                       0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+                       0xcd, 0xcd
+               },
+               50,
+               {
+                       0xd4, 0x63, 0x3c, 0x17, 0xf6, 0xfb, 0x8d, 0x74,
+                       0x4c, 0x66, 0xde, 0xe0, 0xf8, 0xf0, 0x74, 0x55,
+                       0x6e, 0xc4, 0xaf, 0x55, 0xef, 0x07, 0x99, 0x85,
+                       0x41, 0x46, 0x8e, 0xb4, 0x9b, 0xd2, 0xe9, 0x17
+               }
+       },
+       {
+               {
+                       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+                       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+                       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+                       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c
+               },
+               32,
+               "Test With Truncation",
+               20,
+               {
+                       0x75, 0x46, 0xaf, 0x01, 0x84, 0x1f, 0xc0, 0x9b,
+                       0x1a, 0xb9, 0xc3, 0x74, 0x9a, 0x5f, 0x1c, 0x17,
+                       0xd4, 0xf5, 0x89, 0x66, 0x8a, 0x58, 0x7b, 0x27,
+                       0x00, 0xa9, 0xc9, 0x7c, 0x11, 0x93, 0xcf, 0x42
+               }
+       },
+       {
+               {
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+               },
+               80,
+               "Test Using Larger Than Block-Size Key - Hash Key First",
+               54,
+               {
+                       0x69, 0x53, 0x02, 0x5e, 0xd9, 0x6f, 0x0c, 0x09,
+                       0xf8, 0x0a, 0x96, 0xf7, 0x8e, 0x65, 0x38, 0xdb,
+                       0xe2, 0xe7, 0xb8, 0x20, 0xe3, 0xdd, 0x97, 0x0e,
+                       0x7d, 0xdd, 0x39, 0x09, 0x1b, 0x32, 0x35, 0x2f
+               }
+       },
+       {
+               {
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+               },
+               80,
+               "Test Using Larger Than Block-Size Key and Larger Than One "
+               "Block-Size Data",
+               73,
+               {
+                       0x63, 0x55, 0xac, 0x22, 0xe8, 0x90, 0xd0, 0xa3,
+                       0xc8, 0x48, 0x1a, 0x5c, 0xa4, 0x82, 0x5b, 0xc8,
+                       0x84, 0xd3, 0xe7, 0xa1, 0xff, 0x98, 0xa2, 0xfc,
+                       0x2a, 0xc7, 0xd8, 0xe0, 0x64, 0xc3, 0xb2, 0xe6
+               }
+       }
+};
+
+
+int main(int argc, char *argv[])
+{
+
+       unsigned int i;
+       u8 hash[32];
+       const u8 *addr[2];
+       size_t len[2];
+       int errors = 0;
+
+       for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+               printf("SHA256 test case %d:", i + 1);
+
+               addr[0] = (u8 *) tests[i].data;
+               len[0] = strlen(tests[i].data);
+               sha256_vector(1, addr, len, hash);
+               if (memcmp(hash, tests[i].hash, 32) != 0) {
+                       printf(" FAIL");
+                       errors++;
+               } else
+                       printf(" OK");
+
+               if (len[0]) {
+                       addr[0] = (u8 *) tests[i].data;
+                       len[0] = 1;
+                       addr[1] = (u8 *) tests[i].data + 1;
+                       len[1] = strlen(tests[i].data) - 1;
+                       sha256_vector(2, addr, len, hash);
+                       if (memcmp(hash, tests[i].hash, 32) != 0) {
+                               printf(" FAIL");
+                               errors++;
+                       } else
+                               printf(" OK");
+               }
+
+               printf("\n");
+       }
+
+       for (i = 0; i < sizeof(hmac_tests) / sizeof(hmac_tests[0]); i++) {
+               struct hmac_test *t = &hmac_tests[i];
+               printf("HMAC-SHA256 test case %d:", i + 1);
+
+               hmac_sha256(t->key, t->key_len, t->data, t->data_len, hash);
+               if (memcmp(hash, t->hash, 32) != 0) {
+                       printf(" FAIL");
+                       errors++;
+               } else
+                       printf(" OK");
+
+               addr[0] = t->data;
+               len[0] = t->data_len;
+               hmac_sha256_vector(t->key, t->key_len, 1, addr, len, hash);
+               if (memcmp(hash, t->hash, 32) != 0) {
+                       printf(" FAIL");
+                       errors++;
+               } else
+                       printf(" OK");
+
+               if (len[0]) {
+                       addr[0] = t->data;
+                       len[0] = 1;
+                       addr[1] = t->data + 1;
+                       len[1] = t->data_len - 1;
+                       hmac_sha256_vector(t->key, t->key_len, 2, addr, len,
+                                          hash);
+                       if (memcmp(hash, t->hash, 32) != 0) {
+                               printf(" FAIL");
+                               errors++;
+                       } else
+                               printf(" OK");
+               }
+
+               printf("\n");
+       }
+
+       printf("Test IEEE 802.11r KDF\n");
+       sha256_prf((u8 *) "abc", 3, "KDF test", (u8 *) "data", 4,
+                  hash, sizeof(hash));
+       /* TODO: add proper test case for this */
+
+       return errors;
+}
diff --git a/tests/test-x509.c b/tests/test-x509.c
new file mode 100644 (file)
index 0000000..96181c2
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "tls/x509v3.h"
+
+extern int wpa_debug_level;
+
+
+int main(int argc, char *argv[])
+{
+       FILE *f;
+       u8 buf[3000];
+       size_t len;
+       struct x509_certificate *cert;
+
+       wpa_debug_level = 0;
+
+       f = fopen(argv[1], "rb");
+       if (f == NULL)
+               return -1;
+       len = fread(buf, 1, sizeof(buf), f);
+       fclose(f);
+
+       cert = x509_certificate_parse(buf, len);
+       if (cert == NULL)
+               printf("Failed to parse X.509 certificate\n");
+       x509_certificate_free(cert);
+
+       return 0;
+}
diff --git a/tests/test-x509v3.c b/tests/test-x509v3.c
new file mode 100644 (file)
index 0000000..6943efc
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "tls/asn1.h"
+#include "tls/x509v3.h"
+
+extern int wpa_debug_level;
+
+
+int main(int argc, char *argv[])
+{
+       char *buf;
+       size_t len;
+       struct x509_certificate *certs = NULL, *last = NULL, *cert;
+       int i, reason;
+
+       wpa_debug_level = 0;
+
+       if (argc < 3 || strcmp(argv[1], "-v") != 0) {
+               printf("usage: test_x509v3 -v <cert1.der> <cert2.der> ..\n");
+               return -1;
+       }
+
+       for (i = 2; i < argc; i++) {
+               printf("Reading: %s\n", argv[i]);
+               buf = os_readfile(argv[i], &len);
+               if (buf == NULL) {
+                       printf("Failed to read '%s'\n", argv[i]);
+                       return -1;
+               }
+
+               cert = x509_certificate_parse((u8 *) buf, len);
+               if (cert == NULL) {
+                       printf("Failed to parse X.509 certificate\n");
+                       return -1;
+               }
+
+               free(buf);
+
+               if (certs == NULL)
+                       certs = cert;
+               else
+                       last->next = cert;
+               last = cert;
+       }
+
+       printf("\n\nValidating certificate chain\n");
+       if (x509_certificate_chain_validate(last, certs, &reason, 0) < 0) {
+               printf("\nCertificate chain validation failed: %d\n", reason);
+               return -1;
+       }
+       printf("\nCertificate chain is valid\n");
+
+       return 0;
+}
diff --git a/tests/test_x509v3_nist.sh b/tests/test_x509v3_nist.sh
new file mode 100755 (executable)
index 0000000..d3f94bb
--- /dev/null
@@ -0,0 +1,144 @@
+#!/bin/bash
+
+# X.509 Path Validation Test Suite, Version 1.07
+# http://csrc.nist.gov/pki/testing/x509paths_old.html
+# http://csrc.nist.gov/pki/testing/x509tests.tgz
+
+if [ -z "$1" ]; then
+    echo "usage: $0 <path to X509tests directory>"
+    exit 1
+fi
+
+TESTS=$1
+
+if [ ! -d $TESTS ]; then
+    echo "Not a directory: $TESTS"
+    exit 1
+fi
+
+X509TEST="./test-x509v3 -v"
+TMPOUT=test_x509v3_nist.out
+
+# TODO: add support for validating CRLs
+
+END="End Certificate "
+ROOT="Trust Anchor "
+ICA="Intermediate Certificate "
+
+SUCCESS=""
+FAILURE=""
+
+function run_test
+{
+    NUM=$1
+    RES=$2
+    shift 2
+    $X509TEST "$@" > $TMPOUT.$NUM
+    VALRES=$?
+    OK=0
+    if [ $RES -eq 0 ]; then
+       # expecting success
+       if [ $VALRES -eq 0 ]; then
+           OK=1
+       else
+           echo "test$NUM failed - expected validation success"
+           OK=0
+       fi
+    else
+       # expecting failure
+       if [ $VALRES -eq 0 ]; then
+           echo "test$NUM failed - expected validation failure"
+           OK=0
+       else
+           REASON=`grep "Certificate chain validation failed: " $TMPOUT.$NUM`
+           if [ $? -eq 0 ]; then
+               REASONNUM=`echo "$REASON" | colrm 1 37`
+               if [ $REASONNUM -eq $RES ]; then
+                   OK=1
+               else
+                   echo "test$NUM failed - expected validation result $RES; result was $REASONNUM"
+                   OK=0
+               fi
+           else
+               echo "test$NUM failed - expected validation failure; other type of error detected"
+               OK=0
+           fi
+       fi
+    fi
+    if [ $OK -eq 1 ]; then
+       rm $TMPOUT.$NUM
+       SUCCESS="$SUCCESS $NUM"
+    else
+       FAILURE="$FAILURE $NUM"
+    fi
+}
+
+P=$TESTS/test
+
+run_test 1 0 "${P}1/${END}CP.01.01.crt" "${P}1/${ROOT}CP.01.01.crt"
+run_test 2 1 "${P}2/${END}CP.01.02.crt" "${P}2/${ICA}CP.01.02.crt" "${P}2/${ROOT}CP.01.01.crt"
+run_test 3 1 "${P}3/${END}CP.01.03.crt" "${P}3/${ICA}CP.01.03.crt" "${P}3/${ROOT}CP.01.01.crt"
+run_test 4 0 "${P}4/${END}CP.02.01.crt" "${P}4/${ICA}2 CP.02.01.crt" "${P}4/${ICA}1 CP.02.01.crt" "${P}4/${ROOT}CP.01.01.crt"
+run_test 5 4 "${P}5/${END}CP.02.02.crt" "${P}5/${ICA}CP.02.02.crt" "${P}5/${ROOT}CP.01.01.crt"
+run_test 6 4 "${P}6/${END}CP.02.03.crt" "${P}6/${ICA}CP.02.03.crt" "${P}6/${ROOT}CP.01.01.crt"
+run_test 7 0 "${P}7/${END}CP.02.04.crt" "${P}7/${ICA}CP.02.04.crt" "${P}7/${ROOT}CP.01.01.crt"
+run_test 8 4 "${P}8/${END}CP.02.05.crt" "${P}8/${ICA}CP.02.05.crt" "${P}8/${ROOT}CP.01.01.crt"
+run_test 9 4 "${P}9/${END}CP.03.01.crt" "${P}9/${ICA}CP.03.01.crt" "${P}9/${ROOT}CP.01.01.crt"
+run_test 10 4 "${P}10/${END}CP.03.02.crt" "${P}10/${ICA}CP.03.02.crt" "${P}10/${ROOT}CP.01.01.crt"
+run_test 11 4 "${P}11/${END}CP.03.03.crt" "${P}11/${ICA}CP.03.03.crt" "${P}11/${ROOT}CP.01.01.crt"
+run_test 12 0 "${P}12/${END}CP.03.04.crt" "${P}12/${ICA}CP.03.04.crt" "${P}12/${ROOT}CP.01.01.crt"
+run_test 13 5 "${P}13/${END}CP.04.01.crt" "${P}13/${ICA}CP.04.01.crt" "${P}13/${ROOT}CP.01.01.crt"
+run_test 14 5 "${P}14/${END}CP.04.02.crt" "${P}14/${ICA}CP.04.02.crt" "${P}14/${ROOT}CP.01.01.crt"
+run_test 15 0 "${P}15/${END}CP.04.03.crt" "${P}15/${ICA}CP.04.03.crt" "${P}15/${ROOT}CP.01.01.crt"
+run_test 16 0 "${P}16/${END}CP.04.04.crt" "${P}16/${ICA}CP.04.04.crt" "${P}16/${ROOT}CP.01.01.crt"
+run_test 17 0 "${P}17/${END}CP.04.05.crt" "${P}17/${ICA}CP.04.05.crt" "${P}17/${ROOT}CP.01.01.crt"
+run_test 18 0 "${P}18/${END}CP.04.06.crt" "${P}18/${ICA}CP.04.06.crt" "${P}18/${ROOT}CP.01.01.crt"
+run_test 19 1 "${P}19/${END}CP.05.01.crt" "${P}19/${ICA}CP.05.01.crt" "${P}19/${ROOT}CP.01.01.crt"
+run_test 20 3 "${P}20/${END}CP.06.01.crt" "${P}20/${ICA}CP.06.01.crt" "${P}20/${ROOT}CP.01.01.crt"
+run_test 21 3 "${P}21/${END}CP.06.02.crt" "${P}21/${ICA}CP.06.02.crt" "${P}21/${ROOT}CP.01.01.crt"
+run_test 22 1 "${P}22/${END}IC.01.01.crt" "${P}22/${ICA}IC.01.01.crt" "${P}22/${ROOT}CP.01.01.crt"
+run_test 23 1 "${P}23/${END}IC.02.01.crt" "${P}23/${ICA}IC.02.01.crt" "${P}23/${ROOT}CP.01.01.crt"
+run_test 24 0 "${P}24/${END}IC.02.02.crt" "${P}24/${ICA}IC.02.02.crt" "${P}24/${ROOT}CP.01.01.crt"
+run_test 25 1 "${P}25/${END}IC.02.03.crt" "${P}25/${ICA}IC.02.03.crt" "${P}25/${ROOT}CP.01.01.crt"
+run_test 26 0 "${P}26/${END}IC.02.04.crt" "${P}26/${ICA}IC.02.04.crt" "${P}26/${ROOT}CP.01.01.crt"
+run_test 27 0 "${P}27/${END}IC.04.01.crt" "${P}27/${ICA}IC.04.01.crt" "${P}27/${ROOT}CP.01.01.crt"
+run_test 28 1 "${P}28/${END}IC.05.01.crt" "${P}28/${ICA}IC.05.01.crt" "${P}28/${ROOT}CP.01.01.crt"
+run_test 29 1 "${P}29/${END}IC.05.02.crt" "${P}29/${ICA}IC.05.02.crt" "${P}29/${ROOT}CP.01.01.crt"
+run_test 30 0 "${P}30/${END}IC.05.03.crt" "${P}30/${ICA}IC.05.03.crt" "${P}30/${ROOT}CP.01.01.crt"
+run_test 31 1 "${P}31/${END}IC.06.01.crt" "${P}31/${ICA}IC.06.01.crt" "${P}31/${ROOT}CP.01.01.crt"
+run_test 32 1 "${P}32/${END}IC.06.02.crt" "${P}32/${ICA}IC.06.02.crt" "${P}32/${ROOT}CP.01.01.crt"
+run_test 33 0 "${P}33/${END}IC.06.03.crt" "${P}33/${ICA}IC.06.03.crt" "${P}33/${ROOT}CP.01.01.crt"
+run_test 34 0 "${P}34/${END}PP.01.01.crt" "${P}34/${ICA}PP.01.01.crt" "${P}34/${ROOT}CP.01.01.crt"
+run_test 35 0 "${P}35/${END}PP.01.02.crt" "${P}35/${ICA}PP.01.02.crt" "${P}35/${ROOT}CP.01.01.crt"
+run_test 36 0 "${P}36/${END}PP.01.03.crt" "${P}36/${ICA}2 PP.01.03.crt" "${P}36/${ICA}1 PP.01.03.crt" "${P}36/${ROOT}CP.01.01.crt"
+run_test 37 0 "${P}37/${END}PP.01.04.crt" "${P}37/${ICA}2 PP.01.04.crt" "${P}37/${ICA}1 PP.01.04.crt" "${P}37/${ROOT}CP.01.01.crt"
+run_test 38 0 "${P}38/${END}PP.01.05.crt" "${P}38/${ICA}2 PP.01.05.crt" "${P}38/${ICA}1 PP.01.05.crt" "${P}38/${ROOT}CP.01.01.crt"
+run_test 39 0 "${P}39/${END}PP.01.06.crt" "${P}39/${ICA}3 PP.01.06.crt" "${P}39/${ICA}2 PP.01.06.crt" "${P}39/${ICA}1 PP.01.06.crt" "${P}39/${ROOT}CP.01.01.crt"
+run_test 40 0 "${P}40/${END}PP.01.07.crt" "${P}40/${ICA}3 PP.01.07.crt" "${P}40/${ICA}2 PP.01.07.crt" "${P}40/${ICA}1 PP.01.07.crt" "${P}40/${ROOT}CP.01.01.crt"
+run_test 41 0 "${P}41/${END}PP.01.08.crt" "${P}41/${ICA}3 PP.01.08.crt" "${P}41/${ICA}2 PP.01.08.crt" "${P}41/${ICA}1 PP.01.08.crt" "${P}41/${ROOT}CP.01.01.crt"
+run_test 42 0 "${P}42/${END}PP.01.09.crt" "${P}42/${ICA}4 PP.01.09.crt" "${P}42/${ICA}3 PP.01.09.crt" "${P}42/${ICA}2 PP.01.09.crt" "${P}42/${ICA}1 PP.01.09.crt" "${P}42/${ROOT}CP.01.01.crt"
+run_test 43 0 "${P}43/${END}PP.06.01.crt" "${P}43/${ICA}4 PP.06.01.crt" "${P}43/${ICA}3 PP.06.01.crt" "${P}43/${ICA}2 PP.06.01.crt" "${P}43/${ICA}1 PP.06.01.crt" "${P}43/${ROOT}CP.01.01.crt"
+run_test 44 0 "${P}44/${END}PP.06.02.crt" "${P}44/${ICA}4 PP.06.02.crt" "${P}44/${ICA}3 PP.06.02.crt" "${P}44/${ICA}2 PP.06.02.crt" "${P}44/${ICA}1 PP.06.02.crt" "${P}44/${ROOT}CP.01.01.crt"
+run_test 45 0 "${P}45/${END}PP.06.03.crt" "${P}45/${ICA}4 PP.06.03.crt" "${P}45/${ICA}3 PP.06.03.crt" "${P}45/${ICA}2 PP.06.03.crt" "${P}45/${ICA}1 PP.06.03.crt" "${P}45/${ROOT}CP.01.01.crt"
+run_test 46 0 "${P}46/${END}PP.06.04.crt" "${P}46/${ICA}4 PP.06.04.crt" "${P}46/${ICA}3 PP.06.04.crt" "${P}46/${ICA}2 PP.06.04.crt" "${P}46/${ICA}1 PP.06.04.crt" "${P}46/${ROOT}CP.01.01.crt"
+run_test 47 0 "${P}47/${END}PP.06.05.crt" "${P}47/${ICA}4 PP.06.05.crt" "${P}47/${ICA}3 PP.06.05.crt" "${P}47/${ICA}2 PP.06.05.crt" "${P}47/${ICA}1 PP.06.05.crt" "${P}47/${ROOT}CP.01.01.crt"
+run_test 48 0 "${P}48/${END}PP.08.01.crt" "${P}48/${ICA}PP.08.01.crt" "${P}48/${ROOT}CP.01.01.crt"
+run_test 49 0 "${P}49/${END}PP.08.02.crt" "${P}49/${ICA}PP.08.02.crt" "${P}49/${ROOT}CP.01.01.crt"
+run_test 50 0 "${P}50/${END}PP.08.03.crt" "${P}50/${ICA}PP.08.03.crt" "${P}50/${ROOT}CP.01.01.crt"
+run_test 51 0 "${P}51/${END}PP.08.04.crt" "${P}51/${ICA}PP.08.04.crt" "${P}51/${ROOT}CP.01.01.crt"
+run_test 52 0 "${P}52/${END}PP.08.05.crt" "${P}52/${ICA}PP.08.05.crt" "${P}52/${ROOT}CP.01.01.crt"
+run_test 53 0 "${P}53/${END}PP.08.06.crt" "${P}53/${ICA}PP.08.06.crt" "${P}53/${ROOT}CP.01.01.crt"
+run_test 54 1 "${P}54/${END}PL.01.01.crt" "${P}54/${ICA}2 PL.01.01.crt" "${P}54/${ICA}1 PL.01.01.crt" "${P}54/${ROOT}CP.01.01.crt"
+run_test 55 1 "${P}55/${END}PL.01.02.crt" "${P}55/${ICA}2 PL.01.02.crt" "${P}55/${ICA}1 PL.01.02.crt" "${P}55/${ROOT}CP.01.01.crt"
+run_test 56 0 "${P}56/${END}PL.01.03.crt" "${P}56/${ICA}PL.01.03.crt" "${P}56/${ROOT}CP.01.01.crt"
+run_test 57 0 "${P}57/${END}PL.01.04.crt" "${P}57/${ICA}PL.01.04.crt" "${P}57/${ROOT}CP.01.01.crt"
+run_test 58 1 "${P}58/${END}PL.01.05.crt" "${P}58/${ICA}3 PL.01.05.crt" "${P}58/${ICA}2 PL.01.05.crt" "${P}58/${ICA}1 PL.01.05.crt" "${P}58/${ROOT}CP.01.01.crt"
+run_test 59 1 "${P}59/${END}PL.01.06.crt" "${P}59/${ICA}3 PL.01.06.crt" "${P}59/${ICA}2 PL.01.06.crt" "${P}59/${ICA}1 PL.01.06.crt" "${P}59/${ROOT}CP.01.01.crt"
+run_test 60 1 "${P}60/${END}PL.01.07.crt" "${P}60/${ICA}4 PL.01.07.crt" "${P}60/${ICA}3 PL.01.07.crt" "${P}60/${ICA}2 PL.01.07.crt" "${P}60/${ICA}1 PL.01.07.crt" "${P}60/${ROOT}CP.01.01.crt"
+run_test 61 1 "${P}61/${END}PL.01.08.crt" "${P}61/${ICA}4 PL.01.08.crt" "${P}61/${ICA}3 PL.01.08.crt" "${P}61/${ICA}2 PL.01.08.crt" "${P}61/${ICA}1 PL.01.08.crt" "${P}61/${ROOT}CP.01.01.crt"
+run_test 62 0 "${P}62/${END}PL.01.09.crt" "${P}62/${ICA}4 PL.01.09.crt" "${P}62/${ICA}3 PL.01.09.crt" "${P}62/${ICA}2 PL.01.09.crt" "${P}62/${ICA}1 PL.01.09.crt" "${P}62/${ROOT}CP.01.01.crt"
+run_test 63 0 "${P}63/${END}PL.01.10.crt" "${P}63/${ICA}4 PL.01.10.crt" "${P}63/${ICA}3 PL.01.10.crt" "${P}63/${ICA}2 PL.01.10.crt" "${P}63/${ICA}1 PL.01.10.crt" "${P}63/${ROOT}CP.01.01.crt"
+
+
+echo "Successful tests:$SUCCESS"
+echo "Failed tests:$FAILURE"
diff --git a/tests/test_x509v3_nist2.sh b/tests/test_x509v3_nist2.sh
new file mode 100755 (executable)
index 0000000..572bd9d
--- /dev/null
@@ -0,0 +1,165 @@
+#!/bin/bash
+
+# Public Key Interoperability Test Suite (PKITS)
+# http://csrc.nist.gov/pki/testing/x509paths.html
+# http://csrc.nist.gov/groups/ST/crypto_apps_infra/documents/PKITS_data.zip
+
+if [ -z "$1" ]; then
+    echo "usage: $0 <path to root test directory>"
+    exit 1
+fi
+
+TESTS=$1
+
+if [ ! -d $TESTS ]; then
+    echo "Not a directory: $TESTS"
+    exit 1
+fi
+
+X509TEST="$PWD/test-x509v3 -v"
+TMPOUT="$PWD/test_x509v3_nist2.out"
+
+# TODO: add support for validating CRLs
+
+SUCCESS=""
+FAILURE=""
+
+function run_test
+{
+    NUM=$1
+    RES=$2
+    shift 2
+    $X509TEST "$@" TrustAnchorRootCertificate.crt > $TMPOUT.$NUM
+    VALRES=$?
+    OK=0
+    if [ $RES -eq 0 ]; then
+       # expecting success
+       if [ $VALRES -eq 0 ]; then
+           OK=1
+       else
+           echo "$NUM failed - expected validation success"
+           OK=0
+       fi
+    else
+       # expecting failure
+       if [ $VALRES -eq 0 ]; then
+           echo "$NUM failed - expected validation failure"
+           OK=0
+       else
+           REASON=`grep "Certificate chain validation failed: " $TMPOUT.$NUM`
+           if [ $? -eq 0 ]; then
+               REASONNUM=`echo "$REASON" | colrm 1 37`
+               if [ $REASONNUM -eq $RES ]; then
+                   OK=1
+               else
+                   echo "$NUM failed - expected validation result $RES; result was $REASONNUM"
+                   OK=0
+               fi
+           else
+               echo "$NUM failed - expected validation failure; other type of error detected"
+               OK=0
+           fi
+       fi
+    fi
+    if [ $OK -eq 1 ]; then
+       rm $TMPOUT.$NUM
+       SUCCESS="$SUCCESS $NUM"
+    else
+       FAILURE="$FAILURE $NUM"
+    fi
+}
+
+pushd $TESTS/certs
+
+run_test 4.1.1 0 ValidCertificatePathTest1EE.crt GoodCACert.crt
+run_test 4.1.2 1 InvalidCASignatureTest2EE.crt BadSignedCACert.crt
+run_test 4.1.3 1 InvalidEESignatureTest3EE.crt GoodCACert.crt
+
+run_test 4.2.1 4 InvalidCAnotBeforeDateTest1EE.crt BadnotBeforeDateCACert.crt
+run_test 4.2.2 4 InvalidEEnotBeforeDateTest2EE.crt GoodCACert.crt
+run_test 4.2.3 0 Validpre2000UTCnotBeforeDateTest3EE.crt GoodCACert.crt
+run_test 4.2.4 0 ValidGeneralizedTimenotBeforeDateTest4EE.crt GoodCACert.crt
+run_test 4.2.5 4 InvalidCAnotAfterDateTest5EE.crt BadnotAfterDateCACert.crt
+run_test 4.2.6 4 InvalidEEnotAfterDateTest6EE.crt GoodCACert.crt
+run_test 4.2.7 4 Invalidpre2000UTCEEnotAfterDateTest7EE.crt GoodCACert.crt
+run_test 4.2.8 0 ValidGeneralizedTimenotAfterDateTest8EE.crt GoodCACert.crt
+
+run_test 4.3.1 5 InvalidNameChainingTest1EE.crt GoodCACert.crt
+run_test 4.3.2 5 InvalidNameChainingOrderTest2EE.crt NameOrderingCACert.crt
+run_test 4.3.3 0 ValidNameChainingWhitespaceTest3EE.crt GoodCACert.crt
+run_test 4.3.4 0 ValidNameChainingWhitespaceTest4EE.crt GoodCACert.crt
+run_test 4.3.5 0 ValidNameChainingCapitalizationTest5EE.crt GoodCACert.crt
+run_test 4.3.6 0 ValidNameUIDsTest6EE.crt UIDCACert.crt
+run_test 4.3.7 0 ValidRFC3280MandatoryAttributeTypesTest7EE.crt RFC3280MandatoryAttributeTypesCACert.crt
+run_test 4.3.8 0 ValidRFC3280OptionalAttributeTypesTest8EE.crt RFC3280OptionalAttributeTypesCACert.crt
+run_test 4.3.9 0 ValidUTF8StringEncodedNamesTest9EE.crt UTF8StringEncodedNamesCACert.crt
+run_test 4.3.10 0 ValidRolloverfromPrintableStringtoUTF8StringTest10EE.crt RolloverfromPrintableStringtoUTF8StringCACert.crt
+run_test 4.3.11 0 ValidUTF8StringCaseInsensitiveMatchTest11EE.crt UTF8StringCaseInsensitiveMatchCACert.crt
+
+run_test 4.4.1 1 InvalidMissingCRLTest1EE.crt NoCRLCACert.crt
+# skip rest of 4.4.x tests since CRLs are not yet supported
+
+run_test 4.5.1 0 ValidBasicSelfIssuedOldWithNewTest1EE.crt BasicSelfIssuedNewKeyOldWithNewCACert.crt BasicSelfIssuedNewKeyCACert.crt
+run_test 4.5.2 3 InvalidBasicSelfIssuedOldWithNewTest2EE.crt BasicSelfIssuedNewKeyOldWithNewCACert.crt BasicSelfIssuedNewKeyCACert.crt
+run_test 4.5.3 0 ValidBasicSelfIssuedNewWithOldTest3EE.crt BasicSelfIssuedOldKeyNewWithOldCACert.crt BasicSelfIssuedOldKeyCACert.crt
+run_test 4.5.4 0 ValidBasicSelfIssuedNewWithOldTest4EE.crt BasicSelfIssuedOldKeyNewWithOldCACert.crt BasicSelfIssuedOldKeyCACert.crt
+run_test 4.5.5 3 InvalidBasicSelfIssuedNewWithOldTest5EE.crt BasicSelfIssuedOldKeyNewWithOldCACert.crt BasicSelfIssuedOldKeyCACert.crt
+run_test 4.5.6 0 ValidBasicSelfIssuedCRLSigningKeyTest6EE.crt BasicSelfIssuedCRLSigningKeyCRLCert.crt BasicSelfIssuedCRLSigningKeyCACert.crt
+run_test 4.5.7 3 InvalidBasicSelfIssuedCRLSigningKeyTest7EE.crt BasicSelfIssuedCRLSigningKeyCRLCert.crt BasicSelfIssuedCRLSigningKeyCACert.crt
+run_test 4.5.8 1 InvalidBasicSelfIssuedCRLSigningKeyTest8EE.crt BasicSelfIssuedCRLSigningKeyCRLCert.crt BasicSelfIssuedCRLSigningKeyCACert.crt
+
+run_test 4.6.1 1 InvalidMissingbasicConstraintsTest1EE.crt MissingbasicConstraintsCACert.crt
+run_test 4.6.2 1 InvalidcAFalseTest2EE.crt basicConstraintsCriticalcAFalseCACert.crt
+run_test 4.6.3 1 InvalidcAFalseTest3EE.crt basicConstraintsNotCriticalcAFalseCACert.crt
+run_test 4.6.4 0 ValidbasicConstraintsNotCriticalTest4EE.crt basicConstraintsNotCriticalCACert.crt
+run_test 4.6.5 1 InvalidpathLenConstraintTest5EE.crt pathLenConstraint0subCACert.crt pathLenConstraint0CACert.crt
+run_test 4.6.6 1 InvalidpathLenConstraintTest6EE.crt pathLenConstraint0subCACert.crt pathLenConstraint0CACert.crt
+run_test 4.6.7 0 ValidpathLenConstraintTest7EE.crt pathLenConstraint0CACert.crt
+run_test 4.6.8 0 ValidpathLenConstraintTest8EE.crt pathLenConstraint0CACert.crt
+run_test 4.6.9 1 InvalidpathLenConstraintTest9EE.crt pathLenConstraint6subsubCA00Cert.crt pathLenConstraint6subCA0Cert.crt pathLenConstraint6CACert.crt
+run_test 4.6.10 1 InvalidpathLenConstraintTest10EE.crt pathLenConstraint6subsubCA00Cert.crt pathLenConstraint6subCA0Cert.crt pathLenConstraint6CACert.crt
+run_test 4.6.11 1 InvalidpathLenConstraintTest11EE.crt pathLenConstraint6subsubsubCA11XCert.crt pathLenConstraint6subsubCA11Cert.crt pathLenConstraint6subCA1Cert.crt pathLenConstraint6CACert.crt
+run_test 4.6.12 1 InvalidpathLenConstraintTest12EE.crt pathLenConstraint6subsubsubCA11XCert.crt pathLenConstraint6subsubCA11Cert.crt pathLenConstraint6subCA1Cert.crt pathLenConstraint6CACert.crt
+run_test 4.6.13 0 ValidpathLenConstraintTest13EE.crt pathLenConstraint6subsubsubCA41XCert.crt pathLenConstraint6subsubCA41Cert.crt pathLenConstraint6subCA4Cert.crt pathLenConstraint6CACert.crt
+run_test 4.6.14 0 ValidpathLenConstraintTest14EE.crt pathLenConstraint6subsubsubCA41XCert.crt pathLenConstraint6subsubCA41Cert.crt pathLenConstraint6subCA4Cert.crt pathLenConstraint6CACert.crt
+run_test 4.6.15 0 ValidSelfIssuedpathLenConstraintTest15EE.crt pathLenConstraint0SelfIssuedCACert.crt pathLenConstraint0CACert.crt
+run_test 4.6.16 1 InvalidSelfIssuedpathLenConstraintTest16EE.crt pathLenConstraint0subCA2Cert.crt pathLenConstraint0SelfIssuedCACert.crt pathLenConstraint0CACert.crt
+run_test 4.6.17 0 ValidSelfIssuedpathLenConstraintTest17EE.crt pathLenConstraint1SelfIssuedsubCACert.crt pathLenConstraint1subCACert.crt pathLenConstraint1SelfIssuedCACert.crt pathLenConstraint1CACert.crt
+
+run_test 4.7.1 1 InvalidkeyUsageCriticalkeyCertSignFalseTest1EE.crt keyUsageCriticalkeyCertSignFalseCACert.crt
+run_test 4.7.2 1 InvalidkeyUsageNotCriticalkeyCertSignFalseTest2EE.crt keyUsageNotCriticalkeyCertSignFalseCACert.crt
+run_test 4.7.3 0 ValidkeyUsageNotCriticalTest3EE.crt keyUsageNotCriticalCACert.crt
+run_test 4.7.4 1 InvalidkeyUsageCriticalcRLSignFalseTest4EE.crt keyUsageCriticalcRLSignFalseCACert.crt
+run_test 4.7.5 1 InvalidkeyUsageNotCriticalcRLSignFalseTest5EE.crt keyUsageNotCriticalcRLSignFalseCACert.crt
+
+run_test 4.8.1 0 ValidCertificatePathTest1EE.crt GoodCACert.crt
+run_test 4.8.2 0 AllCertificatesNoPoliciesTest2EE.crt NoPoliciesCACert.crt
+run_test 4.8.3 0 DifferentPoliciesTest3EE.crt PoliciesP2subCACert.crt GoodCACert.crt
+run_test 4.8.4 0 DifferentPoliciesTest4EE.crt GoodsubCACert.crt GoodCACert.crt
+run_test 4.8.5 0 DifferentPoliciesTest5EE.crt PoliciesP2subCA2Cert.crt GoodCACert.crt
+run_test 4.8.6 0 OverlappingPoliciesTest6EE.crt PoliciesP1234subsubCAP123P12Cert.crt PoliciesP1234subCAP123Cert.crt PoliciesP1234CACert.crt
+run_test 4.8.7 0 DifferentPoliciesTest7EE.crt PoliciesP123subsubCAP12P1Cert.crt PoliciesP123subCAP12Cert.crt PoliciesP123CACert.crt
+run_test 4.8.8 0 DifferentPoliciesTest8EE.crt PoliciesP12subsubCAP1P2Cert.crt PoliciesP12subCAP1Cert.crt PoliciesP12CACert.crt
+run_test 4.8.9 0 DifferentPoliciesTest9EE.crt PoliciesP123subsubsubCAP12P2P1Cert.crt PoliciesP123subsubCAP12P2Cert.crt PoliciesP123subCAP12Cert.crt PoliciesP123CACert.crt
+run_test 4.8.10 0 AllCertificatesSamePoliciesTest10EE.crt PoliciesP12CACert.crt
+run_test 4.8.11 0 AllCertificatesanyPolicyTest11EE.crt anyPolicyCACert.crt
+run_test 4.8.12 0 DifferentPoliciesTest12EE.crt PoliciesP3CACert.crt
+run_test 4.8.13 0 AllCertificatesSamePoliciesTest13EE.crt PoliciesP123CACert.crt
+run_test 4.8.14 0 AnyPolicyTest14EE.crt anyPolicyCACert.crt
+run_test 4.8.15 0 UserNoticeQualifierTest15EE.crt
+run_test 4.8.16 0 UserNoticeQualifierTest16EE.crt GoodCACert.crt
+run_test 4.8.17 0 UserNoticeQualifierTest17EE.crt GoodCACert.crt
+run_test 4.8.18 0 UserNoticeQualifierTest18EE.crt PoliciesP12CACert.crt
+run_test 4.8.19 0 UserNoticeQualifierTest19EE.crt TrustAnchorRootCertificate.crt
+run_test 4.8.20 0 CPSPointerQualifierTest20EE.crt GoodCACert.crt
+
+if false; then
+# DSA tests
+run_test 4.1.4 0 ValidDSASignaturesTest4EE.crt DSACACert.crt
+fi
+
+popd
+
+
+echo "Successful tests:$SUCCESS"
+echo "Failed tests:$FAILURE"
diff --git a/wlantest/Makefile b/wlantest/Makefile
new file mode 100644 (file)
index 0000000..c165ed4
--- /dev/null
@@ -0,0 +1,111 @@
+ALL=wlantest wlantest_cli
+
+all: $(ALL)
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef RANLIB
+RANLIB=ranlib
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+
+CFLAGS += -I.
+CFLAGS += -I../src
+CFLAGS += -I../src/utils
+
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+Q=@
+E=echo
+ifeq ($(V), 1)
+Q=
+E=true
+endif
+
+%.o: %.c
+       $(Q)$(CC) -c -o $@ $(CFLAGS) $<
+       @$(E) "  CC " $<
+
+
+OBJS_lib += ../src/utils/libutils.a
+OBJS_lib += ../src/crypto/libcrypto.a
+
+CFLAGS += -DCONFIG_PEERKEY
+CFLAGS += -DCONFIG_IEEE80211W
+CFLAGS += -DCONFIG_IEEE80211R
+
+OBJS += ../src/common/ieee802_11_common.o
+OBJS += ../src/common/wpa_common.o
+OBJS += ../src/radius/radius.o
+OBJS += ../src/rsn_supp/wpa_ie.o
+
+OBJS += wlantest.o
+OBJS += readpcap.o
+OBJS += writepcap.o
+OBJS += monitor.o
+OBJS += process.o
+OBJS += wired.o
+OBJS += rx_mgmt.o
+OBJS += rx_data.o
+OBJS += rx_eapol.o
+OBJS += rx_ip.o
+OBJS += rx_tdls.o
+OBJS += bss.o
+OBJS += sta.o
+OBJS += crc32.o
+OBJS += ccmp.o
+OBJS += tkip.o
+OBJS += ctrl.o
+OBJS += inject.o
+OBJS += wep.o
+
+LIBS += -lpcap
+
+
+../src/utils/libutils.a:
+       $(MAKE) -C ../src/utils
+
+../src/crypto/libcrypto.a:
+       $(MAKE) -C ../src/crypto
+
+
+ifneq ($(CONFIG_SOLIB), yes)
+LIBWLANTEST = libwlantest.a
+libwlantest.a: $(OBJS_lib)
+       $(AR) crT libwlantest.a $(OBJS_lib)
+       $(RANLIB) libwlantest.a
+
+else
+CFLAGS  += -fPIC -DPIC
+LDFLAGS += -shared
+
+LIBWLANTEST  = libwlantest.so
+libwlantest.so: $(OBJS_lib)
+       $(LDO) $(LDFLAGS) $(OBJS_lib) -o $(LIBWLANTEST)
+
+endif
+
+
+OBJS_cli = wlantest_cli.o
+
+
+wlantest: $(OBJS) $(LIBWLANTEST)
+       $(LDO) $(LDFLAGS) -o wlantest $(OBJS) -L. -lwlantest $(LIBS)
+
+wlantest_cli: $(OBJS_cli) $(LIBWLANTEST)
+       $(LDO) $(LDFLAGS) -o wlantest_cli $(OBJS_cli) -L. -lwlantest
+
+clean:
+       $(MAKE) -C ../src clean
+       rm -f core *~ *.o *.d libwlantest.a libwlantest.so $(ALL)
+
+-include $(OBJS:%.o=%.d)
diff --git a/wlantest/bss.c b/wlantest/bss.c
new file mode 100644 (file)
index 0000000..34dee50
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/defs.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "crypto/sha1.h"
+#include "wlantest.h"
+
+
+struct wlantest_bss * bss_find(struct wlantest *wt, const u8 *bssid)
+{
+       struct wlantest_bss *bss;
+
+       dl_list_for_each(bss, &wt->bss, struct wlantest_bss, list) {
+               if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
+                       return bss;
+       }
+
+       return NULL;
+}
+
+
+struct wlantest_bss * bss_get(struct wlantest *wt, const u8 *bssid)
+{
+       struct wlantest_bss *bss;
+
+       if (bssid[0] & 0x01)
+               return NULL; /* Skip group addressed frames */
+
+       bss = bss_find(wt, bssid);
+       if (bss)
+               return bss;
+
+       bss = os_zalloc(sizeof(*bss));
+       if (bss == NULL)
+               return NULL;
+       dl_list_init(&bss->sta);
+       dl_list_init(&bss->pmk);
+       dl_list_init(&bss->tdls);
+       os_memcpy(bss->bssid, bssid, ETH_ALEN);
+       dl_list_add(&wt->bss, &bss->list);
+       wpa_printf(MSG_DEBUG, "Discovered new BSS - " MACSTR,
+                  MAC2STR(bss->bssid));
+       return bss;
+}
+
+
+void pmk_deinit(struct wlantest_pmk *pmk)
+{
+       dl_list_del(&pmk->list);
+       os_free(pmk);
+}
+
+
+void tdls_deinit(struct wlantest_tdls *tdls)
+{
+       dl_list_del(&tdls->list);
+       os_free(tdls);
+}
+
+
+void bss_deinit(struct wlantest_bss *bss)
+{
+       struct wlantest_sta *sta, *n;
+       struct wlantest_pmk *pmk, *np;
+       struct wlantest_tdls *tdls, *nt;
+       dl_list_for_each_safe(sta, n, &bss->sta, struct wlantest_sta, list)
+               sta_deinit(sta);
+       dl_list_for_each_safe(pmk, np, &bss->pmk, struct wlantest_pmk, list)
+               pmk_deinit(pmk);
+       dl_list_for_each_safe(tdls, nt, &bss->tdls, struct wlantest_tdls, list)
+               tdls_deinit(tdls);
+       dl_list_del(&bss->list);
+       os_free(bss);
+}
+
+
+int bss_add_pmk_from_passphrase(struct wlantest_bss *bss,
+                               const char *passphrase)
+{
+       struct wlantest_pmk *pmk;
+
+       pmk = os_zalloc(sizeof(*pmk));
+       if (pmk == NULL)
+               return -1;
+       if (pbkdf2_sha1(passphrase, (char *) bss->ssid, bss->ssid_len, 4096,
+                       pmk->pmk, sizeof(pmk->pmk)) < 0) {
+               os_free(pmk);
+               return -1;
+       }
+
+       wpa_printf(MSG_INFO, "Add possible PMK for BSSID " MACSTR
+                  " based on passphrase '%s'",
+                  MAC2STR(bss->bssid), passphrase);
+       wpa_hexdump(MSG_DEBUG, "Possible PMK", pmk->pmk, sizeof(pmk->pmk));
+       dl_list_add(&bss->pmk, &pmk->list);
+
+       return 0;
+}
+
+
+static void bss_add_pmk(struct wlantest *wt, struct wlantest_bss *bss)
+{
+       struct wlantest_passphrase *p;
+
+       dl_list_for_each(p, &wt->passphrase, struct wlantest_passphrase, list)
+       {
+               if (!is_zero_ether_addr(p->bssid) &&
+                   os_memcmp(p->bssid, bss->bssid, ETH_ALEN) != 0)
+                       continue;
+               if (p->ssid_len &&
+                   (p->ssid_len != bss->ssid_len ||
+                    os_memcmp(p->ssid, bss->ssid, p->ssid_len) != 0))
+                       continue;
+
+               if (bss_add_pmk_from_passphrase(bss, p->passphrase) < 0)
+                       break;
+       }
+}
+
+
+void bss_update(struct wlantest *wt, struct wlantest_bss *bss,
+               struct ieee802_11_elems *elems)
+{
+       struct wpa_ie_data data;
+       int update = 0;
+
+       if (bss->capab_info != bss->prev_capab_info)
+               update = 1;
+
+       if (elems->ssid == NULL || elems->ssid_len > 32) {
+               wpa_printf(MSG_INFO, "Invalid or missing SSID in a Beacon "
+                          "frame for " MACSTR, MAC2STR(bss->bssid));
+               bss->parse_error_reported = 1;
+               return;
+       }
+
+       if (bss->ssid_len != elems->ssid_len ||
+           os_memcmp(bss->ssid, elems->ssid, bss->ssid_len) != 0) {
+               wpa_printf(MSG_DEBUG, "Store SSID '%s' for BSSID " MACSTR,
+                          wpa_ssid_txt(elems->ssid, elems->ssid_len),
+                          MAC2STR(bss->bssid));
+               os_memcpy(bss->ssid, elems->ssid, elems->ssid_len);
+               bss->ssid_len = elems->ssid_len;
+               bss_add_pmk(wt, bss);
+       }
+
+
+       if (elems->rsn_ie == NULL) {
+               if (bss->rsnie[0]) {
+                       wpa_printf(MSG_INFO, "BSS " MACSTR " - RSN IE removed",
+                                  MAC2STR(bss->bssid));
+                       bss->rsnie[0] = 0;
+                       update = 1;
+               }
+       } else {
+               if (bss->rsnie[0] == 0 ||
+                   os_memcmp(bss->rsnie, elems->rsn_ie - 2,
+                             elems->rsn_ie_len + 2) != 0) {
+                       wpa_printf(MSG_INFO, "BSS " MACSTR " - RSN IE "
+                                  "stored", MAC2STR(bss->bssid));
+                       wpa_hexdump(MSG_DEBUG, "RSN IE", elems->rsn_ie - 2,
+                                   elems->rsn_ie_len + 2);
+                       update = 1;
+               }
+               os_memcpy(bss->rsnie, elems->rsn_ie - 2,
+                         elems->rsn_ie_len + 2);
+       }
+
+       if (elems->wpa_ie == NULL) {
+               if (bss->wpaie[0]) {
+                       wpa_printf(MSG_INFO, "BSS " MACSTR " - WPA IE removed",
+                                  MAC2STR(bss->bssid));
+                       bss->wpaie[0] = 0;
+                       update = 1;
+               }
+       } else {
+               if (bss->wpaie[0] == 0 ||
+                   os_memcmp(bss->wpaie, elems->wpa_ie - 2,
+                             elems->wpa_ie_len + 2) != 0) {
+                       wpa_printf(MSG_INFO, "BSS " MACSTR " - WPA IE "
+                                  "stored", MAC2STR(bss->bssid));
+                       wpa_hexdump(MSG_DEBUG, "WPA IE", elems->wpa_ie - 2,
+                                   elems->wpa_ie_len + 2);
+                       update = 1;
+               }
+               os_memcpy(bss->wpaie, elems->wpa_ie - 2,
+                         elems->wpa_ie_len + 2);
+       }
+
+       if (!update)
+               return;
+
+       bss->prev_capab_info = bss->capab_info;
+       bss->proto = 0;
+       bss->pairwise_cipher = 0;
+       bss->group_cipher = 0;
+       bss->key_mgmt = 0;
+       bss->rsn_capab = 0;
+       bss->mgmt_group_cipher = 0;
+
+       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));
+               } else {
+                       bss->proto |= data.proto;
+                       bss->pairwise_cipher |= data.pairwise_cipher;
+                       bss->group_cipher |= data.group_cipher;
+                       bss->key_mgmt |= data.key_mgmt;
+                       bss->rsn_capab = data.capabilities;
+                       bss->mgmt_group_cipher |= data.mgmt_group_cipher;
+               }
+       }
+
+       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));
+               } else {
+                       bss->proto |= data.proto;
+                       bss->pairwise_cipher |= data.pairwise_cipher;
+                       bss->group_cipher |= data.group_cipher;
+                       bss->key_mgmt |= data.key_mgmt;
+                       bss->rsn_capab = data.capabilities;
+                       bss->mgmt_group_cipher |= data.mgmt_group_cipher;
+               }
+       }
+
+       if (!(bss->proto & WPA_PROTO_RSN) ||
+           !(bss->rsn_capab & WPA_CAPABILITY_MFPC))
+               bss->mgmt_group_cipher = 0;
+
+       if (!bss->wpaie[0] && !bss->rsnie[0] &&
+           (bss->capab_info & WLAN_CAPABILITY_PRIVACY))
+               bss->group_cipher = WPA_CIPHER_WEP40;
+
+       wpa_printf(MSG_INFO, "BSS " MACSTR
+                  " proto=%s%s%s"
+                  "pairwise=%s%s%s%s"
+                  "group=%s%s%s%s%s%s"
+                  "mgmt_group_cipher=%s"
+                  "key_mgmt=%s%s%s%s%s%s%s%s"
+                  "rsn_capab=%s%s%s%s%s",
+                  MAC2STR(bss->bssid),
+                  bss->proto == 0 ? "OPEN " : "",
+                  bss->proto & WPA_PROTO_WPA ? "WPA " : "",
+                  bss->proto & WPA_PROTO_RSN ? "WPA2 " : "",
+                  bss->pairwise_cipher == 0 ? "N/A " : "",
+                  bss->pairwise_cipher & WPA_CIPHER_NONE ? "NONE " : "",
+                  bss->pairwise_cipher & WPA_CIPHER_TKIP ? "TKIP " : "",
+                  bss->pairwise_cipher & WPA_CIPHER_CCMP ? "CCMP " : "",
+                  bss->group_cipher == 0 ? "N/A " : "",
+                  bss->group_cipher & WPA_CIPHER_NONE ? "NONE " : "",
+                  bss->group_cipher & WPA_CIPHER_WEP40 ? "WEP40 " : "",
+                  bss->group_cipher & WPA_CIPHER_WEP104 ? "WEP104 " : "",
+                  bss->group_cipher & WPA_CIPHER_TKIP ? "TKIP " : "",
+                  bss->group_cipher & WPA_CIPHER_CCMP ? "CCMP " : "",
+                  bss->mgmt_group_cipher & WPA_CIPHER_AES_128_CMAC ? "BIP " :
+                  "N/A ",
+                  bss->key_mgmt == 0 ? "N/A " : "",
+                  bss->key_mgmt & WPA_KEY_MGMT_IEEE8021X ? "EAP " : "",
+                  bss->key_mgmt & WPA_KEY_MGMT_PSK ? "PSK " : "",
+                  bss->key_mgmt & WPA_KEY_MGMT_WPA_NONE ? "WPA-NONE " : "",
+                  bss->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X ? "FT-EAP " : "",
+                  bss->key_mgmt & WPA_KEY_MGMT_FT_PSK ? "FT-PSK " : "",
+                  bss->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256 ?
+                  "EAP-SHA256 " : "",
+                  bss->key_mgmt & WPA_KEY_MGMT_PSK_SHA256 ?
+                  "PSK-SHA256 " : "",
+                  bss->rsn_capab & WPA_CAPABILITY_PREAUTH ? "PREAUTH " : "",
+                  bss->rsn_capab & WPA_CAPABILITY_NO_PAIRWISE ?
+                  "NO_PAIRWISE " : "",
+                  bss->rsn_capab & WPA_CAPABILITY_MFPR ? "MFPR " : "",
+                  bss->rsn_capab & WPA_CAPABILITY_MFPC ? "MFPC " : "",
+                  bss->rsn_capab & WPA_CAPABILITY_PEERKEY_ENABLED ?
+                  "PEERKEY " : "");
+}
+
+
+void bss_flush(struct wlantest *wt)
+{
+       struct wlantest_bss *bss, *n;
+       dl_list_for_each_safe(bss, n, &wt->bss, struct wlantest_bss, list)
+               bss_deinit(bss);
+}
diff --git a/wlantest/ccmp.c b/wlantest/ccmp.c
new file mode 100644 (file)
index 0000000..5e51310
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+ * CTR with CBC-MAC 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.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "crypto/aes.h"
+#include "wlantest.h"
+
+
+static void ccmp_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;
+
+       nonce[0] = 0;
+
+       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;
+                       nonce[0] = qc[0] & 0x0f;
+               }
+       } else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
+               nonce[0] |= 0x10; /* Management */
+
+       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 + 1, hdr->addr2, ETH_ALEN);
+       nonce[7] = data[7]; /* PN5 */
+       nonce[8] = data[6]; /* PN4 */
+       nonce[9] = data[5]; /* PN3 */
+       nonce[10] = data[4]; /* PN2 */
+       nonce[11] = data[1]; /* PN1 */
+       nonce[12] = data[0]; /* PN0 */
+}
+
+
+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];
+       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];
+
+       if (data_len < 8 + 8)
+               return NULL;
+
+       plain = os_malloc(data_len + AES_BLOCK_SIZE);
+       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);
+       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) {
+               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",
+                          MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
+                          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;
+       }
+
+       *decrypted_len = mlen;
+       return plain;
+}
+
+
+void ccmp_get_pn(u8 *pn, const u8 *data)
+{
+       pn[0] = data[7]; /* PN5 */
+       pn[1] = data[6]; /* PN4 */
+       pn[2] = data[5]; /* PN3 */
+       pn[3] = data[4]; /* PN2 */
+       pn[4] = data[1]; /* PN1 */
+       pn[5] = data[0]; /* PN0 */
+}
+
+
+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;
+       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)
+               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 */
+
+       aes = aes_encrypt_init(tk, 16);
+       if (aes == NULL) {
+               os_free(crypt);
+               return NULL;
+       }
+
+       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);
+
+       /* 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);
+       }
+
+       /* Encryption */
+
+       /* 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);
+
+       ppos = crypt + hdrlen + 8;
+
+       /* 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++;
+       }
+
+       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);
+
+       wpa_hexdump(MSG_EXCESSIVE, "CCMP encrypted", crypt + hdrlen + 8, plen);
+
+       aes_encrypt_deinit(aes);
+
+       *encrypted_len = hdrlen + 8 + plen + 8;
+
+       return crypt;
+}
diff --git a/wlantest/crc32.c b/wlantest/crc32.c
new file mode 100644 (file)
index 0000000..c1747d8
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+
+/*
+ * IEEE 802.11 FCS CRC32
+ * G(x) = x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 +
+ *        x^5 + x^4 + x^2 + x + 1
+ */
+static const u32 crc32_table[256] = {
+       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+       0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+       0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+       0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+       0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+       0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+       0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+       0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+       0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+       0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+       0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+       0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+       0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+       0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+       0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+       0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+       0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+       0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+       0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+       0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+       0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+       0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+       0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+       0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+       0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+       0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+       0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+       0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+       0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+       0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+       0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+       0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+       0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+       0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+       0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+       0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+       0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+       0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+       0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+       0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+       0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+       0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+       0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+       0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+       0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+       0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+       0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+       0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+       0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+       0x2d02ef8d
+};
+
+
+u32 crc32(const u8 *frame, size_t frame_len)
+{
+       size_t i;
+       u32 crc;
+
+       crc = 0xFFFFFFFF;
+       for (i = 0; i < frame_len; i++)
+               crc = crc32_table[(crc ^ frame[i]) & 0xff] ^ (crc >> 8);
+
+       return ~crc;
+}
diff --git a/wlantest/ctrl.c b/wlantest/ctrl.c
new file mode 100644 (file)
index 0000000..2132b2b
--- /dev/null
@@ -0,0 +1,1358 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+#include <sys/un.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/defs.h"
+#include "common/version.h"
+#include "common/ieee802_11_defs.h"
+#include "wlantest.h"
+#include "wlantest_ctrl.h"
+
+
+static u8 * attr_get(u8 *buf, size_t buflen, enum wlantest_ctrl_attr attr,
+                    size_t *len)
+{
+       u8 *pos = buf;
+
+       while (pos + 8 <= buf + buflen) {
+               enum wlantest_ctrl_attr a;
+               size_t alen;
+               a = WPA_GET_BE32(pos);
+               pos += 4;
+               alen = WPA_GET_BE32(pos);
+               pos += 4;
+               if (pos + alen > buf + buflen) {
+                       wpa_printf(MSG_DEBUG, "Invalid control message "
+                                  "attribute");
+                       return NULL;
+               }
+               if (a == attr) {
+                       *len = alen;
+                       return pos;
+               }
+               pos += alen;
+       }
+
+       return NULL;
+}
+
+
+static u8 * attr_get_macaddr(u8 *buf, size_t buflen,
+                            enum wlantest_ctrl_attr attr)
+{
+       u8 *addr;
+       size_t addr_len;
+       addr = attr_get(buf, buflen, attr, &addr_len);
+       if (addr && addr_len != ETH_ALEN)
+               addr = NULL;
+       return addr;
+}
+
+
+static int attr_get_int(u8 *buf, size_t buflen, enum wlantest_ctrl_attr attr)
+{
+       u8 *pos;
+       size_t len;
+       pos = attr_get(buf, buflen, attr, &len);
+       if (pos == NULL || len != 4)
+               return -1;
+       return WPA_GET_BE32(pos);
+}
+
+
+static u8 * attr_add_str(u8 *pos, u8 *end, enum wlantest_ctrl_attr attr,
+                        const char *str)
+{
+       size_t len = os_strlen(str);
+
+       if (pos == NULL || end - pos < 8 + len)
+               return NULL;
+       WPA_PUT_BE32(pos, attr);
+       pos += 4;
+       WPA_PUT_BE32(pos, len);
+       pos += 4;
+       os_memcpy(pos, str, len);
+       pos += len;
+       return pos;
+}
+
+
+static u8 * attr_add_be32(u8 *pos, u8 *end, enum wlantest_ctrl_attr attr,
+                         u32 val)
+{
+       if (pos == NULL || end - pos < 12)
+               return NULL;
+       WPA_PUT_BE32(pos, attr);
+       pos += 4;
+       WPA_PUT_BE32(pos, 4);
+       pos += 4;
+       WPA_PUT_BE32(pos, val);
+       pos += 4;
+       return pos;
+}
+
+
+static void ctrl_disconnect(struct wlantest *wt, int sock)
+{
+       int i;
+       wpa_printf(MSG_DEBUG, "Disconnect control interface connection %d",
+                  sock);
+       for (i = 0; i < MAX_CTRL_CONNECTIONS; i++) {
+               if (wt->ctrl_socks[i] == sock) {
+                       close(wt->ctrl_socks[i]);
+                       eloop_unregister_read_sock(wt->ctrl_socks[i]);
+                       wt->ctrl_socks[i] = -1;
+                       break;
+               }
+       }
+}
+
+
+static void ctrl_send(struct wlantest *wt, int sock, const u8 *buf,
+                     size_t len)
+{
+       if (send(sock, buf, len, 0) < 0) {
+               wpa_printf(MSG_INFO, "send(ctrl): %s", strerror(errno));
+               ctrl_disconnect(wt, sock);
+       }
+}
+
+
+static void ctrl_send_simple(struct wlantest *wt, int sock,
+                            enum wlantest_ctrl_cmd cmd)
+{
+       u8 buf[4];
+       WPA_PUT_BE32(buf, cmd);
+       ctrl_send(wt, sock, buf, sizeof(buf));
+}
+
+
+static struct wlantest_bss * ctrl_get_bss(struct wlantest *wt, int sock,
+                                         u8 *cmd, size_t clen)
+{
+       struct wlantest_bss *bss;
+       u8 *pos;
+       size_t len;
+
+       pos = attr_get(cmd, clen, WLANTEST_ATTR_BSSID, &len);
+       if (pos == NULL || len != ETH_ALEN) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
+               return NULL;
+       }
+
+       bss = bss_find(wt, pos);
+       if (bss == NULL) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE);
+               return NULL;
+       }
+
+       return bss;
+}
+
+
+static struct wlantest_sta * ctrl_get_sta(struct wlantest *wt, int sock,
+                                         u8 *cmd, size_t clen,
+                                         struct wlantest_bss *bss)
+{
+       struct wlantest_sta *sta;
+       u8 *pos;
+       size_t len;
+
+       if (bss == NULL)
+               return NULL;
+
+       pos = attr_get(cmd, clen, WLANTEST_ATTR_STA_ADDR, &len);
+       if (pos == NULL || len != ETH_ALEN) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
+               return NULL;
+       }
+
+       sta = sta_find(bss, pos);
+       if (sta == NULL) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE);
+               return NULL;
+       }
+
+       return sta;
+}
+
+
+static struct wlantest_sta * ctrl_get_sta2(struct wlantest *wt, int sock,
+                                          u8 *cmd, size_t clen,
+                                          struct wlantest_bss *bss)
+{
+       struct wlantest_sta *sta;
+       u8 *pos;
+       size_t len;
+
+       if (bss == NULL)
+               return NULL;
+
+       pos = attr_get(cmd, clen, WLANTEST_ATTR_STA2_ADDR, &len);
+       if (pos == NULL || len != ETH_ALEN) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
+               return NULL;
+       }
+
+       sta = sta_find(bss, pos);
+       if (sta == NULL) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE);
+               return NULL;
+       }
+
+       return sta;
+}
+
+
+static void ctrl_list_bss(struct wlantest *wt, int sock)
+{
+       u8 buf[WLANTEST_CTRL_MAX_RESP_LEN], *pos, *len;
+       struct wlantest_bss *bss;
+
+       pos = buf;
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_SUCCESS);
+       pos += 4;
+       WPA_PUT_BE32(pos, WLANTEST_ATTR_BSSID);
+       pos += 4;
+       len = pos; /* to be filled */
+       pos += 4;
+
+       dl_list_for_each(bss, &wt->bss, struct wlantest_bss, list) {
+               if (pos + ETH_ALEN > buf + WLANTEST_CTRL_MAX_RESP_LEN)
+                       break;
+               os_memcpy(pos, bss->bssid, ETH_ALEN);
+               pos += ETH_ALEN;
+       }
+
+       WPA_PUT_BE32(len, pos - len - 4);
+       ctrl_send(wt, sock, buf, pos - buf);
+}
+
+
+static void ctrl_list_sta(struct wlantest *wt, int sock, u8 *cmd, size_t clen)
+{
+       u8 buf[WLANTEST_CTRL_MAX_RESP_LEN], *pos, *len;
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+
+       bss = ctrl_get_bss(wt, sock, cmd, clen);
+       if (bss == NULL)
+               return;
+
+       pos = buf;
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_SUCCESS);
+       pos += 4;
+       WPA_PUT_BE32(pos, WLANTEST_ATTR_STA_ADDR);
+       pos += 4;
+       len = pos; /* to be filled */
+       pos += 4;
+
+       dl_list_for_each(sta, &bss->sta, struct wlantest_sta, list) {
+               if (pos + ETH_ALEN > buf + WLANTEST_CTRL_MAX_RESP_LEN)
+                       break;
+               os_memcpy(pos, sta->addr, ETH_ALEN);
+               pos += ETH_ALEN;
+       }
+
+       WPA_PUT_BE32(len, pos - len - 4);
+       ctrl_send(wt, sock, buf, pos - buf);
+}
+
+
+static void ctrl_flush(struct wlantest *wt, int sock)
+{
+       wpa_printf(MSG_DEBUG, "Drop all collected BSS data");
+       bss_flush(wt);
+       ctrl_send_simple(wt, sock, WLANTEST_CTRL_SUCCESS);
+}
+
+
+static void ctrl_clear_sta_counters(struct wlantest *wt, int sock, u8 *cmd,
+                                   size_t clen)
+{
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+
+       bss = ctrl_get_bss(wt, sock, cmd, clen);
+       sta = ctrl_get_sta(wt, sock, cmd, clen, bss);
+       if (sta == NULL) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE);
+               return;
+       }
+
+       os_memset(sta->counters, 0, sizeof(sta->counters));
+       ctrl_send_simple(wt, sock, WLANTEST_CTRL_SUCCESS);
+}
+
+
+static void ctrl_clear_bss_counters(struct wlantest *wt, int sock, u8 *cmd,
+                                   size_t clen)
+{
+       struct wlantest_bss *bss;
+
+       bss = ctrl_get_bss(wt, sock, cmd, clen);
+       if (bss == NULL) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE);
+               return;
+       }
+
+       os_memset(bss->counters, 0, sizeof(bss->counters));
+       ctrl_send_simple(wt, sock, WLANTEST_CTRL_SUCCESS);
+}
+
+
+static void ctrl_clear_tdls_counters(struct wlantest *wt, int sock, u8 *cmd,
+                                    size_t clen)
+{
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+       struct wlantest_sta *sta2;
+       struct wlantest_tdls *tdls;
+
+       bss = ctrl_get_bss(wt, sock, cmd, clen);
+       sta = ctrl_get_sta(wt, sock, cmd, clen, bss);
+       sta2 = ctrl_get_sta2(wt, sock, cmd, clen, bss);
+       if (sta == NULL || sta2 == NULL) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE);
+               return;
+       }
+
+       dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list) {
+               if ((tdls->init == sta && tdls->resp == sta2) ||
+                   (tdls->init == sta2 && tdls->resp == sta))
+                       os_memset(tdls->counters, 0, sizeof(tdls->counters));
+       }
+       ctrl_send_simple(wt, sock, WLANTEST_CTRL_SUCCESS);
+}
+
+
+static void ctrl_get_sta_counter(struct wlantest *wt, int sock, u8 *cmd,
+                                size_t clen)
+{
+       u8 *addr;
+       size_t addr_len;
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+       u32 counter;
+       u8 buf[4 + 12], *end, *pos;
+
+       bss = ctrl_get_bss(wt, sock, cmd, clen);
+       sta = ctrl_get_sta(wt, sock, cmd, clen, bss);
+       if (sta == NULL)
+               return;
+
+       addr = attr_get(cmd, clen, WLANTEST_ATTR_STA_COUNTER, &addr_len);
+       if (addr == NULL || addr_len != 4) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
+               return;
+       }
+       counter = WPA_GET_BE32(addr);
+       if (counter >= NUM_WLANTEST_STA_COUNTER) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
+               return;
+       }
+
+       pos = buf;
+       end = buf + sizeof(buf);
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_SUCCESS);
+       pos += 4;
+       pos = attr_add_be32(pos, end, WLANTEST_ATTR_COUNTER,
+                           sta->counters[counter]);
+       ctrl_send(wt, sock, buf, pos - buf);
+}
+
+
+static void ctrl_get_bss_counter(struct wlantest *wt, int sock, u8 *cmd,
+                                size_t clen)
+{
+       u8 *addr;
+       size_t addr_len;
+       struct wlantest_bss *bss;
+       u32 counter;
+       u8 buf[4 + 12], *end, *pos;
+
+       bss = ctrl_get_bss(wt, sock, cmd, clen);
+       if (bss == NULL)
+               return;
+
+       addr = attr_get(cmd, clen, WLANTEST_ATTR_BSS_COUNTER, &addr_len);
+       if (addr == NULL || addr_len != 4) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
+               return;
+       }
+       counter = WPA_GET_BE32(addr);
+       if (counter >= NUM_WLANTEST_BSS_COUNTER) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
+               return;
+       }
+
+       pos = buf;
+       end = buf + sizeof(buf);
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_SUCCESS);
+       pos += 4;
+       pos = attr_add_be32(pos, end, WLANTEST_ATTR_COUNTER,
+                           bss->counters[counter]);
+       ctrl_send(wt, sock, buf, pos - buf);
+}
+
+
+static void ctrl_get_tdls_counter(struct wlantest *wt, int sock, u8 *cmd,
+                                 size_t clen)
+{
+       u8 *addr;
+       size_t addr_len;
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+       struct wlantest_sta *sta2;
+       struct wlantest_tdls *tdls;
+       u32 counter;
+       u8 buf[4 + 12], *end, *pos;
+       int found = 0;
+
+       bss = ctrl_get_bss(wt, sock, cmd, clen);
+       sta = ctrl_get_sta(wt, sock, cmd, clen, bss);
+       sta2 = ctrl_get_sta2(wt, sock, cmd, clen, bss);
+       if (sta == NULL || sta2 == NULL) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE);
+               return;
+       }
+
+       addr = attr_get(cmd, clen, WLANTEST_ATTR_TDLS_COUNTER, &addr_len);
+       if (addr == NULL || addr_len != 4) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
+               return;
+       }
+       counter = WPA_GET_BE32(addr);
+       if (counter >= NUM_WLANTEST_TDLS_COUNTER) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
+               return;
+       }
+
+       dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list) {
+               if (tdls->init == sta && tdls->resp == sta2) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (!found) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE);
+               return;
+       }
+
+       pos = buf;
+       end = buf + sizeof(buf);
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_SUCCESS);
+       pos += 4;
+       pos = attr_add_be32(pos, end, WLANTEST_ATTR_COUNTER,
+                           tdls->counters[counter]);
+       ctrl_send(wt, sock, buf, pos - buf);
+}
+
+
+static void build_mgmt_hdr(struct ieee80211_mgmt *mgmt,
+                          struct wlantest_bss *bss, struct wlantest_sta *sta,
+                          int sender_ap, int stype)
+{
+       os_memset(mgmt, 0, 24);
+       mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
+       if (sender_ap) {
+               if (sta)
+                       os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
+               else
+                       os_memset(mgmt->da, 0xff, ETH_ALEN);
+               os_memcpy(mgmt->sa, bss->bssid, ETH_ALEN);
+       } else {
+               os_memcpy(mgmt->da, bss->bssid, ETH_ALEN);
+               os_memcpy(mgmt->sa, sta->addr, ETH_ALEN);
+       }
+       os_memcpy(mgmt->bssid, bss->bssid, ETH_ALEN);
+}
+
+
+static int ctrl_inject_auth(struct wlantest *wt, struct wlantest_bss *bss,
+                           struct wlantest_sta *sta, int sender_ap,
+                           enum wlantest_inject_protection prot)
+{
+       struct ieee80211_mgmt mgmt;
+
+       if (prot != WLANTEST_INJECT_NORMAL &&
+           prot != WLANTEST_INJECT_UNPROTECTED)
+               return -1; /* Authentication frame is never protected */
+       if (sta == NULL)
+               return -1; /* No broadcast Authentication frames */
+
+       if (sender_ap)
+               wpa_printf(MSG_INFO, "INJECT: Auth " MACSTR " -> " MACSTR,
+                          MAC2STR(bss->bssid), MAC2STR(sta->addr));
+       else
+               wpa_printf(MSG_INFO, "INJECT: Auth " MACSTR " -> " MACSTR,
+                          MAC2STR(sta->addr), MAC2STR(bss->bssid));
+       build_mgmt_hdr(&mgmt, bss, sta, sender_ap, WLAN_FC_STYPE_AUTH);
+
+       mgmt.u.auth.auth_alg = host_to_le16(WLAN_AUTH_OPEN);
+       mgmt.u.auth.auth_transaction = host_to_le16(1);
+       mgmt.u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS);
+
+       return wlantest_inject(wt, bss, sta, (u8 *) &mgmt, 24 + 6,
+                              WLANTEST_INJECT_UNPROTECTED);
+}
+
+
+static int ctrl_inject_assocreq(struct wlantest *wt, struct wlantest_bss *bss,
+                               struct wlantest_sta *sta, int sender_ap,
+                               enum wlantest_inject_protection prot)
+{
+       u8 *buf;
+       struct ieee80211_mgmt *mgmt;
+       int ret;
+
+       if (prot != WLANTEST_INJECT_NORMAL &&
+           prot != WLANTEST_INJECT_UNPROTECTED)
+               return -1; /* Association Request frame is never protected */
+       if (sta == NULL)
+               return -1; /* No broadcast Association Request frames */
+       if (sender_ap)
+               return -1; /* No Association Request frame sent by AP */
+       if (sta->assocreq_ies == NULL) {
+               wpa_printf(MSG_INFO, "INJECT: No previous (Re)Association "
+                          "Request available for " MACSTR,
+                          MAC2STR(sta->addr));
+               return -1;
+       }
+
+       wpa_printf(MSG_INFO, "INJECT: AssocReq " MACSTR " -> " MACSTR,
+                  MAC2STR(sta->addr), MAC2STR(bss->bssid));
+       buf = os_malloc(sizeof(*mgmt) + sta->assocreq_ies_len);
+       if (buf == NULL)
+               return -1;
+       mgmt = (struct ieee80211_mgmt *) buf;
+
+       build_mgmt_hdr(mgmt, bss, sta, sender_ap, WLAN_FC_STYPE_ASSOC_REQ);
+
+       mgmt->u.assoc_req.capab_info = host_to_le16(sta->assocreq_capab_info);
+       mgmt->u.assoc_req.listen_interval =
+               host_to_le16(sta->assocreq_listen_int);
+       os_memcpy(mgmt->u.assoc_req.variable, sta->assocreq_ies,
+                 sta->assocreq_ies_len);
+
+       ret = wlantest_inject(wt, bss, sta, buf,
+                             24 + 4 + sta->assocreq_ies_len,
+                             WLANTEST_INJECT_UNPROTECTED);
+       os_free(buf);
+       return ret;
+}
+
+
+static int ctrl_inject_reassocreq(struct wlantest *wt,
+                                 struct wlantest_bss *bss,
+                                 struct wlantest_sta *sta, int sender_ap,
+                                 enum wlantest_inject_protection prot)
+{
+       u8 *buf;
+       struct ieee80211_mgmt *mgmt;
+       int ret;
+
+       if (prot != WLANTEST_INJECT_NORMAL &&
+           prot != WLANTEST_INJECT_UNPROTECTED)
+               return -1; /* Reassociation Request frame is never protected */
+       if (sta == NULL)
+               return -1; /* No broadcast Reassociation Request frames */
+       if (sender_ap)
+               return -1; /* No Reassociation Request frame sent by AP */
+       if (sta->assocreq_ies == NULL) {
+               wpa_printf(MSG_INFO, "INJECT: No previous (Re)Association "
+                          "Request available for " MACSTR,
+                          MAC2STR(sta->addr));
+               return -1;
+       }
+
+       wpa_printf(MSG_INFO, "INJECT: ReassocReq " MACSTR " -> " MACSTR,
+                  MAC2STR(sta->addr), MAC2STR(bss->bssid));
+       buf = os_malloc(sizeof(*mgmt) + sta->assocreq_ies_len);
+       if (buf == NULL)
+               return -1;
+       mgmt = (struct ieee80211_mgmt *) buf;
+
+       build_mgmt_hdr(mgmt, bss, sta, sender_ap, WLAN_FC_STYPE_REASSOC_REQ);
+
+       mgmt->u.reassoc_req.capab_info =
+               host_to_le16(sta->assocreq_capab_info);
+       mgmt->u.reassoc_req.listen_interval =
+               host_to_le16(sta->assocreq_listen_int);
+       os_memcpy(mgmt->u.reassoc_req.current_ap, bss->bssid, ETH_ALEN);
+       os_memcpy(mgmt->u.reassoc_req.variable, sta->assocreq_ies,
+                 sta->assocreq_ies_len);
+
+       ret = wlantest_inject(wt, bss, sta, buf,
+                             24 + 10 + sta->assocreq_ies_len,
+                             WLANTEST_INJECT_UNPROTECTED);
+       os_free(buf);
+       return ret;
+}
+
+
+static int ctrl_inject_deauth(struct wlantest *wt, struct wlantest_bss *bss,
+                             struct wlantest_sta *sta, int sender_ap,
+                             enum wlantest_inject_protection prot)
+{
+       struct ieee80211_mgmt mgmt;
+
+       if (sender_ap) {
+               if (sta)
+                       wpa_printf(MSG_INFO, "INJECT: Deauth " MACSTR " -> "
+                                  MACSTR,
+                                  MAC2STR(bss->bssid), MAC2STR(sta->addr));
+               else
+                       wpa_printf(MSG_INFO, "INJECT: Deauth " MACSTR
+                                  " -> broadcast", MAC2STR(bss->bssid));
+       } else
+               wpa_printf(MSG_INFO, "INJECT: Deauth " MACSTR " -> " MACSTR,
+                          MAC2STR(sta->addr), MAC2STR(bss->bssid));
+       build_mgmt_hdr(&mgmt, bss, sta, sender_ap, WLAN_FC_STYPE_DEAUTH);
+
+       mgmt.u.deauth.reason_code = host_to_le16(WLAN_REASON_UNSPECIFIED);
+
+       return wlantest_inject(wt, bss, sta, (u8 *) &mgmt, 24 + 2, prot);
+}
+
+
+static int ctrl_inject_disassoc(struct wlantest *wt, struct wlantest_bss *bss,
+                               struct wlantest_sta *sta, int sender_ap,
+                               enum wlantest_inject_protection prot)
+{
+       struct ieee80211_mgmt mgmt;
+
+       if (sender_ap) {
+               if (sta)
+                       wpa_printf(MSG_INFO, "INJECT: Disassoc " MACSTR " -> "
+                                  MACSTR,
+                                  MAC2STR(bss->bssid), MAC2STR(sta->addr));
+               else
+                       wpa_printf(MSG_INFO, "INJECT: Disassoc " MACSTR
+                                  " -> broadcast", MAC2STR(bss->bssid));
+       } else
+               wpa_printf(MSG_INFO, "INJECT: Disassoc " MACSTR " -> " MACSTR,
+                          MAC2STR(sta->addr), MAC2STR(bss->bssid));
+       build_mgmt_hdr(&mgmt, bss, sta, sender_ap, WLAN_FC_STYPE_DISASSOC);
+
+       mgmt.u.disassoc.reason_code = host_to_le16(WLAN_REASON_UNSPECIFIED);
+
+       return wlantest_inject(wt, bss, sta, (u8 *) &mgmt, 24 + 2, prot);
+}
+
+
+static int ctrl_inject_saqueryreq(struct wlantest *wt,
+                                 struct wlantest_bss *bss,
+                                 struct wlantest_sta *sta, int sender_ap,
+                                 enum wlantest_inject_protection prot)
+{
+       struct ieee80211_mgmt mgmt;
+
+       if (sta == NULL)
+               return -1; /* No broadcast SA Query frames */
+
+       if (sender_ap)
+               wpa_printf(MSG_INFO, "INJECT: SA Query Request " MACSTR " -> "
+                          MACSTR, MAC2STR(bss->bssid), MAC2STR(sta->addr));
+       else
+               wpa_printf(MSG_INFO, "INJECT: SA Query Request " MACSTR " -> "
+                          MACSTR, MAC2STR(sta->addr), MAC2STR(bss->bssid));
+       build_mgmt_hdr(&mgmt, bss, sta, sender_ap, WLAN_FC_STYPE_ACTION);
+
+       mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
+       mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
+       mgmt.u.action.u.sa_query_req.trans_id[0] = 0x12;
+       mgmt.u.action.u.sa_query_req.trans_id[1] = 0x34;
+       os_memcpy(sender_ap ? sta->ap_sa_query_tr : sta->sta_sa_query_tr,
+                 mgmt.u.action.u.sa_query_req.trans_id,
+                 WLAN_SA_QUERY_TR_ID_LEN);
+       return wlantest_inject(wt, bss, sta, (u8 *) &mgmt, 24 + 4, prot);
+}
+
+
+static void ctrl_inject(struct wlantest *wt, int sock, u8 *cmd, size_t clen)
+{
+       u8 *bssid, *sta_addr;
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+       int frame, sender_ap, prot;
+       int ret = 0;
+
+       bssid = attr_get_macaddr(cmd, clen, WLANTEST_ATTR_BSSID);
+       sta_addr = attr_get_macaddr(cmd, clen, WLANTEST_ATTR_STA_ADDR);
+       frame = attr_get_int(cmd, clen, WLANTEST_ATTR_INJECT_FRAME);
+       sender_ap = attr_get_int(cmd, clen, WLANTEST_ATTR_INJECT_SENDER_AP);
+       if (sender_ap < 0)
+               sender_ap = 0;
+       prot = attr_get_int(cmd, clen, WLANTEST_ATTR_INJECT_PROTECTION);
+       if (bssid == NULL || sta_addr == NULL || frame < 0 || prot < 0) {
+               wpa_printf(MSG_INFO, "Invalid inject command parameters");
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
+               return;
+       }
+
+       bss = bss_find(wt, bssid);
+       if (bss == NULL) {
+               wpa_printf(MSG_INFO, "BSS not found for inject command");
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE);
+               return;
+       }
+
+       if (is_broadcast_ether_addr(sta_addr)) {
+               if (!sender_ap) {
+                       wpa_printf(MSG_INFO, "Invalid broadcast inject "
+                                  "command without sender_ap set");
+                       ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
+                       return;
+               } sta = NULL;
+       } else {
+               sta = sta_find(bss, sta_addr);
+               if (sta == NULL) {
+                       wpa_printf(MSG_INFO, "Station not found for inject "
+                                  "command");
+                       ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE);
+                       return;
+               }
+       }
+
+       switch (frame) {
+       case WLANTEST_FRAME_AUTH:
+               ret = ctrl_inject_auth(wt, bss, sta, sender_ap, prot);
+               break;
+       case WLANTEST_FRAME_ASSOCREQ:
+               ret = ctrl_inject_assocreq(wt, bss, sta, sender_ap, prot);
+               break;
+       case WLANTEST_FRAME_REASSOCREQ:
+               ret = ctrl_inject_reassocreq(wt, bss, sta, sender_ap, prot);
+               break;
+       case WLANTEST_FRAME_DEAUTH:
+               ret = ctrl_inject_deauth(wt, bss, sta, sender_ap, prot);
+               break;
+       case WLANTEST_FRAME_DISASSOC:
+               ret = ctrl_inject_disassoc(wt, bss, sta, sender_ap, prot);
+               break;
+       case WLANTEST_FRAME_SAQUERYREQ:
+               ret = ctrl_inject_saqueryreq(wt, bss, sta, sender_ap, prot);
+               break;
+       default:
+               wpa_printf(MSG_INFO, "Unsupported inject command frame %d",
+                          frame);
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
+               return;
+       }
+
+       if (ret)
+               wpa_printf(MSG_INFO, "Failed to inject frame");
+       else
+               wpa_printf(MSG_INFO, "Frame injected successfully");
+       ctrl_send_simple(wt, sock, ret == 0 ? WLANTEST_CTRL_SUCCESS :
+                        WLANTEST_CTRL_FAILURE);
+}
+
+
+static void ctrl_version(struct wlantest *wt, int sock)
+{
+       u8 buf[WLANTEST_CTRL_MAX_RESP_LEN], *pos;
+
+       pos = buf;
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_SUCCESS);
+       pos += 4;
+       pos = attr_add_str(pos, buf + sizeof(buf), WLANTEST_ATTR_VERSION,
+                          VERSION_STR);
+       ctrl_send(wt, sock, buf, pos - buf);
+}
+
+
+static void ctrl_add_passphrase(struct wlantest *wt, int sock, u8 *cmd,
+                               size_t clen)
+{
+       u8 *passphrase;
+       size_t len;
+       struct wlantest_passphrase *p, *pa;
+       u8 *bssid;
+
+       passphrase = attr_get(cmd, clen, WLANTEST_ATTR_PASSPHRASE, &len);
+       if (passphrase == NULL) {
+               u8 *wepkey;
+               char *key;
+               enum wlantest_ctrl_cmd res;
+
+               wepkey = attr_get(cmd, clen, WLANTEST_ATTR_WEPKEY, &len);
+               if (wepkey == NULL) {
+                       ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
+                       return;
+               }
+               key = os_zalloc(len + 1);
+               if (key == NULL) {
+                       ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE);
+                       return;
+               }
+               os_memcpy(key, wepkey, len);
+               if (add_wep(wt, key) < 0)
+                       res = WLANTEST_CTRL_FAILURE;
+               else
+                       res = WLANTEST_CTRL_SUCCESS;
+               os_free(key);
+               ctrl_send_simple(wt, sock, res);
+               return;
+       }
+
+       if (len < 8 || len > 63) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
+               return;
+       }
+
+       p = os_zalloc(sizeof(*p));
+       if (p == NULL) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE);
+               return;
+       }
+       os_memcpy(p->passphrase, passphrase, len);
+       wpa_printf(MSG_INFO, "Add passphrase '%s'", p->passphrase);
+
+       bssid = attr_get_macaddr(cmd, clen, WLANTEST_ATTR_BSSID);
+       if (bssid) {
+               os_memcpy(p->bssid, bssid, ETH_ALEN);
+               wpa_printf(MSG_INFO, "Limit passphrase for BSSID " MACSTR,
+                          MAC2STR(p->bssid));
+       }
+
+       dl_list_for_each(pa, &wt->passphrase, struct wlantest_passphrase, list)
+       {
+               if (os_strcmp(p->passphrase, pa->passphrase) == 0 &&
+                   os_memcmp(p->bssid, pa->bssid, ETH_ALEN) == 0) {
+                       wpa_printf(MSG_INFO, "Passphrase was already known");
+                       os_free(p);
+                       p = NULL;
+                       break;
+               }
+       }
+
+       if (p) {
+               struct wlantest_bss *bss;
+               dl_list_add(&wt->passphrase, &p->list);
+               dl_list_for_each(bss, &wt->bss, struct wlantest_bss, list) {
+                       if (bssid &&
+                           os_memcmp(p->bssid, bss->bssid, ETH_ALEN) != 0)
+                               continue;
+                       bss_add_pmk_from_passphrase(bss, p->passphrase);
+               }
+       }
+
+       ctrl_send_simple(wt, sock, WLANTEST_CTRL_SUCCESS);
+}
+
+
+static void info_print_proto(char *buf, size_t len, int proto)
+{
+       char *pos, *end;
+
+       if (proto == 0) {
+               os_snprintf(buf, len, "OPEN");
+               return;
+       }
+
+       pos = buf;
+       end = buf + len;
+
+       if (proto & WPA_PROTO_WPA)
+               pos += os_snprintf(pos, end - pos, "%sWPA",
+                                  pos == buf ? "" : " ");
+       if (proto & WPA_PROTO_RSN)
+               pos += os_snprintf(pos, end - pos, "%sWPA2",
+                                  pos == buf ? "" : " ");
+}
+
+
+static void info_print_cipher(char *buf, size_t len, int cipher)
+{
+       char *pos, *end;
+
+       if (cipher == 0) {
+               os_snprintf(buf, len, "N/A");
+               return;
+       }
+
+       pos = buf;
+       end = buf + len;
+
+       if (cipher & WPA_CIPHER_NONE)
+               pos += os_snprintf(pos, end - pos, "%sNONE",
+                                  pos == buf ? "" : " ");
+       if (cipher & WPA_CIPHER_WEP40)
+               pos += os_snprintf(pos, end - pos, "%sWEP40",
+                                  pos == buf ? "" : " ");
+       if (cipher & WPA_CIPHER_WEP104)
+               pos += os_snprintf(pos, end - pos, "%sWEP104",
+                                  pos == buf ? "" : " ");
+       if (cipher & WPA_CIPHER_TKIP)
+               pos += os_snprintf(pos, end - pos, "%sTKIP",
+                                  pos == buf ? "" : " ");
+       if (cipher & WPA_CIPHER_CCMP)
+               pos += os_snprintf(pos, end - pos, "%sCCMP",
+                                  pos == buf ? "" : " ");
+       if (cipher & WPA_CIPHER_AES_128_CMAC)
+               pos += os_snprintf(pos, end - pos, "%sBIP",
+                                  pos == buf ? "" : " ");
+}
+
+
+static void info_print_key_mgmt(char *buf, size_t len, int key_mgmt)
+{
+       char *pos, *end;
+
+       if (key_mgmt == 0) {
+               os_snprintf(buf, len, "N/A");
+               return;
+       }
+
+       pos = buf;
+       end = buf + len;
+
+       if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
+               pos += os_snprintf(pos, end - pos, "%sEAP",
+                                  pos == buf ? "" : " ");
+       if (key_mgmt & WPA_KEY_MGMT_PSK)
+               pos += os_snprintf(pos, end - pos, "%sPSK",
+                                  pos == buf ? "" : " ");
+       if (key_mgmt & WPA_KEY_MGMT_WPA_NONE)
+               pos += os_snprintf(pos, end - pos, "%sWPA-NONE",
+                                  pos == buf ? "" : " ");
+       if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
+               pos += os_snprintf(pos, end - pos, "%sFT-EAP",
+                                  pos == buf ? "" : " ");
+       if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
+               pos += os_snprintf(pos, end - pos, "%sFT-PSK",
+                                  pos == buf ? "" : " ");
+       if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
+               pos += os_snprintf(pos, end - pos, "%sEAP-SHA256",
+                                  pos == buf ? "" : " ");
+       if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+               pos += os_snprintf(pos, end - pos, "%sPSK-SHA256",
+                                  pos == buf ? "" : " ");
+}
+
+
+static void info_print_rsn_capab(char *buf, size_t len, int capab)
+{
+       char *pos, *end;
+
+       pos = buf;
+       end = buf + len;
+
+       if (capab & WPA_CAPABILITY_PREAUTH)
+               pos += os_snprintf(pos, end - pos, "%sPREAUTH",
+                                  pos == buf ? "" : " ");
+       if (capab & WPA_CAPABILITY_NO_PAIRWISE)
+               pos += os_snprintf(pos, end - pos, "%sNO_PAIRWISE",
+                                  pos == buf ? "" : " ");
+       if (capab & WPA_CAPABILITY_MFPR)
+               pos += os_snprintf(pos, end - pos, "%sMFPR",
+                                  pos == buf ? "" : " ");
+       if (capab & WPA_CAPABILITY_MFPC)
+               pos += os_snprintf(pos, end - pos, "%sMFPC",
+                                  pos == buf ? "" : " ");
+       if (capab & WPA_CAPABILITY_PEERKEY_ENABLED)
+               pos += os_snprintf(pos, end - pos, "%sPEERKEY",
+                                  pos == buf ? "" : " ");
+}
+
+
+static void info_print_state(char *buf, size_t len, int state)
+{
+       switch (state) {
+       case STATE1:
+               os_strlcpy(buf, "NOT-AUTH", len);
+               break;
+       case STATE2:
+               os_strlcpy(buf, "AUTH", len);
+               break;
+       case STATE3:
+               os_strlcpy(buf, "AUTH+ASSOC", len);
+               break;
+       }
+}
+
+
+static void ctrl_info_sta(struct wlantest *wt, int sock, u8 *cmd, size_t clen)
+{
+       u8 *addr;
+       size_t addr_len;
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+       enum wlantest_sta_info info;
+       u8 buf[4 + 108], *end, *pos;
+       char resp[100];
+
+       bss = ctrl_get_bss(wt, sock, cmd, clen);
+       sta = ctrl_get_sta(wt, sock, cmd, clen, bss);
+       if (sta == NULL)
+               return;
+
+       addr = attr_get(cmd, clen, WLANTEST_ATTR_STA_INFO, &addr_len);
+       if (addr == NULL || addr_len != 4) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
+               return;
+       }
+       info = WPA_GET_BE32(addr);
+
+       resp[0] = '\0';
+       switch (info) {
+       case WLANTEST_STA_INFO_PROTO:
+               info_print_proto(resp, sizeof(resp), sta->proto);
+               break;
+       case WLANTEST_STA_INFO_PAIRWISE:
+               info_print_cipher(resp, sizeof(resp), sta->pairwise_cipher);
+               break;
+       case WLANTEST_STA_INFO_KEY_MGMT:
+               info_print_key_mgmt(resp, sizeof(resp), sta->key_mgmt);
+               break;
+       case WLANTEST_STA_INFO_RSN_CAPAB:
+               info_print_rsn_capab(resp, sizeof(resp), sta->rsn_capab);
+               break;
+       case WLANTEST_STA_INFO_STATE:
+               info_print_state(resp, sizeof(resp), sta->state);
+               break;
+       default:
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
+               return;
+       }
+
+       pos = buf;
+       end = buf + sizeof(buf);
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_SUCCESS);
+       pos += 4;
+       pos = attr_add_str(pos, end, WLANTEST_ATTR_INFO, resp);
+       ctrl_send(wt, sock, buf, pos - buf);
+}
+
+
+static void ctrl_info_bss(struct wlantest *wt, int sock, u8 *cmd, size_t clen)
+{
+       u8 *addr;
+       size_t addr_len;
+       struct wlantest_bss *bss;
+       enum wlantest_bss_info info;
+       u8 buf[4 + 108], *end, *pos;
+       char resp[100];
+
+       bss = ctrl_get_bss(wt, sock, cmd, clen);
+       if (bss == NULL)
+               return;
+
+       addr = attr_get(cmd, clen, WLANTEST_ATTR_BSS_INFO, &addr_len);
+       if (addr == NULL || addr_len != 4) {
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
+               return;
+       }
+       info = WPA_GET_BE32(addr);
+
+       resp[0] = '\0';
+       switch (info) {
+       case WLANTEST_BSS_INFO_PROTO:
+               info_print_proto(resp, sizeof(resp), bss->proto);
+               break;
+       case WLANTEST_BSS_INFO_PAIRWISE:
+               info_print_cipher(resp, sizeof(resp), bss->pairwise_cipher);
+               break;
+       case WLANTEST_BSS_INFO_GROUP:
+               info_print_cipher(resp, sizeof(resp), bss->group_cipher);
+               break;
+       case WLANTEST_BSS_INFO_GROUP_MGMT:
+               info_print_cipher(resp, sizeof(resp), bss->mgmt_group_cipher);
+               break;
+       case WLANTEST_BSS_INFO_KEY_MGMT:
+               info_print_key_mgmt(resp, sizeof(resp), bss->key_mgmt);
+               break;
+       case WLANTEST_BSS_INFO_RSN_CAPAB:
+               info_print_rsn_capab(resp, sizeof(resp), bss->rsn_capab);
+               break;
+       default:
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
+               return;
+       }
+
+       pos = buf;
+       end = buf + sizeof(buf);
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_SUCCESS);
+       pos += 4;
+       pos = attr_add_str(pos, end, WLANTEST_ATTR_INFO, resp);
+       ctrl_send(wt, sock, buf, pos - buf);
+}
+
+
+static void ctrl_send_(struct wlantest *wt, int sock, u8 *cmd, size_t clen)
+{
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+       u8 *bssid, *sta_addr;
+       int prot;
+       u8 *frame;
+       size_t frame_len;
+       int ret = 0;
+       struct ieee80211_hdr *hdr;
+       u16 fc;
+
+       frame = attr_get(cmd, clen, WLANTEST_ATTR_FRAME, &frame_len);
+       prot = attr_get_int(cmd, clen, WLANTEST_ATTR_INJECT_PROTECTION);
+       if (frame == NULL || frame_len < 24 || prot < 0) {
+               wpa_printf(MSG_INFO, "Invalid send command parameters");
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
+               return;
+       }
+
+       hdr = (struct ieee80211_hdr *) frame;
+       fc = le_to_host16(hdr->frame_control);
+       switch (WLAN_FC_GET_TYPE(fc)) {
+       case WLAN_FC_TYPE_MGMT:
+               bssid = hdr->addr3;
+               if (os_memcmp(hdr->addr2, hdr->addr3, ETH_ALEN) == 0)
+                       sta_addr = hdr->addr1;
+               else
+                       sta_addr = hdr->addr2;
+               break;
+       case WLAN_FC_TYPE_DATA:
+               switch (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) {
+               case 0:
+                       bssid = hdr->addr3;
+                       sta_addr = hdr->addr2;
+                       break;
+               case WLAN_FC_TODS:
+                       bssid = hdr->addr1;
+                       sta_addr = hdr->addr2;
+                       break;
+               case WLAN_FC_FROMDS:
+                       bssid = hdr->addr2;
+                       sta_addr = hdr->addr1;
+                       break;
+               default:
+                       wpa_printf(MSG_INFO, "Unsupported inject frame");
+                       ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE);
+                       return;
+               }
+               break;
+       default:
+               wpa_printf(MSG_INFO, "Unsupported inject frame");
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE);
+               return;
+       }
+
+       bss = bss_find(wt, bssid);
+       if (bss == NULL && prot != WLANTEST_INJECT_UNPROTECTED) {
+               wpa_printf(MSG_INFO, "Unknown BSSID");
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE);
+               return;
+       }
+
+       if (bss)
+               sta = sta_find(bss, sta_addr);
+       else
+               sta = NULL;
+       if (sta == NULL && prot != WLANTEST_INJECT_UNPROTECTED) {
+               wpa_printf(MSG_INFO, "Unknown STA address");
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE);
+               return;
+       }
+
+       ret = wlantest_inject(wt, bss, sta, frame, frame_len, prot);
+
+       if (ret)
+               wpa_printf(MSG_INFO, "Failed to inject frame");
+       else
+               wpa_printf(MSG_INFO, "Frame injected successfully");
+       ctrl_send_simple(wt, sock, ret == 0 ? WLANTEST_CTRL_SUCCESS :
+                        WLANTEST_CTRL_FAILURE);
+}
+
+
+static void ctrl_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+       struct wlantest *wt = eloop_ctx;
+       u8 buf[WLANTEST_CTRL_MAX_CMD_LEN];
+       int len;
+       enum wlantest_ctrl_cmd cmd;
+
+       wpa_printf(MSG_EXCESSIVE, "New control interface message from %d",
+                  sock);
+       len = recv(sock, buf, sizeof(buf), 0);
+       if (len < 0) {
+               wpa_printf(MSG_INFO, "recv(ctrl): %s", strerror(errno));
+               ctrl_disconnect(wt, sock);
+               return;
+       }
+       if (len == 0) {
+               ctrl_disconnect(wt, sock);
+               return;
+       }
+
+       if (len < 4) {
+               wpa_printf(MSG_INFO, "Too short control interface command "
+                          "from %d", sock);
+               ctrl_disconnect(wt, sock);
+               return;
+       }
+       cmd = WPA_GET_BE32(buf);
+       wpa_printf(MSG_EXCESSIVE, "Control interface command %d from %d",
+                  cmd, sock);
+
+       switch (cmd) {
+       case WLANTEST_CTRL_PING:
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_SUCCESS);
+               break;
+       case WLANTEST_CTRL_TERMINATE:
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_SUCCESS);
+               eloop_terminate();
+               break;
+       case WLANTEST_CTRL_LIST_BSS:
+               ctrl_list_bss(wt, sock);
+               break;
+       case WLANTEST_CTRL_LIST_STA:
+               ctrl_list_sta(wt, sock, buf + 4, len - 4);
+               break;
+       case WLANTEST_CTRL_FLUSH:
+               ctrl_flush(wt, sock);
+               break;
+       case WLANTEST_CTRL_CLEAR_STA_COUNTERS:
+               ctrl_clear_sta_counters(wt, sock, buf + 4, len - 4);
+               break;
+       case WLANTEST_CTRL_CLEAR_BSS_COUNTERS:
+               ctrl_clear_bss_counters(wt, sock, buf + 4, len - 4);
+               break;
+       case WLANTEST_CTRL_CLEAR_TDLS_COUNTERS:
+               ctrl_clear_tdls_counters(wt, sock, buf + 4, len - 4);
+               break;
+       case WLANTEST_CTRL_GET_STA_COUNTER:
+               ctrl_get_sta_counter(wt, sock, buf + 4, len - 4);
+               break;
+       case WLANTEST_CTRL_GET_BSS_COUNTER:
+               ctrl_get_bss_counter(wt, sock, buf + 4, len - 4);
+               break;
+       case WLANTEST_CTRL_GET_TDLS_COUNTER:
+               ctrl_get_tdls_counter(wt, sock, buf + 4, len - 4);
+               break;
+       case WLANTEST_CTRL_INJECT:
+               ctrl_inject(wt, sock, buf + 4, len - 4);
+               break;
+       case WLANTEST_CTRL_VERSION:
+               ctrl_version(wt, sock);
+               break;
+       case WLANTEST_CTRL_ADD_PASSPHRASE:
+               ctrl_add_passphrase(wt, sock, buf + 4, len - 4);
+               break;
+       case WLANTEST_CTRL_INFO_STA:
+               ctrl_info_sta(wt, sock, buf + 4, len - 4);
+               break;
+       case WLANTEST_CTRL_INFO_BSS:
+               ctrl_info_bss(wt, sock, buf + 4, len - 4);
+               break;
+       case WLANTEST_CTRL_SEND:
+               ctrl_send_(wt, sock, buf + 4, len - 4);
+               break;
+       default:
+               ctrl_send_simple(wt, sock, WLANTEST_CTRL_UNKNOWN_CMD);
+               break;
+       }
+}
+
+
+static void ctrl_connect(int sock, void *eloop_ctx, void *sock_ctx)
+{
+       struct wlantest *wt = eloop_ctx;
+       int conn, i;
+
+       conn = accept(sock, NULL, NULL);
+       if (conn < 0) {
+               wpa_printf(MSG_INFO, "accept(ctrl): %s", strerror(errno));
+               return;
+       }
+       wpa_printf(MSG_MSGDUMP, "New control interface connection %d", conn);
+
+       for (i = 0; i < MAX_CTRL_CONNECTIONS; i++) {
+               if (wt->ctrl_socks[i] < 0)
+                       break;
+       }
+
+       if (i == MAX_CTRL_CONNECTIONS) {
+               wpa_printf(MSG_INFO, "No room for new control connection");
+               close(conn);
+               return;
+       }
+
+       wt->ctrl_socks[i] = conn;
+       eloop_register_read_sock(conn, ctrl_read, wt, NULL);
+}
+
+
+int ctrl_init(struct wlantest *wt)
+{
+       struct sockaddr_un addr;
+
+       wt->ctrl_sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+       if (wt->ctrl_sock < 0) {
+               wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
+               return -1;
+       }
+
+       os_memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       os_strlcpy(addr.sun_path + 1, WLANTEST_SOCK_NAME,
+                  sizeof(addr.sun_path) - 1);
+       if (bind(wt->ctrl_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               wpa_printf(MSG_ERROR, "bind: %s", strerror(errno));
+               close(wt->ctrl_sock);
+               wt->ctrl_sock = -1;
+               return -1;
+       }
+
+       if (listen(wt->ctrl_sock, 5) < 0) {
+               wpa_printf(MSG_ERROR, "listen: %s", strerror(errno));
+               close(wt->ctrl_sock);
+               wt->ctrl_sock = -1;
+               return -1;
+       }
+
+       if (eloop_register_read_sock(wt->ctrl_sock, ctrl_connect, wt, NULL)) {
+               close(wt->ctrl_sock);
+               wt->ctrl_sock = -1;
+               return -1;
+       }
+
+       return 0;
+}
+
+
+void ctrl_deinit(struct wlantest *wt)
+{
+       int i;
+
+       if (wt->ctrl_sock < 0)
+               return;
+
+       for (i = 0; i < MAX_CTRL_CONNECTIONS; i++) {
+               if (wt->ctrl_socks[i] >= 0) {
+                       close(wt->ctrl_socks[i]);
+                       eloop_unregister_read_sock(wt->ctrl_socks[i]);
+                       wt->ctrl_socks[i] = -1;
+               }
+       }
+
+       eloop_unregister_read_sock(wt->ctrl_sock);
+       close(wt->ctrl_sock);
+       wt->ctrl_sock = -1;
+}
diff --git a/wlantest/inject.c b/wlantest/inject.c
new file mode 100644 (file)
index 0000000..e8e7de7
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/defs.h"
+#include "common/ieee802_11_defs.h"
+#include "crypto/aes_wrap.h"
+#include "wlantest.h"
+
+
+static int inject_frame(int s, const void *data, size_t len)
+{
+#define        IEEE80211_RADIOTAP_F_FRAG       0x08
+       unsigned char rtap_hdr[] = {
+               0x00, 0x00, /* radiotap version */
+               0x0e, 0x00, /* radiotap length */
+               0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
+               IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
+               0x00,       /* padding */
+               0x00, 0x00, /* RX and TX flags to indicate that */
+               0x00, 0x00, /* this is the injected frame directly */
+       };
+       struct iovec iov[2] = {
+               {
+                       .iov_base = &rtap_hdr,
+                       .iov_len = sizeof(rtap_hdr),
+               },
+               {
+                       .iov_base = (void *) data,
+                       .iov_len = len,
+               }
+       };
+       struct msghdr msg = {
+               .msg_name = NULL,
+               .msg_namelen = 0,
+               .msg_iov = iov,
+               .msg_iovlen = 2,
+               .msg_control = NULL,
+               .msg_controllen = 0,
+               .msg_flags = 0,
+       };
+       int ret;
+
+       ret = sendmsg(s, &msg, 0);
+       if (ret < 0)
+               perror("sendmsg");
+       return ret;
+}
+
+
+static int is_robust_mgmt(u8 *frame, size_t len)
+{
+       struct ieee80211_mgmt *mgmt;
+       u16 fc, stype;
+       if (len < 24)
+               return 0;
+       mgmt = (struct ieee80211_mgmt *) frame;
+       fc = le_to_host16(mgmt->frame_control);
+       if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
+               return 0;
+       stype = WLAN_FC_GET_STYPE(fc);
+       if (stype == WLAN_FC_STYPE_DEAUTH || stype == WLAN_FC_STYPE_DISASSOC)
+               return 1;
+       if (stype == WLAN_FC_STYPE_ACTION) {
+               if (len < 25)
+                       return 0;
+               if (mgmt->u.action.category != WLAN_ACTION_PUBLIC)
+                       return 1;
+       }
+       return 0;
+}
+
+
+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 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;
+       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);
+               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);
+
+       return (ret < 0) ? -1 : 0;
+}
+
+
+static int wlantest_inject_prot_bc(struct wlantest *wt,
+                                  struct wlantest_bss *bss,
+                                  u8 *frame, size_t len, int incorrect_key)
+{
+       u8 *crypt;
+       size_t crypt_len;
+       int ret;
+       u8 dummy[64];
+       u8 *pn;
+       struct ieee80211_hdr *hdr;
+       u16 fc;
+       int hdrlen;
+
+       hdr = (struct ieee80211_hdr *) frame;
+       hdrlen = 24;
+       fc = le_to_host16(hdr->frame_control);
+
+       if (!bss->gtk_len[bss->gtk_idx])
+               return -1;
+
+       if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
+           (WLAN_FC_TODS | WLAN_FC_FROMDS))
+               hdrlen += ETH_ALEN;
+       pn = bss->rsc[bss->gtk_idx];
+       inc_byte_array(pn, 6);
+
+       os_memset(dummy, 0x11, sizeof(dummy));
+       if (bss->group_cipher == WPA_CIPHER_TKIP)
+               crypt = tkip_encrypt(incorrect_key ? dummy :
+                                    bss->gtk[bss->gtk_idx],
+                                    frame, len, hdrlen, NULL, pn,
+                                    bss->gtk_idx, &crypt_len);
+       else
+               crypt = ccmp_encrypt(incorrect_key ? dummy :
+                                    bss->gtk[bss->gtk_idx],
+                                    frame, len, hdrlen, NULL, pn,
+                                    bss->gtk_idx, &crypt_len);
+
+       if (crypt == NULL)
+               return -1;
+
+       ret = inject_frame(wt->monitor_sock, crypt, crypt_len);
+       os_free(crypt);
+
+       return (ret < 0) ? -1 : 0;
+}
+
+
+static int wlantest_inject_prot(struct wlantest *wt, struct wlantest_bss *bss,
+                               struct wlantest_sta *sta, u8 *frame,
+                               size_t len, int incorrect_key)
+{
+       u8 *crypt;
+       size_t crypt_len;
+       int ret;
+       u8 dummy[64];
+       u8 *pn;
+       struct ieee80211_hdr *hdr;
+       u16 fc;
+       int tid = 0;
+       u8 *qos = NULL;
+       int hdrlen;
+       struct wlantest_tdls *tdls = NULL;
+       const u8 *tk = NULL;
+
+       hdr = (struct ieee80211_hdr *) frame;
+       hdrlen = 24;
+       fc = le_to_host16(hdr->frame_control);
+
+       if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA &&
+           (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == 0) {
+               struct wlantest_sta *sta2;
+               bss = bss_get(wt, hdr->addr3);
+               if (bss == NULL) {
+                       wpa_printf(MSG_DEBUG, "No BSS found for TDLS "
+                                  "injection");
+                       return -1;
+               }
+               sta = sta_find(bss, hdr->addr2);
+               sta2 = sta_find(bss, hdr->addr1);
+               if (sta == NULL || sta2 == NULL) {
+                       wpa_printf(MSG_DEBUG, "No stations found for TDLS "
+                                  "injection");
+                       return -1;
+               }
+               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 injecting Data "
+                                                  "frame on direct link");
+                               tk = tdls->tpk.tk;
+                               break;
+                       }
+               }
+       }
+
+       if (tk == NULL && sta == NULL) {
+               if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
+                       return wlantest_inject_bip(wt, bss, frame, len,
+                                                  incorrect_key);
+               return wlantest_inject_prot_bc(wt, bss, frame, len,
+                                              incorrect_key);
+       }
+
+       if (tk == NULL && !sta->ptk_set) {
+               wpa_printf(MSG_DEBUG, "No key known for injection");
+               return -1;
+       }
+
+       if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
+               tid = 16;
+       else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) {
+               if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
+                   (WLAN_FC_TODS | WLAN_FC_FROMDS))
+                       hdrlen += ETH_ALEN;
+               if (WLAN_FC_GET_STYPE(fc) & 0x08) {
+                       qos = frame + hdrlen;
+                       hdrlen += 2;
+                       tid = qos[0] & 0x0f;
+               }
+       }
+       if (tk) {
+               if (os_memcmp(hdr->addr2, tdls->init->addr, ETH_ALEN) == 0)
+                       pn = tdls->rsc_init[tid];
+               else
+                       pn = tdls->rsc_resp[tid];
+       } else if (os_memcmp(hdr->addr2, bss->bssid, ETH_ALEN) == 0)
+               pn = sta->rsc_fromds[tid];
+       else
+               pn = sta->rsc_tods[tid];
+       inc_byte_array(pn, 6);
+
+       os_memset(dummy, 0x11, sizeof(dummy));
+       if (tk) 
+               crypt = ccmp_encrypt(incorrect_key ? dummy : tk,
+                                    frame, len, hdrlen, qos, pn, 0,
+                                    &crypt_len);
+       else if (sta->pairwise_cipher == WPA_CIPHER_TKIP)
+               crypt = tkip_encrypt(incorrect_key ? dummy : sta->ptk.tk1,
+                                    frame, len, hdrlen, qos, pn, 0,
+                                    &crypt_len);
+       else
+               crypt = ccmp_encrypt(incorrect_key ? dummy : sta->ptk.tk1,
+                                    frame, len, hdrlen, qos, pn, 0,
+                                    &crypt_len);
+
+       if (crypt == NULL) {
+               wpa_printf(MSG_DEBUG, "Frame encryption failed");
+               return -1;
+       }
+
+       wpa_hexdump(MSG_DEBUG, "Inject frame (encrypted)", crypt, crypt_len);
+       ret = inject_frame(wt->monitor_sock, crypt, crypt_len);
+       os_free(crypt);
+       wpa_printf(MSG_DEBUG, "inject_frame for protected frame: %d", ret);
+
+       return (ret < 0) ? -1 : 0;
+}
+
+
+int wlantest_inject(struct wlantest *wt, struct wlantest_bss *bss,
+                   struct wlantest_sta *sta, u8 *frame, size_t len,
+                   enum wlantest_inject_protection prot)
+{
+       int ret;
+       struct ieee80211_hdr *hdr;
+       u16 fc;
+       int protectable, protect = 0;
+
+       wpa_hexdump(MSG_DEBUG, "Inject frame", frame, len);
+       if (wt->monitor_sock < 0) {
+               wpa_printf(MSG_INFO, "Cannot inject frames when monitor "
+                          "interface is not in use");
+               return -1;
+       }
+
+       if (prot != WLANTEST_INJECT_UNPROTECTED &&
+           (bss == NULL || sta == NULL)) {
+               wpa_printf(MSG_INFO, "No BSS/STA information to inject "
+                          "protected frames");
+               return -1;
+       }
+
+       hdr = (struct ieee80211_hdr *) frame;
+       fc = le_to_host16(hdr->frame_control);
+       protectable = WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA ||
+               is_robust_mgmt(frame, len);
+
+       if ((prot == WLANTEST_INJECT_PROTECTED ||
+            prot == WLANTEST_INJECT_INCORRECT_KEY) && bss) {
+               if (!sta &&
+                   ((WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+                     !bss->igtk_set[bss->igtk_idx]) ||
+                    (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA &&
+                     !bss->gtk_len[bss->gtk_idx]))) {
+                       wpa_printf(MSG_INFO, "No GTK/IGTK known for "
+                                  MACSTR " to protect the injected "
+                                  "frame", MAC2STR(bss->bssid));
+                       return -1;
+               }
+               if (sta && !sta->ptk_set) {
+                       wpa_printf(MSG_INFO, "No PTK known for the STA " MACSTR
+                                  " to encrypt the injected frame",
+                                  MAC2STR(sta->addr));
+                       return -1;
+               }
+               protect = 1;
+       } else if (protectable && prot != WLANTEST_INJECT_UNPROTECTED && bss) {
+               if (sta && sta->ptk_set)
+                       protect = 1;
+               else if (!sta) {
+                       if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA &&
+                           bss->gtk_len[bss->gtk_idx])
+                               protect = 1;
+                       if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+                           bss->igtk_set[bss->igtk_idx])
+                               protect = 1;
+               }
+       }
+
+       if (protect && bss)
+               return wlantest_inject_prot(
+                       wt, bss, sta, frame, len,
+                       prot == WLANTEST_INJECT_INCORRECT_KEY);
+
+       ret = inject_frame(wt->monitor_sock, frame, len);
+       wpa_printf(MSG_DEBUG, "inject_frame for unprotected frame: %d", ret);
+       return (ret < 0) ? -1 : 0;
+}
diff --git a/wlantest/monitor.c b/wlantest/monitor.c
new file mode 100644 (file)
index 0000000..c16893a
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+#include <net/if.h>
+#include <netpacket/packet.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "wlantest.h"
+
+
+static void monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+       struct wlantest *wt = eloop_ctx;
+       u8 buf[3000];
+       int len;
+
+       len = recv(sock, buf, sizeof(buf), 0);
+       if (len < 0) {
+               wpa_printf(MSG_INFO, "recv(PACKET): %s", strerror(errno));
+               return;
+       }
+
+       write_pcap_captured(wt, buf, len);
+       wlantest_process(wt, buf, len);
+}
+
+
+static void monitor_read_wired(int sock, void *eloop_ctx, void *sock_ctx)
+{
+       struct wlantest *wt = eloop_ctx;
+       u8 buf[3000];
+       int len;
+
+       len = recv(sock, buf, sizeof(buf), 0);
+       if (len < 0) {
+               wpa_printf(MSG_INFO, "recv(PACKET): %s", strerror(errno));
+               return;
+       }
+
+       wlantest_process_wired(wt, buf, len);
+}
+
+
+int monitor_init(struct wlantest *wt, const char *ifname)
+{
+       struct sockaddr_ll ll;
+
+       os_memset(&ll, 0, sizeof(ll));
+       ll.sll_family = AF_PACKET;
+       ll.sll_ifindex = if_nametoindex(ifname);
+       if (ll.sll_ifindex == 0) {
+               wpa_printf(MSG_ERROR, "Monitor interface '%s' does not exist",
+                          ifname);
+               return -1;
+       }
+
+       wt->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+       if (wt->monitor_sock < 0) {
+               wpa_printf(MSG_ERROR, "socket(PF_PACKET,SOCK_RAW): %s",
+                          strerror(errno));
+               return -1;
+       }
+
+       if (bind(wt->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+               wpa_printf(MSG_ERROR, "bind(PACKET): %s", strerror(errno));
+               close(wt->monitor_sock);
+               wt->monitor_sock = -1;
+               return -1;
+       }
+
+       if (eloop_register_read_sock(wt->monitor_sock, monitor_read, wt, NULL))
+       {
+               wpa_printf(MSG_ERROR, "Could not register monitor read "
+                          "socket");
+               close(wt->monitor_sock);
+               wt->monitor_sock = -1;
+               return -1;
+       }
+
+       return 0;
+}
+
+
+int monitor_init_wired(struct wlantest *wt, const char *ifname)
+{
+       struct sockaddr_ll ll;
+
+       os_memset(&ll, 0, sizeof(ll));
+       ll.sll_family = AF_PACKET;
+       ll.sll_ifindex = if_nametoindex(ifname);
+       if (ll.sll_ifindex == 0) {
+               wpa_printf(MSG_ERROR, "Monitor interface '%s' does not exist",
+                          ifname);
+               return -1;
+       }
+
+       wt->monitor_wired = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+       if (wt->monitor_wired < 0) {
+               wpa_printf(MSG_ERROR, "socket(PF_PACKET,SOCK_RAW): %s",
+                          strerror(errno));
+               return -1;
+       }
+
+       if (bind(wt->monitor_wired, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+               wpa_printf(MSG_ERROR, "bind(PACKET): %s", strerror(errno));
+               close(wt->monitor_wired);
+               wt->monitor_wired = -1;
+               return -1;
+       }
+
+       if (eloop_register_read_sock(wt->monitor_wired, monitor_read_wired,
+                                    wt, NULL)) {
+               wpa_printf(MSG_ERROR, "Could not register monitor read "
+                          "socket");
+               close(wt->monitor_wired);
+               wt->monitor_wired = -1;
+               return -1;
+       }
+
+       return 0;
+}
+
+
+void monitor_deinit(struct wlantest *wt)
+{
+       if (wt->monitor_sock >= 0) {
+               eloop_unregister_read_sock(wt->monitor_sock);
+               close(wt->monitor_sock);
+               wt->monitor_sock = -1;
+       }
+
+       if (wt->monitor_wired >= 0) {
+               eloop_unregister_read_sock(wt->monitor_wired);
+               close(wt->monitor_wired);
+               wt->monitor_wired = -1;
+       }
+}
diff --git a/wlantest/process.c b/wlantest/process.c
new file mode 100644 (file)
index 0000000..a4dd87d
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/radiotap.h"
+#include "utils/radiotap_iter.h"
+#include "common/ieee802_11_defs.h"
+#include "wlantest.h"
+
+
+static struct wlantest_sta * rx_get_sta(struct wlantest *wt,
+                                       const struct ieee80211_hdr *hdr,
+                                       size_t len, int *to_ap)
+{
+       u16 fc;
+       const u8 *sta_addr, *bssid;
+       struct wlantest_bss *bss;
+
+       *to_ap = 0;
+       if (hdr->addr1[0] & 0x01)
+               return NULL; /* Ignore group addressed frames */
+
+       fc = le_to_host16(hdr->frame_control);
+       switch (WLAN_FC_GET_TYPE(fc)) {
+       case WLAN_FC_TYPE_MGMT:
+               if (len < 24)
+                       return NULL;
+               bssid = hdr->addr3;
+               if (os_memcmp(bssid, hdr->addr2, ETH_ALEN) == 0) {
+                       sta_addr = hdr->addr1;
+                       *to_ap = 0;
+               } else {
+                       if (os_memcmp(bssid, hdr->addr1, ETH_ALEN) != 0)
+                               return NULL; /* Unsupported STA-to-STA frame */
+                       sta_addr = hdr->addr2;
+                       *to_ap = 1;
+               }
+               break;
+       case WLAN_FC_TYPE_DATA:
+               if (len < 24)
+                       return NULL;
+               switch (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) {
+               case 0:
+                       return NULL; /* IBSS not supported */
+               case WLAN_FC_FROMDS:
+                       sta_addr = hdr->addr1;
+                       bssid = hdr->addr2;
+                       *to_ap = 0;
+                       break;
+               case WLAN_FC_TODS:
+                       sta_addr = hdr->addr2;
+                       bssid = hdr->addr1;
+                       *to_ap = 1;
+                       break;
+               case WLAN_FC_TODS | WLAN_FC_FROMDS:
+                       return NULL; /* WDS not supported */
+               default:
+                       return NULL;
+               }
+               break;
+       case WLAN_FC_TYPE_CTRL:
+               if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PSPOLL &&
+                   len >= 16) {
+                       sta_addr = hdr->addr2;
+                       bssid = hdr->addr1;
+                       *to_ap = 1;
+               } else
+                       return NULL;
+               break;
+       default:
+               return NULL;
+       }
+
+       bss = bss_find(wt, bssid);
+       if (bss == NULL)
+               return NULL;
+       return sta_find(bss, sta_addr);
+}
+
+
+static void rx_update_ps(struct wlantest *wt, const struct ieee80211_hdr *hdr,
+                        size_t len, struct wlantest_sta *sta, int to_ap)
+{
+       u16 fc, type, stype;
+
+       if (sta == NULL)
+               return;
+
+       fc = le_to_host16(hdr->frame_control);
+       type = WLAN_FC_GET_TYPE(fc);
+       stype = WLAN_FC_GET_STYPE(fc);
+
+       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));
+               } else
+                       sta->pspoll = 0;
+               return;
+       }
+
+       sta->pspoll = 0;
+
+       if (type == WLAN_FC_TYPE_DATA || type == WLAN_FC_TYPE_MGMT ||
+           (type == WLAN_FC_TYPE_CTRL && stype == WLAN_FC_STYPE_PSPOLL)) {
+               /*
+                * In theory, the PS state changes only at the end of the frame
+                * exchange that is ACKed by the AP. However, most cases are
+                * handled with this simpler implementation that does not
+                * 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));
+                       sta->pwrmgt = 0;
+               } else if (!sta->pwrmgt && (fc & WLAN_FC_PWRMGT)) {
+                       wpa_printf(MSG_DEBUG, "STA " MACSTR " went to sleep",
+                                  MAC2STR(sta->addr));
+                       sta->pwrmgt = 1;
+               }
+       }
+
+       if (type == WLAN_FC_TYPE_CTRL && stype == WLAN_FC_STYPE_PSPOLL)
+               sta->pspoll = 1;
+}
+
+
+static int rx_duplicate(struct wlantest *wt, const struct ieee80211_hdr *hdr,
+                       size_t len, struct wlantest_sta *sta, int to_ap)
+{
+       u16 fc;
+       int tid = 16;
+       le16 *seq_ctrl;
+
+       if (sta == NULL)
+               return 0;
+
+       fc = le_to_host16(hdr->frame_control);
+       if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA &&
+           (WLAN_FC_GET_STYPE(fc) & 0x08) && len >= 26) {
+               const u8 *qos = ((const u8 *) hdr) + 24;
+               tid = qos[0] & 0x0f;
+       }
+
+       if (to_ap)
+               seq_ctrl = &sta->seq_ctrl_to_ap[tid];
+       else
+               seq_ctrl = &sta->seq_ctrl_to_sta[tid];
+
+       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));
+               return 1;
+       }
+
+       *seq_ctrl = hdr->seq_ctrl;
+
+       return 0;
+}
+
+
+static void rx_ack(struct wlantest *wt, const struct ieee80211_hdr *hdr)
+{
+       struct ieee80211_hdr *last = (struct ieee80211_hdr *) wt->last_hdr;
+       u16 fc;
+
+       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)");
+               return;
+       }
+
+       /* Ack to the previous frame */
+       fc = le_to_host16(last->frame_control);
+       if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
+               rx_mgmt_ack(wt, last);
+}
+
+
+static void rx_frame(struct wlantest *wt, const u8 *data, size_t len)
+{
+       const struct ieee80211_hdr *hdr;
+       u16 fc;
+       struct wlantest_sta *sta;
+       int to_ap;
+
+       wpa_hexdump(MSG_EXCESSIVE, "RX frame", data, len);
+       if (len < 2)
+               return;
+
+       hdr = (const struct ieee80211_hdr *) data;
+       fc = le_to_host16(hdr->frame_control);
+       if (fc & WLAN_FC_PVER) {
+               wpa_printf(MSG_DEBUG, "Drop RX frame with unexpected pver=%d",
+                          fc & WLAN_FC_PVER);
+               return;
+       }
+
+       sta = rx_get_sta(wt, hdr, len, &to_ap);
+
+       switch (WLAN_FC_GET_TYPE(fc)) {
+       case WLAN_FC_TYPE_MGMT:
+               if (len < 24)
+                       break;
+               if (rx_duplicate(wt, hdr, len, sta, to_ap))
+                       break;
+               rx_update_ps(wt, hdr, len, sta, to_ap);
+               rx_mgmt(wt, data, len);
+               break;
+       case WLAN_FC_TYPE_CTRL:
+               if (len < 10)
+                       break;
+               wt->rx_ctrl++;
+               rx_update_ps(wt, hdr, len, sta, to_ap);
+               if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACK)
+                       rx_ack(wt, hdr);
+               break;
+       case WLAN_FC_TYPE_DATA:
+               if (len < 24)
+                       break;
+               if (rx_duplicate(wt, hdr, len, sta, to_ap))
+                       break;
+               rx_update_ps(wt, hdr, len, sta, to_ap);
+               rx_data(wt, data, len);
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "Drop RX frame with unexpected type %d",
+                          WLAN_FC_GET_TYPE(fc));
+               break;
+       }
+
+       os_memcpy(wt->last_hdr, data, len > sizeof(wt->last_hdr) ?
+                 sizeof(wt->last_hdr) : len);
+       wt->last_len = len;
+}
+
+
+static void tx_status(struct wlantest *wt, const u8 *data, size_t len, int ack)
+{
+       wpa_printf(MSG_DEBUG, "TX status: ack=%d", ack);
+       wpa_hexdump(MSG_EXCESSIVE, "TX status frame", data, len);
+}
+
+
+static int check_fcs(const u8 *frame, size_t frame_len, const u8 *fcs)
+{
+       if (WPA_GET_LE32(fcs) != crc32(frame, frame_len))
+               return -1;
+       return 0;
+}
+
+
+void wlantest_process(struct wlantest *wt, const u8 *data, size_t len)
+{
+       struct ieee80211_radiotap_iterator iter;
+       int ret;
+       int rxflags = 0, txflags = 0, failed = 0, fcs = 0;
+       const u8 *frame, *fcspos;
+       size_t frame_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");
+               return;
+       }
+
+       for (;;) {
+               ret = ieee80211_radiotap_iterator_next(&iter);
+               wpa_printf(MSG_EXCESSIVE, "radiotap iter: %d "
+                          "this_arg_index=%d", ret, iter.this_arg_index);
+               if (ret == -ENOENT)
+                       break;
+               if (ret) {
+                       wpa_printf(MSG_INFO, "Invalid radiotap header: %d",
+                                  ret);
+                       return;
+               }
+               switch (iter.this_arg_index) {
+               case IEEE80211_RADIOTAP_FLAGS:
+                       if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
+                               fcs = 1;
+                       break;
+               case IEEE80211_RADIOTAP_RX_FLAGS:
+                       rxflags = 1;
+                       break;
+               case IEEE80211_RADIOTAP_TX_FLAGS:
+                       txflags = 1;
+                       failed = le_to_host16((*(u16 *) iter.this_arg)) &
+                               IEEE80211_RADIOTAP_F_TX_FAIL;
+                       break;
+
+               }
+       }
+
+       if (iter.max_length == 8) {
+               wpa_printf(MSG_DEBUG, "Skip frame inserted by wlantest");
+               return;
+       }
+       frame = data + iter.max_length;
+       frame_len = len - iter.max_length;
+
+       if (fcs && frame_len >= 4) {
+               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");
+                       wt->fcs_error++;
+                       return;
+               }
+       }
+
+       if (rxflags && txflags)
+               return;
+       if (!txflags)
+               rx_frame(wt, frame, frame_len);
+       else
+               tx_status(wt, frame, frame_len, !failed);
+}
+
+
+void wlantest_process_prism(struct wlantest *wt, const u8 *data, size_t len)
+{
+       int fcs = 0;
+       const u8 *frame, *fcspos;
+       size_t frame_len;
+       u32 hdrlen;
+
+       wpa_hexdump(MSG_EXCESSIVE, "Process data", data, len);
+
+       if (len < 8)
+               return;
+       hdrlen = WPA_GET_LE32(data + 4);
+
+       if (len < hdrlen) {
+               wpa_printf(MSG_INFO, "Too short frame to include prism "
+                          "header");
+               return;
+       }
+
+       frame = data + hdrlen;
+       frame_len = len - hdrlen;
+       fcs = 1;
+
+       if (fcs && frame_len >= 4) {
+               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");
+                       wt->fcs_error++;
+                       return;
+               }
+       }
+
+       rx_frame(wt, frame, frame_len);
+}
+
+
+void wlantest_process_80211(struct wlantest *wt, const u8 *data, size_t len)
+{
+       wpa_hexdump(MSG_EXCESSIVE, "Process data", data, len);
+       rx_frame(wt, data, len);
+}
diff --git a/wlantest/readpcap.c b/wlantest/readpcap.c
new file mode 100644 (file)
index 0000000..fd8b1e8
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+#include <pcap.h>
+
+#include "utils/common.h"
+#include "wlantest.h"
+
+
+int read_cap_file(struct wlantest *wt, const char *fname)
+{
+       char errbuf[PCAP_ERRBUF_SIZE];
+       pcap_t *pcap;
+       unsigned int count = 0;
+       struct pcap_pkthdr *hdr;
+       const u_char *data;
+       int res;
+       int dlt;
+
+       pcap = pcap_open_offline(fname, errbuf);
+       if (pcap == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to read pcap file '%s': %s",
+                          fname, errbuf);
+               return -1;
+       }
+       dlt = pcap_datalink(pcap);
+       if (dlt != DLT_IEEE802_11_RADIO && dlt != DLT_PRISM_HEADER &&
+           dlt != DLT_IEEE802_11) {
+               wpa_printf(MSG_ERROR, "Unsupported pcap datalink type: %d",
+                          dlt);
+               pcap_close(pcap);
+               return -1;
+       }
+       wpa_printf(MSG_DEBUG, "pcap datalink type: %d", dlt);
+
+       for (;;) {
+               res = pcap_next_ex(pcap, &hdr, &data);
+               if (res == -2)
+                       break; /* No more packets */
+               if (res == -1) {
+                       wpa_printf(MSG_INFO, "pcap_next_ex failure: %s",
+                                  pcap_geterr(pcap));
+                       break;
+               }
+               if (res != 1) {
+                       wpa_printf(MSG_INFO, "Unexpected pcap_next_ex return "
+                                  "value %d", res);
+                       break;
+               }
+
+               /* Packet was read without problems */
+               wpa_printf(MSG_EXCESSIVE, "pcap hdr: ts=%d.%06d "
+                          "len=%u/%u",
+                          (int) hdr->ts.tv_sec, (int) hdr->ts.tv_usec,
+                          hdr->caplen, hdr->len);
+               if (wt->write_pcap_dumper) {
+                       wt->write_pcap_time = hdr->ts;
+                       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);
+                       continue;
+               }
+               count++;
+               switch (dlt) {
+               case DLT_IEEE802_11_RADIO:
+                       wlantest_process(wt, data, hdr->caplen);
+                       break;
+               case DLT_PRISM_HEADER:
+                       wlantest_process_prism(wt, data, hdr->caplen);
+                       break;
+               case DLT_IEEE802_11:
+                       wlantest_process_80211(wt, data, hdr->caplen);
+               }
+       }
+
+       pcap_close(pcap);
+
+       wpa_printf(MSG_DEBUG, "Read %s: %u packets", fname, count);
+
+       return 0;
+}
+
+
+int read_wired_cap_file(struct wlantest *wt, const char *fname)
+{
+       char errbuf[PCAP_ERRBUF_SIZE];
+       pcap_t *pcap;
+       unsigned int count = 0;
+       struct pcap_pkthdr *hdr;
+       const u_char *data;
+       int res;
+
+       pcap = pcap_open_offline(fname, errbuf);
+       if (pcap == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to read pcap file '%s': %s",
+                          fname, errbuf);
+               return -1;
+       }
+
+       for (;;) {
+               res = pcap_next_ex(pcap, &hdr, &data);
+               if (res == -2)
+                       break; /* No more packets */
+               if (res == -1) {
+                       wpa_printf(MSG_INFO, "pcap_next_ex failure: %s",
+                                  pcap_geterr(pcap));
+                       break;
+               }
+               if (res != 1) {
+                       wpa_printf(MSG_INFO, "Unexpected pcap_next_ex return "
+                                  "value %d", res);
+                       break;
+               }
+
+               /* Packet was read without problems */
+               wpa_printf(MSG_EXCESSIVE, "pcap hdr: ts=%d.%06d "
+                          "len=%u/%u",
+                          (int) hdr->ts.tv_sec, (int) hdr->ts.tv_usec,
+                          hdr->caplen, hdr->len);
+               if (hdr->caplen < hdr->len) {
+                       wpa_printf(MSG_DEBUG, "pcap: Dropped incomplete frame "
+                                  "(%u/%u captured)",
+                                  hdr->caplen, hdr->len);
+                       continue;
+               }
+               count++;
+               wlantest_process_wired(wt, data, hdr->caplen);
+       }
+
+       pcap_close(pcap);
+
+       wpa_printf(MSG_DEBUG, "Read %s: %u packets", fname, count);
+
+       return 0;
+}
diff --git a/wlantest/rx_data.c b/wlantest/rx_data.c
new file mode 100644 (file)
index 0000000..b7f1a89
--- /dev/null
@@ -0,0 +1,535 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+#include <linux/if_ether.h>
+
+#include "utils/common.h"
+#include "common/defs.h"
+#include "common/ieee802_11_defs.h"
+#include "wlantest.h"
+
+
+static const char * data_stype(u16 stype)
+{
+       switch (stype) {
+       case WLAN_FC_STYPE_DATA:
+               return "DATA";
+       case WLAN_FC_STYPE_DATA_CFACK:
+               return "DATA-CFACK";
+       case WLAN_FC_STYPE_DATA_CFPOLL:
+               return "DATA-CFPOLL";
+       case WLAN_FC_STYPE_DATA_CFACKPOLL:
+               return "DATA-CFACKPOLL";
+       case WLAN_FC_STYPE_NULLFUNC:
+               return "NULLFUNC";
+       case WLAN_FC_STYPE_CFACK:
+               return "CFACK";
+       case WLAN_FC_STYPE_CFPOLL:
+               return "CFPOLL";
+       case WLAN_FC_STYPE_CFACKPOLL:
+               return "CFACKPOLL";
+       case WLAN_FC_STYPE_QOS_DATA:
+               return "QOSDATA";
+       case WLAN_FC_STYPE_QOS_DATA_CFACK:
+               return "QOSDATA-CFACK";
+       case WLAN_FC_STYPE_QOS_DATA_CFPOLL:
+               return "QOSDATA-CFPOLL";
+       case WLAN_FC_STYPE_QOS_DATA_CFACKPOLL:
+               return "QOSDATA-CFACKPOLL";
+       case WLAN_FC_STYPE_QOS_NULL:
+               return "QOS-NULL";
+       case WLAN_FC_STYPE_QOS_CFPOLL:
+               return "QOS-CFPOLL";
+       case WLAN_FC_STYPE_QOS_CFACKPOLL:
+               return "QOS-CFACKPOLL";
+       }
+       return "??";
+}
+
+
+static void rx_data_eth(struct wlantest *wt, const u8 *bssid,
+                       const u8 *sta_addr, const u8 *dst, const u8 *src,
+                       u16 ethertype, const u8 *data, size_t len, int prot,
+                       const u8 *peer_addr)
+{
+       switch (ethertype) {
+       case ETH_P_PAE:
+               rx_data_eapol(wt, dst, src, data, len, prot);
+               break;
+       case ETH_P_IP:
+               rx_data_ip(wt, bssid, sta_addr, dst, src, data, len,
+                          peer_addr);
+               break;
+       case 0x890d:
+               rx_data_80211_encap(wt, bssid, sta_addr, dst, src, data, len);
+               break;
+       }
+}
+
+
+static void rx_data_process(struct wlantest *wt, const u8 *bssid,
+                           const u8 *sta_addr,
+                           const u8 *dst, const u8 *src,
+                           const u8 *data, size_t len, int prot,
+                           const u8 *peer_addr)
+{
+       if (len == 0)
+               return;
+
+       if (len >= 8 && os_memcmp(data, "\xaa\xaa\x03\x00\x00\x00", 6) == 0) {
+               rx_data_eth(wt, bssid, sta_addr, dst, src,
+                           WPA_GET_BE16(data + 6), data + 8, len - 8, prot,
+                           peer_addr);
+               return;
+       }
+
+       wpa_hexdump(MSG_DEBUG, "Unrecognized LLC", data, len > 8 ? 8 : len);
+}
+
+
+static void rx_data_bss_prot_group(struct wlantest *wt,
+                                  const struct ieee80211_hdr *hdr,
+                                  const u8 *qos, const u8 *dst, const u8 *src,
+                                  const u8 *data, size_t len)
+{
+       struct wlantest_bss *bss;
+       int keyid;
+       u8 *decrypted;
+       size_t dlen;
+       u8 pn[6];
+
+       bss = bss_get(wt, hdr->addr2);
+       if (bss == NULL)
+               return;
+       if (len < 4) {
+               wpa_printf(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;
+       }
+
+       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));
+               }
+               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);
+               }
+       } 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));
+               }
+       }
+
+       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);
+               return;
+       }
+
+       if (bss->group_cipher == WPA_CIPHER_TKIP)
+               tkip_get_pn(pn, data);
+       else if (bss->group_cipher == WPA_CIPHER_WEP40)
+               goto skip_replay_det;
+       else
+               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));
+               wpa_hexdump(MSG_INFO, "RX PN", pn, 6);
+               wpa_hexdump(MSG_INFO, "RSC", bss->rsc[keyid], 6);
+       }
+
+skip_replay_det:
+       if (bss->group_cipher == WPA_CIPHER_TKIP)
+               decrypted = tkip_decrypt(bss->gtk[keyid], hdr, data, len,
+                                        &dlen);
+       else if (bss->group_cipher == WPA_CIPHER_WEP40)
+               decrypted = wep_decrypt(wt, hdr, data, len, &dlen);
+       else
+               decrypted = ccmp_decrypt(bss->gtk[keyid], hdr, data, len,
+                                        &dlen);
+       if (decrypted) {
+               rx_data_process(wt, bss->bssid, NULL, dst, src, decrypted,
+                               dlen, 1, NULL);
+               os_memcpy(bss->rsc[keyid], pn, 6);
+               write_pcap_decrypted(wt, (const u8 *) hdr, 24 + (qos ? 2 : 0),
+                                    decrypted, dlen);
+       }
+       os_free(decrypted);
+}
+
+
+static void rx_data_bss_prot(struct wlantest *wt,
+                            const struct ieee80211_hdr *hdr, const u8 *qos,
+                            const u8 *dst, const u8 *src, const u8 *data,
+                            size_t len)
+{
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta, *sta2;
+       int keyid;
+       u16 fc = le_to_host16(hdr->frame_control);
+       u8 *decrypted;
+       size_t dlen;
+       int tid;
+       u8 pn[6], *rsc;
+       struct wlantest_tdls *tdls = NULL;
+       const u8 *tk = NULL;
+
+       if (hdr->addr1[0] & 0x01) {
+               rx_data_bss_prot_group(wt, hdr, qos, dst, src, data, len);
+               return;
+       }
+
+       if (fc & WLAN_FC_TODS) {
+               bss = bss_get(wt, hdr->addr1);
+               if (bss == NULL)
+                       return;
+               sta = sta_get(bss, hdr->addr2);
+               if (sta)
+                       sta->counters[WLANTEST_STA_COUNTER_PROT_DATA_TX]++;
+       } else if (fc & WLAN_FC_FROMDS) {
+               bss = bss_get(wt, hdr->addr2);
+               if (bss == NULL)
+                       return;
+               sta = sta_get(bss, hdr->addr1);
+       } else {
+               bss = bss_get(wt, hdr->addr3);
+               if (bss == NULL)
+                       return;
+               sta = sta_find(bss, hdr->addr2);
+               sta2 = sta_find(bss, hdr->addr1);
+               if (sta == NULL || sta2 == NULL)
+                       return;
+               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;
+                       }
+               }
+       }
+       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");
+               return;
+       }
+
+       if (len < 4) {
+               wpa_printf(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;
+       }
+
+       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));
+               }
+               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);
+               }
+       } 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));
+               }
+       }
+
+       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));
+       }
+
+       if (qos)
+               tid = qos[0] & 0x0f;
+       else
+               tid = 0;
+       if (tk) {
+               if (os_memcmp(hdr->addr2, tdls->init->addr, ETH_ALEN) == 0)
+                       rsc = tdls->rsc_init[tid];
+               else
+                       rsc = tdls->rsc_resp[tid];
+       } else if (fc & WLAN_FC_TODS)
+               rsc = sta->rsc_tods[tid];
+       else
+               rsc = sta->rsc_fromds[tid];
+
+
+       if (tk == NULL && sta->pairwise_cipher == WPA_CIPHER_TKIP)
+               tkip_get_pn(pn, data);
+       else if (sta->pairwise_cipher == WPA_CIPHER_WEP40)
+               goto skip_replay_det;
+       else
+               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));
+               wpa_hexdump(MSG_INFO, "RX PN", pn, 6);
+               wpa_hexdump(MSG_INFO, "RSC", rsc, 6);
+       }
+
+skip_replay_det:
+       if (tk)
+               decrypted = ccmp_decrypt(tk, hdr, data, len, &dlen);
+       else if (sta->pairwise_cipher == WPA_CIPHER_TKIP)
+               decrypted = tkip_decrypt(sta->ptk.tk1, hdr, data, len, &dlen);
+       else if (sta->pairwise_cipher == WPA_CIPHER_WEP40)
+               decrypted = wep_decrypt(wt, hdr, data, len, &dlen);
+       else
+               decrypted = ccmp_decrypt(sta->ptk.tk1, hdr, data, len, &dlen);
+       if (decrypted) {
+               u16 fc = le_to_host16(hdr->frame_control);
+               const u8 *peer_addr = NULL;
+               if (!(fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)))
+                       peer_addr = hdr->addr1;
+               os_memcpy(rsc, pn, 6);
+               rx_data_process(wt, bss->bssid, sta->addr, dst, src, decrypted,
+                               dlen, 1, peer_addr);
+               write_pcap_decrypted(wt, (const u8 *) hdr, 24 + (qos ? 2 : 0),
+                                    decrypted, dlen);
+       }
+       os_free(decrypted);
+}
+
+
+static void rx_data_bss(struct wlantest *wt, const struct ieee80211_hdr *hdr,
+                       const u8 *qos, const u8 *dst, const u8 *src,
+                       const u8 *data, size_t len)
+{
+       u16 fc = le_to_host16(hdr->frame_control);
+       int prot = !!(fc & WLAN_FC_ISWEP);
+
+       if (qos) {
+               u8 ack = (qos[0] & 0x60) >> 5;
+               wpa_printf(MSG_MSGDUMP, "BSS DATA: " MACSTR " -> " MACSTR
+                          " len=%u%s tid=%u%s%s",
+                          MAC2STR(src), MAC2STR(dst), (unsigned int) len,
+                          prot ? " Prot" : "", qos[0] & 0x0f,
+                          (qos[0] & 0x10) ? " EOSP" : "",
+                          ack == 0 ? "" :
+                          (ack == 1 ? " NoAck" :
+                           (ack == 2 ? " NoExpAck" : " BA")));
+       } else {
+               wpa_printf(MSG_MSGDUMP, "BSS DATA: " MACSTR " -> " MACSTR
+                          " len=%u%s",
+                          MAC2STR(src), MAC2STR(dst), (unsigned int) len,
+                          prot ? " Prot" : "");
+       }
+
+       if (prot)
+               rx_data_bss_prot(wt, hdr, qos, dst, src, data, len);
+       else {
+               const u8 *bssid, *sta_addr, *peer_addr;
+               if (fc & WLAN_FC_TODS) {
+                       bssid = hdr->addr1;
+                       sta_addr = hdr->addr2;
+                       peer_addr = NULL;
+               } else if (fc & WLAN_FC_FROMDS) {
+                       bssid = hdr->addr2;
+                       sta_addr = hdr->addr1;
+                       peer_addr = NULL;
+               } else {
+                       bssid = hdr->addr3;
+                       sta_addr = hdr->addr2;
+                       peer_addr = hdr->addr1;
+               }
+               rx_data_process(wt, bssid, sta_addr, dst, src, data, len, 0,
+                               peer_addr);
+       }
+}
+
+
+static struct wlantest_tdls * get_tdls(struct wlantest *wt, const u8 *bssid,
+                                      const u8 *sta1_addr,
+                                      const u8 *sta2_addr)
+{
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta1, *sta2;
+       struct wlantest_tdls *tdls;
+
+       bss = bss_find(wt, bssid);
+       if (bss == NULL)
+               return NULL;
+       sta1 = sta_find(bss, sta1_addr);
+       if (sta1 == NULL)
+               return NULL;
+       sta2 = sta_find(bss, sta2_addr);
+       if (sta2 == NULL)
+               return NULL;
+
+       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;
+       }
+
+       return NULL;
+}
+
+
+static void add_direct_link(struct wlantest *wt, const u8 *bssid,
+                           const u8 *sta1_addr, const u8 *sta2_addr)
+{
+       struct wlantest_tdls *tdls;
+
+       tdls = get_tdls(wt, bssid, sta1_addr, sta2_addr);
+       if (tdls == NULL)
+               return;
+
+       if (tdls->link_up)
+               tdls->counters[WLANTEST_TDLS_COUNTER_VALID_DIRECT_LINK]++;
+       else
+               tdls->counters[WLANTEST_TDLS_COUNTER_INVALID_DIRECT_LINK]++;
+}
+
+
+static void add_ap_path(struct wlantest *wt, const u8 *bssid,
+                       const u8 *sta1_addr, const u8 *sta2_addr)
+{
+       struct wlantest_tdls *tdls;
+
+       tdls = get_tdls(wt, bssid, sta1_addr, sta2_addr);
+       if (tdls == NULL)
+               return;
+
+       if (tdls->link_up)
+               tdls->counters[WLANTEST_TDLS_COUNTER_INVALID_AP_PATH]++;
+       else
+               tdls->counters[WLANTEST_TDLS_COUNTER_VALID_AP_PATH]++;
+}
+
+
+void rx_data(struct wlantest *wt, const u8 *data, size_t len)
+{
+       const struct ieee80211_hdr *hdr;
+       u16 fc, stype;
+       size_t hdrlen;
+       const u8 *qos = NULL;
+
+       if (len < 24)
+               return;
+
+       hdr = (const struct ieee80211_hdr *) data;
+       fc = le_to_host16(hdr->frame_control);
+       stype = WLAN_FC_GET_STYPE(fc);
+       hdrlen = 24;
+       if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
+           (WLAN_FC_TODS | WLAN_FC_FROMDS))
+               hdrlen += ETH_ALEN;
+       if (stype & 0x08) {
+               qos = data + hdrlen;
+               hdrlen += 2;
+       }
+       if (len < hdrlen)
+               return;
+       wt->rx_data++;
+
+       switch (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) {
+       case 0:
+               wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s IBSS DA=" MACSTR " SA="
+                          MACSTR " BSSID=" MACSTR,
+                          data_stype(WLAN_FC_GET_STYPE(fc)),
+                          fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
+                          fc & WLAN_FC_ISWEP ? " Prot" : "",
+                          MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
+                          MAC2STR(hdr->addr3));
+               add_direct_link(wt, hdr->addr3, hdr->addr1, hdr->addr2);
+               rx_data_bss(wt, hdr, qos, hdr->addr1, hdr->addr2,
+                           data + hdrlen, len - hdrlen);
+               break;
+       case WLAN_FC_FROMDS:
+               wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s FromDS DA=" MACSTR
+                          " BSSID=" MACSTR " SA=" MACSTR,
+                          data_stype(WLAN_FC_GET_STYPE(fc)),
+                          fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
+                          fc & WLAN_FC_ISWEP ? " Prot" : "",
+                          MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
+                          MAC2STR(hdr->addr3));
+               add_ap_path(wt, hdr->addr2, hdr->addr1, hdr->addr3);
+               rx_data_bss(wt, hdr, qos, hdr->addr1, hdr->addr3,
+                           data + hdrlen, len - hdrlen);
+               break;
+       case WLAN_FC_TODS:
+               wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s ToDS BSSID=" MACSTR
+                          " SA=" MACSTR " DA=" MACSTR,
+                          data_stype(WLAN_FC_GET_STYPE(fc)),
+                          fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
+                          fc & WLAN_FC_ISWEP ? " Prot" : "",
+                          MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
+                          MAC2STR(hdr->addr3));
+               add_ap_path(wt, hdr->addr1, hdr->addr3, hdr->addr2);
+               rx_data_bss(wt, hdr, qos, hdr->addr3, hdr->addr2,
+                           data + hdrlen, len - hdrlen);
+               break;
+       case WLAN_FC_TODS | WLAN_FC_FROMDS:
+               wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s WDS RA=" MACSTR " TA="
+                          MACSTR " DA=" MACSTR " SA=" MACSTR,
+                          data_stype(WLAN_FC_GET_STYPE(fc)),
+                          fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
+                          fc & WLAN_FC_ISWEP ? " Prot" : "",
+                          MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
+                          MAC2STR(hdr->addr3),
+                          MAC2STR((const u8 *) (hdr + 1)));
+               break;
+       }
+}
diff --git a/wlantest/rx_eapol.c b/wlantest/rx_eapol.c
new file mode 100644 (file)
index 0000000..5a87326
--- /dev/null
@@ -0,0 +1,1034 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/crypto.h"
+#include "common/defs.h"
+#include "common/ieee802_11_defs.h"
+#include "common/eapol_common.h"
+#include "common/wpa_common.h"
+#include "rsn_supp/wpa_ie.h"
+#include "wlantest.h"
+
+
+static int is_zero(const u8 *buf, size_t len)
+{
+       size_t i;
+       for (i = 0; i < len; i++) {
+               if (buf[i])
+                       return 0;
+       }
+       return 1;
+}
+
+
+static int check_mic(const u8 *kck, int ver, const u8 *data, size_t len)
+{
+       u8 *buf;
+       int ret = -1;
+       struct ieee802_1x_hdr *hdr;
+       struct wpa_eapol_key *key;
+       u8 rx_mic[16];
+
+       buf = os_malloc(len);
+       if (buf == NULL)
+               return -1;
+       os_memcpy(buf, data, len);
+       hdr = (struct ieee802_1x_hdr *) buf;
+       key = (struct wpa_eapol_key *) (hdr + 1);
+
+       os_memcpy(rx_mic, key->key_mic, 16);
+       os_memset(key->key_mic, 0, 16);
+
+       if (wpa_eapol_key_mic(kck, ver, buf, len, key->key_mic) == 0 &&
+           os_memcmp(rx_mic, key->key_mic, 16) == 0)
+               ret = 0;
+
+       os_free(buf);
+
+       return ret;
+}
+
+
+static void rx_data_eapol_key_1_of_4(struct wlantest *wt, const u8 *dst,
+                                    const u8 *src, const u8 *data, size_t len)
+{
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+       const struct ieee802_1x_hdr *eapol;
+       const struct wpa_eapol_key *hdr;
+
+       wpa_printf(MSG_DEBUG, "EAPOL-Key 1/4 " MACSTR " -> " MACSTR,
+                  MAC2STR(src), MAC2STR(dst));
+       bss = bss_get(wt, src);
+       if (bss == NULL)
+               return;
+       sta = sta_get(bss, dst);
+       if (sta == NULL)
+               return;
+
+       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));
+       }
+       if (!is_zero(hdr->key_rsc, 8)) {
+               wpa_printf(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,
+                  struct wlantest_pmk *pmk)
+{
+       struct wpa_ptk ptk;
+       size_t ptk_len = sta->pairwise_cipher == WPA_CIPHER_TKIP ? 64 : 48;
+       wpa_pmk_to_ptk(pmk->pmk, sizeof(pmk->pmk),
+                      "Pairwise key expansion",
+                      bss->bssid, sta->addr, sta->anonce, sta->snonce,
+                      (u8 *) &ptk, ptk_len,
+                      wpa_key_mgmt_sha256(sta->key_mgmt));
+       if (check_mic(ptk.kck, ver, data, len) < 0)
+               return -1;
+
+       wpa_printf(MSG_INFO, "Derived PTK for STA " MACSTR " BSSID " MACSTR,
+                  MAC2STR(sta->addr), MAC2STR(bss->bssid));
+       sta->counters[WLANTEST_STA_COUNTER_PTK_LEARNED]++;
+       if (sta->ptk_set) {
+               /*
+                * Rekeying - use new PTK for EAPOL-Key frames, but continue
+                * using the old PTK for frame decryption.
+                */
+               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);
+               wpa_hexdump(MSG_DEBUG, "TPTK:TK1", sta->tptk.tk1, 16);
+               if (ptk_len > 48)
+                       wpa_hexdump(MSG_DEBUG, "TPTK:TK2", sta->tptk.u.tk2,
+                                   16);
+               sta->tptk_set = 1;
+               return 0;
+       }
+       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);
+       wpa_hexdump(MSG_DEBUG, "PTK:TK1", sta->ptk.tk1, 16);
+       if (ptk_len > 48)
+               wpa_hexdump(MSG_DEBUG, "PTK:TK2", sta->ptk.u.tk2, 16);
+       sta->ptk_set = 1;
+       os_memset(sta->rsc_tods, 0, sizeof(sta->rsc_tods));
+       os_memset(sta->rsc_fromds, 0, sizeof(sta->rsc_fromds));
+       return 0;
+}
+
+
+static void derive_ptk(struct wlantest *wt, struct wlantest_bss *bss,
+                      struct wlantest_sta *sta, u16 ver,
+                      const u8 *data, size_t len)
+{
+       struct wlantest_pmk *pmk;
+
+       wpa_printf(MSG_DEBUG, "Trying to derive PTK for " MACSTR,
+                  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)
+                       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)
+                       return;
+       }
+       wpa_printf(MSG_DEBUG, "No matching PMK found to derive PTK");
+}
+
+
+static void rx_data_eapol_key_2_of_4(struct wlantest *wt, const u8 *dst,
+                                    const u8 *src, const u8 *data, size_t len)
+{
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+       const struct ieee802_1x_hdr *eapol;
+       const struct wpa_eapol_key *hdr;
+       const u8 *key_data, *kck;
+       u16 key_info, key_data_len;
+       struct wpa_eapol_ie_parse ie;
+
+       wpa_printf(MSG_DEBUG, "EAPOL-Key 2/4 " MACSTR " -> " MACSTR,
+                  MAC2STR(src), MAC2STR(dst));
+       bss = bss_get(wt, dst);
+       if (bss == NULL)
+               return;
+       sta = sta_get(bss, src);
+       if (sta == NULL)
+               return;
+
+       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));
+       }
+       if (!is_zero(hdr->key_rsc, 8)) {
+               wpa_printf(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);
+       key_data_len = WPA_GET_BE16(hdr->key_data_length);
+       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");
+               return;
+       }
+
+       kck = sta->ptk.kck;
+       if (sta->tptk_set) {
+               wpa_printf(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");
+               return;
+       }
+       wpa_printf(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");
+               return;
+       }
+
+       if (ie.wpa_ie) {
+               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));
+                       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);
+               }
+       }
+
+       if (ie.rsn_ie) {
+               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));
+                       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);
+               }
+       }
+}
+
+
+static u8 * decrypt_eapol_key_data_rc4(const u8 *kek,
+                                      const struct wpa_eapol_key *hdr,
+                                      size_t *len)
+{
+       u8 ek[32], *buf;
+       u16 keydatalen = WPA_GET_BE16(hdr->key_data_length);
+
+       buf = os_malloc(keydatalen);
+       if (buf == NULL)
+               return NULL;
+
+       os_memcpy(ek, hdr->key_iv, 16);
+       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");
+               os_free(buf);
+               return NULL;
+       }
+
+       *len = keydatalen;
+       return buf;
+}
+
+
+static u8 * decrypt_eapol_key_data_aes(const u8 *kek,
+                                      const struct wpa_eapol_key *hdr,
+                                      size_t *len)
+{
+       u8 *buf;
+       u16 keydatalen = WPA_GET_BE16(hdr->key_data_length);
+
+       if (keydatalen % 8) {
+               wpa_printf(MSG_INFO, "Unsupported AES-WRAP len %d",
+                          keydatalen);
+               return NULL;
+       }
+       keydatalen -= 8; /* AES-WRAP adds 8 bytes */
+       buf = os_malloc(keydatalen);
+       if (buf == NULL)
+               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");
+               return NULL;
+       }
+
+       *len = keydatalen;
+       return buf;
+}
+
+
+static u8 * decrypt_eapol_key_data(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);
+       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);
+       default:
+               wpa_printf(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)
+{
+       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");
+               return;
+       }
+
+       if (ie.wpa_ie) {
+               wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - WPA IE",
+                           ie.wpa_ie, ie.wpa_ie_len);
+       }
+
+       if (ie.rsn_ie) {
+               wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - RSN IE",
+                           ie.rsn_ie, ie.rsn_ie_len);
+       }
+
+       if (ie.gtk) {
+               wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - GTK KDE",
+                           ie.gtk, ie.gtk_len);
+               if (ie.gtk_len >= 2 && ie.gtk_len <= 2 + 32) {
+                       int id;
+                       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]);
+                       wpa_hexdump(MSG_DEBUG, "GTK", ie.gtk + 2,
+                                   ie.gtk_len - 2);
+                       bss->gtk_len[id] = ie.gtk_len - 2;
+                       os_memcpy(bss->gtk[id], 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];
+                       bss->rsc[id][3] = rsc[2];
+                       bss->rsc[id][4] = rsc[1];
+                       bss->rsc[id][5] = rsc[0];
+                       bss->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);
+               }
+       }
+
+       if (ie.igtk) {
+               wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - IGTK KDE",
+                           ie.igtk, ie.igtk_len);
+               if (ie.igtk_len == 24) {
+                       u16 id;
+                       id = WPA_GET_LE16(ie.igtk);
+                       if (id > 5) {
+                               wpa_printf(MSG_INFO, "Unexpected IGTK KeyID "
+                                          "%u", id);
+                       } else {
+                               const u8 *ipn;
+                               wpa_printf(MSG_DEBUG, "IGTK KeyID %u", id);
+                               wpa_hexdump(MSG_DEBUG, "IPN", ie.igtk + 2, 6);
+                               wpa_hexdump(MSG_DEBUG, "IGTK", ie.igtk + 8,
+                                           16);
+                               os_memcpy(bss->igtk[id], ie.igtk + 8, 16);
+                               bss->igtk_set[id] = 1;
+                               ipn = ie.igtk + 2;
+                               bss->ipn[id][0] = ipn[5];
+                               bss->ipn[id][1] = ipn[4];
+                               bss->ipn[id][2] = ipn[3];
+                               bss->ipn[id][3] = ipn[2];
+                               bss->ipn[id][4] = ipn[1];
+                               bss->ipn[id][5] = ipn[0];
+                               bss->igtk_idx = id;
+                       }
+               } else {
+                       wpa_printf(MSG_INFO, "Invalid IGTK KDE length %u",
+                                  (unsigned) ie.igtk_len);
+               }
+       }
+}
+
+
+static void rx_data_eapol_key_3_of_4(struct wlantest *wt, const u8 *dst,
+                                    const u8 *src, const u8 *data, size_t len)
+{
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+       const struct ieee802_1x_hdr *eapol;
+       const struct wpa_eapol_key *hdr;
+       const u8 *key_data, *kck;
+       int recalc = 0;
+       u16 key_info, ver;
+       u8 *decrypted_buf = NULL;
+       const u8 *decrypted;
+       size_t decrypted_len = 0;
+       struct wpa_eapol_ie_parse ie;
+
+       wpa_printf(MSG_DEBUG, "EAPOL-Key 3/4 " MACSTR " -> " MACSTR,
+                  MAC2STR(src), MAC2STR(dst));
+       bss = bss_get(wt, src);
+       if (bss == NULL)
+               return;
+       sta = sta_get(bss, dst);
+       if (sta == NULL)
+               return;
+
+       eapol = (const struct ieee802_1x_hdr *) data;
+       hdr = (const struct wpa_eapol_key *) (eapol + 1);
+       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");
+               recalc = 1;
+       }
+       os_memcpy(sta->anonce, hdr->key_nonce, WPA_NONCE_LEN);
+       if (recalc) {
+               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 3/4");
+               return;
+       }
+
+       kck = sta->ptk.kck;
+       if (sta->tptk_set) {
+               wpa_printf(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 3/4 MIC");
+               return;
+       }
+       wpa_printf(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");
+               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_len);
+               if (decrypted_buf == NULL) {
+                       wpa_printf(MSG_INFO, "Failed to decrypt EAPOL-Key Key "
+                                  "Data");
+                       return;
+               }
+               decrypted = decrypted_buf;
+               wpa_hexdump(MSG_DEBUG, "Decrypted EAPOL-Key Key Data",
+                           decrypted, decrypted_len);
+       }
+       if (wt->write_pcap_dumper && decrypted != key_data) {
+               /* Fill in a dummy Data frame header */
+               u8 buf[24 + 8 + sizeof(*eapol) + sizeof(*hdr)];
+               struct ieee80211_hdr *h;
+               struct wpa_eapol_key *k;
+               const u8 *p;
+               u8 *pos;
+               size_t plain_len;
+
+               plain_len = decrypted_len;
+               p = decrypted;
+               while (p + 1 < decrypted + decrypted_len) {
+                       if (p[0] == 0xdd && p[1] == 0x00) {
+                               /* Remove padding */
+                               plain_len = p - decrypted;
+                               break;
+                       }
+                       p += 2 + p[1];
+               }
+
+               os_memset(buf, 0, sizeof(buf));
+               h = (struct ieee80211_hdr *) buf;
+               h->frame_control = host_to_le16(0x0208);
+               os_memcpy(h->addr1, dst, ETH_ALEN);
+               os_memcpy(h->addr2, src, ETH_ALEN);
+               os_memcpy(h->addr3, src, ETH_ALEN);
+               pos = (u8 *) (h + 1);
+               os_memcpy(pos, "\xaa\xaa\x03\x00\x00\x00\x88\x8e", 8);
+               pos += 8;
+               os_memcpy(pos, eapol, sizeof(*eapol));
+               pos += sizeof(*eapol);
+               os_memcpy(pos, hdr, sizeof(*hdr));
+               k = (struct wpa_eapol_key *) pos;
+               WPA_PUT_BE16(k->key_info,
+                            key_info & ~WPA_KEY_INFO_ENCR_KEY_DATA);
+               WPA_PUT_BE16(k->key_data_length, plain_len);
+               write_pcap_decrypted(wt, buf, sizeof(buf),
+                                    decrypted, plain_len);
+       }
+
+       if (wpa_supplicant_parse_ies(decrypted, decrypted_len, &ie) < 0) {
+               wpa_printf(MSG_INFO, "Failed to parse EAPOL-Key Key Data");
+               os_free(decrypted_buf);
+               return;
+       }
+
+       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));
+               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 "
+                           "Response",
+                           bss->wpaie,
+                           bss->wpaie[0] ? 2 + bss->wpaie[1] : 0);
+       }
+
+       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));
+               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",
+                           bss->rsnie,
+                           bss->rsnie[0] ? 2 + bss->rsnie[1] : 0);
+       }
+
+       learn_kde_keys(bss, decrypted, decrypted_len, hdr->key_rsc);
+       os_free(decrypted_buf);
+}
+
+
+static void rx_data_eapol_key_4_of_4(struct wlantest *wt, const u8 *dst,
+                                    const u8 *src, const u8 *data, size_t len)
+{
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+       const struct ieee802_1x_hdr *eapol;
+       const struct wpa_eapol_key *hdr;
+       u16 key_info;
+       const u8 *kck;
+
+       wpa_printf(MSG_DEBUG, "EAPOL-Key 4/4 " MACSTR " -> " MACSTR,
+                  MAC2STR(src), MAC2STR(dst));
+       bss = bss_get(wt, dst);
+       if (bss == NULL)
+               return;
+       sta = sta_get(bss, src);
+       if (sta == NULL)
+               return;
+
+       eapol = (const struct ieee802_1x_hdr *) data;
+       hdr = (const struct wpa_eapol_key *) (eapol + 1);
+       if (!is_zero(hdr->key_rsc, 8)) {
+               wpa_printf(MSG_INFO, "EAPOL-Key 4/4 from " MACSTR " used "
+                          "non-zero Key RSC", MAC2STR(src));
+       }
+       key_info = WPA_GET_BE16(hdr->key_info);
+
+       if (!sta->ptk_set && !sta->tptk_set) {
+               wpa_printf(MSG_DEBUG, "No PTK known to process EAPOL-Key 4/4");
+               return;
+       }
+
+       kck = sta->ptk.kck;
+       if (sta->tptk_set) {
+               wpa_printf(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 4/4 MIC");
+               return;
+       }
+       wpa_printf(MSG_DEBUG, "Valid MIC found in EAPOL-Key 4/4");
+       if (sta->tptk_set) {
+               wpa_printf(MSG_DEBUG, "Update PTK (rekeying)");
+               os_memcpy(&sta->ptk, &sta->tptk, sizeof(sta->ptk));
+               sta->ptk_set = 1;
+               sta->tptk_set = 0;
+               os_memset(sta->rsc_tods, 0, sizeof(sta->rsc_tods));
+               os_memset(sta->rsc_fromds, 0, sizeof(sta->rsc_fromds));
+       }
+}
+
+
+static void rx_data_eapol_key_1_of_2(struct wlantest *wt, const u8 *dst,
+                                    const u8 *src, const u8 *data, size_t len)
+{
+       struct wlantest_bss *bss;
+       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;
+
+       wpa_printf(MSG_DEBUG, "EAPOL-Key 1/2 " MACSTR " -> " MACSTR,
+                  MAC2STR(src), MAC2STR(dst));
+       bss = bss_get(wt, src);
+       if (bss == NULL)
+               return;
+       sta = sta_get(bss, dst);
+       if (sta == NULL)
+               return;
+
+       eapol = (const struct ieee802_1x_hdr *) data;
+       hdr = (const struct wpa_eapol_key *) (eapol + 1);
+       key_info = WPA_GET_BE16(hdr->key_info);
+
+       if (!sta->ptk_set) {
+               wpa_printf(MSG_DEBUG, "No PTK known to process EAPOL-Key 1/2");
+               return;
+       }
+
+       if (sta->ptk_set &&
+           check_mic(sta->ptk.kck, key_info & WPA_KEY_INFO_TYPE_MASK,
+                     data, len) < 0) {
+               wpa_printf(MSG_INFO, "Mismatch in EAPOL-Key 1/2 MIC");
+               return;
+       }
+       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_len);
+       if (decrypted == NULL) {
+               wpa_printf(MSG_INFO, "Failed to decrypt EAPOL-Key Key Data");
+               return;
+       }
+       wpa_hexdump(MSG_DEBUG, "Decrypted EAPOL-Key Key Data",
+                   decrypted, decrypted_len);
+       if (wt->write_pcap_dumper) {
+               /* Fill in a dummy Data frame header */
+               u8 buf[24 + 8 + sizeof(*eapol) + sizeof(*hdr)];
+               struct ieee80211_hdr *h;
+               struct wpa_eapol_key *k;
+               u8 *pos;
+               size_t plain_len;
+
+               plain_len = decrypted_len;
+               pos = decrypted;
+               while (pos + 1 < decrypted + decrypted_len) {
+                       if (pos[0] == 0xdd && pos[1] == 0x00) {
+                               /* Remove padding */
+                               plain_len = pos - decrypted;
+                               break;
+                       }
+                       pos += 2 + pos[1];
+               }
+
+               os_memset(buf, 0, sizeof(buf));
+               h = (struct ieee80211_hdr *) buf;
+               h->frame_control = host_to_le16(0x0208);
+               os_memcpy(h->addr1, dst, ETH_ALEN);
+               os_memcpy(h->addr2, src, ETH_ALEN);
+               os_memcpy(h->addr3, src, ETH_ALEN);
+               pos = (u8 *) (h + 1);
+               os_memcpy(pos, "\xaa\xaa\x03\x00\x00\x00\x88\x8e", 8);
+               pos += 8;
+               os_memcpy(pos, eapol, sizeof(*eapol));
+               pos += sizeof(*eapol);
+               os_memcpy(pos, hdr, sizeof(*hdr));
+               k = (struct wpa_eapol_key *) pos;
+               WPA_PUT_BE16(k->key_info,
+                            key_info & ~WPA_KEY_INFO_ENCR_KEY_DATA);
+               WPA_PUT_BE16(k->key_data_length, plain_len);
+               write_pcap_decrypted(wt, buf, sizeof(buf),
+                                    decrypted, plain_len);
+       }
+       if (sta->proto & WPA_PROTO_RSN)
+               learn_kde_keys(bss, decrypted, decrypted_len, hdr->key_rsc);
+       else {
+               int klen = bss->group_cipher == WPA_CIPHER_TKIP ? 32 : 16;
+               if (decrypted_len == klen) {
+                       const u8 *rsc = hdr->key_rsc;
+                       int id;
+                       id = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
+                               WPA_KEY_INFO_KEY_INDEX_SHIFT;
+                       wpa_printf(MSG_DEBUG, "GTK key index %d", id);
+                       wpa_hexdump(MSG_DEBUG, "GTK", decrypted,
+                                   decrypted_len);
+                       bss->gtk_len[id] = decrypted_len;
+                       os_memcpy(bss->gtk[id], decrypted, decrypted_len);
+                       bss->rsc[id][0] = rsc[5];
+                       bss->rsc[id][1] = rsc[4];
+                       bss->rsc[id][2] = rsc[3];
+                       bss->rsc[id][3] = rsc[2];
+                       bss->rsc[id][4] = rsc[1];
+                       bss->rsc[id][5] = rsc[0];
+                       wpa_hexdump(MSG_DEBUG, "RSC", bss->rsc[id], 6);
+               } else {
+                       wpa_printf(MSG_INFO, "Unexpected WPA Key Data length "
+                                  "in Group Key msg 1/2 from " MACSTR,
+                                  MAC2STR(src));
+               }
+       }
+       os_free(decrypted);
+}
+
+
+static void rx_data_eapol_key_2_of_2(struct wlantest *wt, const u8 *dst,
+                                    const u8 *src, const u8 *data, size_t len)
+{
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+       const struct ieee802_1x_hdr *eapol;
+       const struct wpa_eapol_key *hdr;
+       u16 key_info;
+
+       wpa_printf(MSG_DEBUG, "EAPOL-Key 2/2 " MACSTR " -> " MACSTR,
+                  MAC2STR(src), MAC2STR(dst));
+       bss = bss_get(wt, dst);
+       if (bss == NULL)
+               return;
+       sta = sta_get(bss, src);
+       if (sta == NULL)
+               return;
+
+       eapol = (const struct ieee802_1x_hdr *) data;
+       hdr = (const struct wpa_eapol_key *) (eapol + 1);
+       if (!is_zero(hdr->key_rsc, 8)) {
+               wpa_printf(MSG_INFO, "EAPOL-Key 2/2 from " MACSTR " used "
+                          "non-zero Key RSC", MAC2STR(src));
+       }
+       key_info = WPA_GET_BE16(hdr->key_info);
+
+       if (!sta->ptk_set) {
+               wpa_printf(MSG_DEBUG, "No PTK known to process EAPOL-Key 2/2");
+               return;
+       }
+
+       if (sta->ptk_set &&
+           check_mic(sta->ptk.kck, key_info & WPA_KEY_INFO_TYPE_MASK,
+                     data, len) < 0) {
+               wpa_printf(MSG_INFO, "Mismatch in EAPOL-Key 2/2 MIC");
+               return;
+       }
+       wpa_printf(MSG_DEBUG, "Valid MIC found in EAPOL-Key 2/2");
+}
+
+
+static void rx_data_eapol_key(struct wlantest *wt, const u8 *dst,
+                             const u8 *src, const u8 *data, size_t len,
+                             int prot)
+{
+       const struct ieee802_1x_hdr *eapol;
+       const struct wpa_eapol_key *hdr;
+       const u8 *key_data;
+       u16 key_info, key_length, ver, key_data_length;
+
+       eapol = (const struct ieee802_1x_hdr *) data;
+       hdr = (const struct wpa_eapol_key *) (eapol + 1);
+
+       wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key",
+                   (const u8 *) hdr, len - sizeof(*eapol));
+       if (len < sizeof(*hdr)) {
+               wpa_printf(MSG_INFO, "Too short EAPOL-Key frame from " MACSTR,
+                          MAC2STR(src));
+               return;
+       }
+
+       if (hdr->type == EAPOL_KEY_TYPE_RC4) {
+               /* TODO: EAPOL-Key RC4 for WEP */
+               wpa_printf(MSG_INFO, "EAPOL-Key Descriptor Type RC4 from "
+                          MACSTR, MAC2STR(src));
+               return;
+       }
+
+       if (hdr->type != EAPOL_KEY_TYPE_RSN &&
+           hdr->type != EAPOL_KEY_TYPE_WPA) {
+               wpa_printf(MSG_INFO, "Unsupported EAPOL-Key Descriptor Type "
+                          "%u from " MACSTR, hdr->type, MAC2STR(src));
+               return;
+       }
+
+       key_info = WPA_GET_BE16(hdr->key_info);
+       key_length = WPA_GET_BE16(hdr->key_length);
+       key_data_length = WPA_GET_BE16(hdr->key_data_length);
+       key_data = (const u8 *) (hdr + 1);
+       if (key_data + key_data_length > data + len) {
+               wpa_printf(MSG_INFO, "Truncated EAPOL-Key from " MACSTR,
+                          MAC2STR(src));
+               return;
+       }
+       if (key_data + key_data_length < data + len) {
+               wpa_hexdump(MSG_DEBUG, "Extra data after EAPOL-Key Key Data "
+                           "field", key_data + key_data_length,
+                       data + len - key_data - key_data_length);
+       }
+
+
+       ver = key_info & WPA_KEY_INFO_TYPE_MASK;
+       wpa_printf(MSG_DEBUG, "EAPOL-Key ver=%u %c idx=%u%s%s%s%s%s%s%s%s "
+                  "datalen=%u",
+                  ver, key_info & WPA_KEY_INFO_KEY_TYPE ? 'P' : 'G',
+                  (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
+                  WPA_KEY_INFO_KEY_INDEX_SHIFT,
+                  (key_info & WPA_KEY_INFO_INSTALL) ? " Install" : "",
+                  (key_info & WPA_KEY_INFO_ACK) ? " ACK" : "",
+                  (key_info & WPA_KEY_INFO_MIC) ? " MIC" : "",
+                  (key_info & WPA_KEY_INFO_SECURE) ? " Secure" : "",
+                  (key_info & WPA_KEY_INFO_ERROR) ? " Error" : "",
+                  (key_info & WPA_KEY_INFO_REQUEST) ? " Request" : "",
+                  (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) ? " Encr" : "",
+                  (key_info & WPA_KEY_INFO_SMK_MESSAGE) ? " SMK" : "",
+                  key_data_length);
+
+       if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
+           ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
+           ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+               wpa_printf(MSG_INFO, "Unsupported EAPOL-Key Key Descriptor "
+                          "Version %u from " MACSTR, ver, MAC2STR(src));
+               return;
+       }
+
+       wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Replay Counter",
+                   hdr->replay_counter, WPA_REPLAY_COUNTER_LEN);
+       wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Nonce",
+                   hdr->key_nonce, WPA_NONCE_LEN);
+       wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key IV",
+                   hdr->key_iv, 16);
+       wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key RSC",
+                   hdr->key_rsc, WPA_KEY_RSC_LEN);
+       wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key MIC",
+                   hdr->key_mic, 16);
+       wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data",
+                   key_data, key_data_length);
+
+       if (hdr->type == EAPOL_KEY_TYPE_RSN &&
+           (key_info & (WPA_KEY_INFO_KEY_INDEX_MASK | BIT(14) | BIT(15))) !=
+           0) {
+               wpa_printf(MSG_INFO, "RSN EAPOL-Key with non-zero reserved "
+                          "Key Info bits 0x%x from " MACSTR,
+                          key_info, MAC2STR(src));
+       }
+
+       if (hdr->type == EAPOL_KEY_TYPE_WPA &&
+           (key_info & (WPA_KEY_INFO_ENCR_KEY_DATA |
+                        WPA_KEY_INFO_SMK_MESSAGE |BIT(14) | BIT(15))) != 0) {
+               wpa_printf(MSG_INFO, "WPA EAPOL-Key with non-zero reserved "
+                          "Key Info bits 0x%x from " MACSTR,
+                          key_info, MAC2STR(src));
+       }
+
+       if (key_length > 32) {
+               wpa_printf(MSG_INFO, "EAPOL-Key with invalid Key Length %d "
+                          "from " MACSTR, key_length, MAC2STR(src));
+       }
+
+       if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
+           !is_zero(hdr->key_iv, 16)) {
+               wpa_printf(MSG_INFO, "EAPOL-Key with non-zero Key IV "
+                          "(reserved with ver=%d) field from " MACSTR,
+                          ver, MAC2STR(src));
+               wpa_hexdump(MSG_INFO, "EAPOL-Key Key IV (reserved)",
+                           hdr->key_iv, 16);
+       }
+
+       if (!is_zero(hdr->key_id, 8)) {
+               wpa_printf(MSG_INFO, "EAPOL-Key with non-zero Key ID "
+                          "(reserved) field from " MACSTR, MAC2STR(src));
+               wpa_hexdump(MSG_INFO, "EAPOL-Key Key ID (reserved)",
+                           hdr->key_id, 8);
+       }
+
+       if (hdr->key_rsc[6] || hdr->key_rsc[7]) {
+               wpa_printf(MSG_INFO, "EAPOL-Key with non-zero Key RSC octets "
+                          "(last two are unused)" MACSTR, MAC2STR(src));
+       }
+
+       if (key_info & (WPA_KEY_INFO_ERROR | WPA_KEY_INFO_REQUEST))
+               return;
+
+       if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
+               return;
+
+       if (key_info & WPA_KEY_INFO_KEY_TYPE) {
+               /* 4-Way Handshake */
+               switch (key_info & (WPA_KEY_INFO_SECURE |
+                                   WPA_KEY_INFO_MIC |
+                                   WPA_KEY_INFO_ACK |
+                                   WPA_KEY_INFO_INSTALL)) {
+               case WPA_KEY_INFO_ACK:
+                       rx_data_eapol_key_1_of_4(wt, dst, src, data, len);
+                       break;
+               case WPA_KEY_INFO_MIC:
+                       if (key_data_length == 0)
+                               rx_data_eapol_key_4_of_4(wt, dst, src, data,
+                                                        len);
+                       else
+                               rx_data_eapol_key_2_of_4(wt, dst, src, data,
+                                                        len);
+                       break;
+               case WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK |
+                       WPA_KEY_INFO_INSTALL:
+                       /* WPA does not include Secure bit in 3/4 */
+                       rx_data_eapol_key_3_of_4(wt, dst, src, data, len);
+                       break;
+               case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+                       WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL:
+                       rx_data_eapol_key_3_of_4(wt, dst, src, data, len);
+                       break;
+               case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC:
+                       if (key_data_length == 0)
+                               rx_data_eapol_key_4_of_4(wt, dst, src, data,
+                                                        len);
+                       else
+                               rx_data_eapol_key_2_of_4(wt, dst, src, data,
+                                                        len);
+                       break;
+               default:
+                       wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key frame");
+                       break;
+               }
+       } else {
+               /* Group Key Handshake */
+               switch (key_info & (WPA_KEY_INFO_SECURE |
+                                   WPA_KEY_INFO_MIC |
+                                   WPA_KEY_INFO_ACK)) {
+               case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+                       WPA_KEY_INFO_ACK:
+                       rx_data_eapol_key_1_of_2(wt, dst, src, data, len);
+                       break;
+               case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC:
+                       rx_data_eapol_key_2_of_2(wt, dst, src, data, len);
+                       break;
+               default:
+                       wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key frame");
+                       break;
+               }
+       }
+}
+
+
+void rx_data_eapol(struct wlantest *wt, const u8 *dst, const u8 *src,
+                  const u8 *data, size_t len, int prot)
+{
+       const struct ieee802_1x_hdr *hdr;
+       u16 length;
+       const u8 *p;
+
+       wpa_hexdump(MSG_EXCESSIVE, "EAPOL", data, len);
+       if (len < sizeof(*hdr)) {
+               wpa_printf(MSG_INFO, "Too short EAPOL frame from " MACSTR,
+                          MAC2STR(src));
+               return;
+       }
+
+       hdr = (const struct ieee802_1x_hdr *) data;
+       length = be_to_host16(hdr->length);
+       wpa_printf(MSG_DEBUG, "RX EAPOL: " MACSTR " -> " MACSTR "%s ver=%u "
+                  "type=%u len=%u",
+                  MAC2STR(src), MAC2STR(dst), prot ? " Prot" : "",
+                  hdr->version, hdr->type, length);
+       if (hdr->version < 1 || hdr->version > 3) {
+               wpa_printf(MSG_INFO, "Unexpected EAPOL version %u from "
+                          MACSTR, hdr->version, MAC2STR(src));
+       }
+       if (sizeof(*hdr) + length > len) {
+               wpa_printf(MSG_INFO, "Truncated EAPOL frame from " MACSTR,
+                          MAC2STR(src));
+               return;
+       }
+
+       if (sizeof(*hdr) + length < len) {
+               wpa_printf(MSG_INFO, "EAPOL frame with %d extra bytes",
+                          (int) (len - sizeof(*hdr) - length));
+       }
+       p = (const u8 *) (hdr + 1);
+
+       switch (hdr->type) {
+       case IEEE802_1X_TYPE_EAP_PACKET:
+               wpa_hexdump(MSG_MSGDUMP, "EAPOL - EAP packet", p, length);
+               break;
+       case IEEE802_1X_TYPE_EAPOL_START:
+               wpa_hexdump(MSG_MSGDUMP, "EAPOL-Start", p, length);
+               break;
+       case IEEE802_1X_TYPE_EAPOL_LOGOFF:
+               wpa_hexdump(MSG_MSGDUMP, "EAPOL-Logoff", p, length);
+               break;
+       case IEEE802_1X_TYPE_EAPOL_KEY:
+               rx_data_eapol_key(wt, dst, src, data, sizeof(*hdr) + length,
+                                 prot);
+               break;
+       case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT:
+               wpa_hexdump(MSG_MSGDUMP, "EAPOL - Encapsulated ASF alert",
+                           p, length);
+               break;
+       default:
+               wpa_hexdump(MSG_MSGDUMP, "Unknown EAPOL payload", p, length);
+               break;
+       }
+}
diff --git a/wlantest/rx_ip.c b/wlantest/rx_ip.c
new file mode 100644 (file)
index 0000000..2070159
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+
+#include "utils/common.h"
+#include "wlantest.h"
+
+
+static void ping_update(struct wlantest_sta *sta, int req, u32 src, u32 dst,
+                       u16 id, u16 seq)
+{
+       if (req) {
+               sta->icmp_echo_req_src = src;
+               sta->icmp_echo_req_dst = dst;
+               sta->icmp_echo_req_id = id;
+               sta->icmp_echo_req_seq = seq;
+               return;
+       }
+
+       if (sta->icmp_echo_req_src == dst &&
+           sta->icmp_echo_req_dst == src &&
+           sta->icmp_echo_req_id == id &&
+           sta->icmp_echo_req_seq == seq) {
+               sta->counters[WLANTEST_STA_COUNTER_PING_OK]++;
+               if (sta->counters[WLANTEST_STA_COUNTER_ASSOCREQ_TX] == 0 &&
+                   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));
+       }
+}
+
+
+static void rx_data_icmp(struct wlantest *wt, const u8 *bssid,
+                        const u8 *sta_addr, u32 dst, u32 src,
+                        const u8 *data, size_t len, const u8 *peer_addr)
+{
+       struct in_addr addr;
+       char buf[20];
+       const struct icmphdr *hdr;
+       u16 id, seq;
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+
+       hdr = (const struct icmphdr *) data;
+       if (len < 4)
+               return;
+
+       /* TODO: check hdr->checksum */
+
+       if (hdr->type != ICMP_ECHOREPLY && hdr->type != ICMP_ECHO)
+               return;
+       if (len < 8)
+               return;
+
+       id = ntohs(hdr->un.echo.id);
+       seq = ntohs(hdr->un.echo.sequence);
+
+       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]" : "");
+
+       bss = bss_find(wt, bssid);
+       if (bss == NULL) {
+               wpa_printf(MSG_INFO, "No BSS " MACSTR " known for ICMP packet",
+                          MAC2STR(bssid));
+               return;
+       }
+
+       if (sta_addr == NULL)
+               return; /* FromDS broadcast ping */
+
+       sta = sta_find(bss, sta_addr);
+       if (sta == NULL) {
+               wpa_printf(MSG_INFO, "No STA " MACSTR " known for ICMP packet",
+                          MAC2STR(sta_addr));
+               return;
+       }
+
+       ping_update(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);
+}
+
+
+void rx_data_ip(struct wlantest *wt, const u8 *bssid, const u8 *sta_addr,
+               const u8 *dst, const u8 *src, const u8 *data, size_t len,
+               const u8 *peer_addr)
+{
+       const struct iphdr *ip;
+       const u8 *payload;
+       size_t plen;
+       u16 frag_off, tot_len;
+
+       ip = (const struct iphdr *) data;
+       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));
+               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));
+               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));
+               return;
+       }
+
+       /* TODO: check header checksum in ip->check */
+
+       frag_off = be_to_host16(ip->frag_off);
+       if (frag_off & 0x1fff) {
+               wpa_printf(MSG_EXCESSIVE, "IP fragment reassembly not yet "
+                          "supported");
+               return;
+       }
+
+       tot_len = be_to_host16(ip->tot_len);
+       if (tot_len > len)
+               return;
+       if (tot_len < len)
+               len = tot_len;
+
+       payload = data + 4 * ip->ihl;
+       plen = len - 4 * ip->ihl;
+
+       switch (ip->protocol) {
+       case IPPROTO_ICMP:
+               rx_data_icmp(wt, bssid, sta_addr, ip->daddr, ip->saddr,
+                            payload, plen, peer_addr);
+               break;
+       }
+}
diff --git a/wlantest/rx_mgmt.c b/wlantest/rx_mgmt.c
new file mode 100644 (file)
index 0000000..c7a9390
--- /dev/null
@@ -0,0 +1,1175 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "crypto/aes_wrap.h"
+#include "wlantest.h"
+
+
+static const char * mgmt_stype(u16 stype)
+{
+       switch (stype) {
+       case WLAN_FC_STYPE_ASSOC_REQ:
+               return "ASSOC-REQ";
+       case WLAN_FC_STYPE_ASSOC_RESP:
+               return "ASSOC-RESP";
+       case WLAN_FC_STYPE_REASSOC_REQ:
+               return "REASSOC-REQ";
+       case WLAN_FC_STYPE_REASSOC_RESP:
+               return "REASSOC-RESP";
+       case WLAN_FC_STYPE_PROBE_REQ:
+               return "PROBE-REQ";
+       case WLAN_FC_STYPE_PROBE_RESP:
+               return "PROBE-RESP";
+       case WLAN_FC_STYPE_BEACON:
+               return "BEACON";
+       case WLAN_FC_STYPE_ATIM:
+               return "ATIM";
+       case WLAN_FC_STYPE_DISASSOC:
+               return "DISASSOC";
+       case WLAN_FC_STYPE_AUTH:
+               return "AUTH";
+       case WLAN_FC_STYPE_DEAUTH:
+               return "DEAUTH";
+       case WLAN_FC_STYPE_ACTION:
+               return "ACTION";
+       }
+       return "??";
+}
+
+
+static void rx_mgmt_beacon(struct wlantest *wt, const u8 *data, size_t len)
+{
+       const struct ieee80211_mgmt *mgmt;
+       struct wlantest_bss *bss;
+       struct ieee802_11_elems elems;
+
+       mgmt = (const struct ieee80211_mgmt *) data;
+       bss = bss_get(wt, mgmt->bssid);
+       if (bss == NULL)
+               return;
+       if (bss->proberesp_seen)
+               return; /* do not override with Beacon data */
+       bss->capab_info = le_to_host16(mgmt->u.beacon.capab_info);
+       if (ieee802_11_parse_elems(mgmt->u.beacon.variable,
+                                  len - (mgmt->u.beacon.variable - data),
+                                  &elems, 0) == ParseFailed) {
+               if (bss->parse_error_reported)
+                       return;
+               wpa_printf(MSG_INFO, "Invalid IEs in a Beacon frame from "
+                          MACSTR, MAC2STR(mgmt->sa));
+               bss->parse_error_reported = 1;
+               return;
+       }
+
+       bss_update(wt, bss, &elems);
+}
+
+
+static void rx_mgmt_probe_resp(struct wlantest *wt, const u8 *data, size_t len)
+{
+       const struct ieee80211_mgmt *mgmt;
+       struct wlantest_bss *bss;
+       struct ieee802_11_elems elems;
+
+       mgmt = (const struct ieee80211_mgmt *) data;
+       bss = bss_get(wt, mgmt->bssid);
+       if (bss == NULL)
+               return;
+
+       bss->capab_info = le_to_host16(mgmt->u.probe_resp.capab_info);
+       if (ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
+                                  len - (mgmt->u.probe_resp.variable - data),
+                                  &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));
+               bss->parse_error_reported = 1;
+               return;
+       }
+
+       bss_update(wt, bss, &elems);
+}
+
+
+static void rx_mgmt_auth(struct wlantest *wt, const u8 *data, size_t len)
+{
+       const struct ieee80211_mgmt *mgmt;
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+       u16 alg, trans, status;
+
+       mgmt = (const struct ieee80211_mgmt *) data;
+       bss = bss_get(wt, mgmt->bssid);
+       if (bss == NULL)
+               return;
+       if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
+               sta = sta_get(bss, mgmt->da);
+       else
+               sta = sta_get(bss, mgmt->sa);
+       if (sta == NULL)
+               return;
+
+       if (len < 24 + 6) {
+               wpa_printf(MSG_INFO, "Too short Authentication frame from "
+                          MACSTR, MAC2STR(mgmt->sa));
+               return;
+       }
+
+       alg = le_to_host16(mgmt->u.auth.auth_alg);
+       trans = le_to_host16(mgmt->u.auth.auth_transaction);
+       status = le_to_host16(mgmt->u.auth.status_code);
+
+       wpa_printf(MSG_DEBUG, "AUTH " MACSTR " -> " MACSTR
+                  " (alg=%u trans=%u status=%u)",
+                  MAC2STR(mgmt->sa), MAC2STR(mgmt->da), alg, trans, status);
+
+       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));
+                       sta->state = STATE2;
+               }
+       }
+
+       if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
+               sta->counters[WLANTEST_STA_COUNTER_AUTH_RX]++;
+       else
+               sta->counters[WLANTEST_STA_COUNTER_AUTH_TX]++;
+}
+
+
+static void deauth_all_stas(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));
+               sta->state = STATE1;
+       }
+}
+
+
+static void tdls_link_down(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");
+                       tdls->link_up = 0;
+               }
+       }
+}
+
+
+static void rx_mgmt_deauth(struct wlantest *wt, const u8 *data, size_t len,
+                          int valid)
+{
+       const struct ieee80211_mgmt *mgmt;
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+       u16 fc, reason;
+
+       mgmt = (const struct ieee80211_mgmt *) data;
+       bss = bss_get(wt, mgmt->bssid);
+       if (bss == NULL)
+               return;
+       if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
+               sta = sta_get(bss, mgmt->da);
+       else
+               sta = sta_get(bss, mgmt->sa);
+
+       if (len < 24 + 2) {
+               wpa_printf(MSG_INFO, "Too short Deauthentication frame from "
+                          MACSTR, MAC2STR(mgmt->sa));
+               return;
+       }
+
+       reason = le_to_host16(mgmt->u.deauth.reason_code);
+       wpa_printf(MSG_DEBUG, "DEAUTH " MACSTR " -> " MACSTR
+                  " (reason=%u) (valid=%d)",
+                  MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
+                  reason, valid);
+       wpa_hexdump(MSG_MSGDUMP, "DEAUTH payload", data + 24, len - 24);
+
+       if (sta == NULL) {
+               if (valid && mgmt->da[0] == 0xff)
+                       deauth_all_stas(bss);
+               return;
+       }
+
+       if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0) {
+               sta->counters[valid ? WLANTEST_STA_COUNTER_VALID_DEAUTH_RX :
+                             WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX]++;
+               if (sta->pwrmgt && !sta->pspoll)
+                       sta->counters[WLANTEST_STA_COUNTER_DEAUTH_RX_ASLEEP]++;
+               else
+                       sta->counters[WLANTEST_STA_COUNTER_DEAUTH_RX_AWAKE]++;
+
+               fc = le_to_host16(mgmt->frame_control);
+               if (!(fc & WLAN_FC_ISWEP) && reason == 6)
+                       sta->counters[WLANTEST_STA_COUNTER_DEAUTH_RX_RC6]++;
+               else if (!(fc & WLAN_FC_ISWEP) && reason == 7)
+                       sta->counters[WLANTEST_STA_COUNTER_DEAUTH_RX_RC7]++;
+       } else
+               sta->counters[valid ? WLANTEST_STA_COUNTER_VALID_DEAUTH_TX :
+                             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));
+               return;
+       }
+
+       if (sta->state != STATE1) {
+               wpa_printf(MSG_DEBUG, "STA " MACSTR
+                          " moved to State 1 with " MACSTR,
+                          MAC2STR(sta->addr), MAC2STR(bss->bssid));
+               sta->state = STATE1;
+       }
+       tdls_link_down(bss, sta);
+}
+
+
+static void rx_mgmt_assoc_req(struct wlantest *wt, const u8 *data, size_t len)
+{
+       const struct ieee80211_mgmt *mgmt;
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+       struct ieee802_11_elems elems;
+
+       mgmt = (const struct ieee80211_mgmt *) data;
+       bss = bss_get(wt, mgmt->bssid);
+       if (bss == NULL)
+               return;
+       sta = sta_get(bss, mgmt->sa);
+       if (sta == NULL)
+               return;
+
+       if (len < 24 + 4) {
+               wpa_printf(MSG_INFO, "Too short Association Request frame "
+                          "from " MACSTR, MAC2STR(mgmt->sa));
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "ASSOCREQ " MACSTR " -> " MACSTR
+                  " (capab=0x%x listen_int=%u)",
+                  MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
+                  le_to_host16(mgmt->u.assoc_req.capab_info),
+                  le_to_host16(mgmt->u.assoc_req.listen_interval));
+
+       sta->counters[WLANTEST_STA_COUNTER_ASSOCREQ_TX]++;
+
+       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));
+               return;
+       }
+
+       sta->assocreq_capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
+       sta->assocreq_listen_int =
+               le_to_host16(mgmt->u.assoc_req.listen_interval);
+       os_free(sta->assocreq_ies);
+       sta->assocreq_ies_len = len - (mgmt->u.assoc_req.variable - data);
+       sta->assocreq_ies = os_malloc(sta->assocreq_ies_len);
+       if (sta->assocreq_ies)
+               os_memcpy(sta->assocreq_ies, mgmt->u.assoc_req.variable,
+                         sta->assocreq_ies_len);
+
+       sta_update_assoc(sta, &elems);
+}
+
+
+static void rx_mgmt_assoc_resp(struct wlantest *wt, const u8 *data, size_t len)
+{
+       const struct ieee80211_mgmt *mgmt;
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+       u16 capab, status, aid;
+
+       mgmt = (const struct ieee80211_mgmt *) data;
+       bss = bss_get(wt, mgmt->bssid);
+       if (bss == NULL)
+               return;
+       sta = sta_get(bss, mgmt->da);
+       if (sta == NULL)
+               return;
+
+       if (len < 24 + 6) {
+               wpa_printf(MSG_INFO, "Too short Association Response frame "
+                          "from " MACSTR, MAC2STR(mgmt->sa));
+               return;
+       }
+
+       capab = le_to_host16(mgmt->u.assoc_resp.capab_info);
+       status = le_to_host16(mgmt->u.assoc_resp.status_code);
+       aid = le_to_host16(mgmt->u.assoc_resp.aid);
+
+       wpa_printf(MSG_DEBUG, "ASSOCRESP " MACSTR " -> " MACSTR
+                  " (capab=0x%x status=%u aid=%u)",
+                  MAC2STR(mgmt->sa), MAC2STR(mgmt->da), capab, status,
+                  aid & 0x3fff);
+
+       if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
+               struct ieee802_11_elems elems;
+               const u8 *ies = mgmt->u.assoc_resp.variable;
+               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));
+               } 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));
+               } else {
+                       sta->counters[
+                               WLANTEST_STA_COUNTER_ASSOCRESP_COMEBACK]++;
+               }
+       }
+
+       if (status)
+               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));
+       }
+       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));
+       }
+
+       if (sta->state < STATE3) {
+               wpa_printf(MSG_DEBUG, "STA " MACSTR
+                          " moved to State 3 with " MACSTR,
+                          MAC2STR(sta->addr), MAC2STR(bss->bssid));
+               sta->state = STATE3;
+       }
+}
+
+
+static void rx_mgmt_reassoc_req(struct wlantest *wt, const u8 *data,
+                               size_t len)
+{
+       const struct ieee80211_mgmt *mgmt;
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+       struct ieee802_11_elems elems;
+
+       mgmt = (const struct ieee80211_mgmt *) data;
+       bss = bss_get(wt, mgmt->bssid);
+       if (bss == NULL)
+               return;
+       sta = sta_get(bss, mgmt->sa);
+       if (sta == NULL)
+               return;
+
+       if (len < 24 + 4 + ETH_ALEN) {
+               wpa_printf(MSG_INFO, "Too short Reassociation Request frame "
+                          "from " MACSTR, MAC2STR(mgmt->sa));
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "REASSOCREQ " MACSTR " -> " MACSTR
+                  " (capab=0x%x listen_int=%u current_ap=" MACSTR ")",
+                  MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
+                  le_to_host16(mgmt->u.reassoc_req.capab_info),
+                  le_to_host16(mgmt->u.reassoc_req.listen_interval),
+                  MAC2STR(mgmt->u.reassoc_req.current_ap));
+
+       sta->counters[WLANTEST_STA_COUNTER_REASSOCREQ_TX]++;
+
+       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));
+               return;
+       }
+
+       sta->assocreq_capab_info =
+               le_to_host16(mgmt->u.reassoc_req.capab_info);
+       sta->assocreq_listen_int =
+               le_to_host16(mgmt->u.reassoc_req.listen_interval);
+       os_free(sta->assocreq_ies);
+       sta->assocreq_ies_len = len - (mgmt->u.reassoc_req.variable - data);
+       sta->assocreq_ies = os_malloc(sta->assocreq_ies_len);
+       if (sta->assocreq_ies)
+               os_memcpy(sta->assocreq_ies, mgmt->u.reassoc_req.variable,
+                         sta->assocreq_ies_len);
+
+       sta_update_assoc(sta, &elems);
+}
+
+
+static void rx_mgmt_reassoc_resp(struct wlantest *wt, const u8 *data,
+                                size_t len)
+{
+       const struct ieee80211_mgmt *mgmt;
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+       u16 capab, status, aid;
+
+       mgmt = (const struct ieee80211_mgmt *) data;
+       bss = bss_get(wt, mgmt->bssid);
+       if (bss == NULL)
+               return;
+       sta = sta_get(bss, mgmt->da);
+       if (sta == NULL)
+               return;
+
+       if (len < 24 + 6) {
+               wpa_printf(MSG_INFO, "Too short Reassociation Response frame "
+                          "from " MACSTR, MAC2STR(mgmt->sa));
+               return;
+       }
+
+       capab = le_to_host16(mgmt->u.reassoc_resp.capab_info);
+       status = le_to_host16(mgmt->u.reassoc_resp.status_code);
+       aid = le_to_host16(mgmt->u.reassoc_resp.aid);
+
+       wpa_printf(MSG_DEBUG, "REASSOCRESP " MACSTR " -> " MACSTR
+                  " (capab=0x%x status=%u aid=%u)",
+                  MAC2STR(mgmt->sa), MAC2STR(mgmt->da), capab, status,
+                  aid & 0x3fff);
+
+       if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
+               struct ieee802_11_elems elems;
+               const u8 *ies = mgmt->u.reassoc_resp.variable;
+               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));
+               } 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));
+               } else {
+                       sta->counters[
+                               WLANTEST_STA_COUNTER_REASSOCRESP_COMEBACK]++;
+               }
+       }
+
+       if (status)
+               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));
+       }
+       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));
+       }
+
+       if (sta->state < STATE3) {
+               wpa_printf(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)
+{
+       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));
+               sta->state = STATE2;
+       }
+}
+
+
+static void rx_mgmt_disassoc(struct wlantest *wt, const u8 *data, size_t len,
+                            int valid)
+{
+       const struct ieee80211_mgmt *mgmt;
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+       u16 fc, reason;
+
+       mgmt = (const struct ieee80211_mgmt *) data;
+       bss = bss_get(wt, mgmt->bssid);
+       if (bss == NULL)
+               return;
+       if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
+               sta = sta_get(bss, mgmt->da);
+       else
+               sta = sta_get(bss, mgmt->sa);
+
+       if (len < 24 + 2) {
+               wpa_printf(MSG_INFO, "Too short Disassociation frame from "
+                          MACSTR, MAC2STR(mgmt->sa));
+               return;
+       }
+
+       reason = le_to_host16(mgmt->u.disassoc.reason_code);
+       wpa_printf(MSG_DEBUG, "DISASSOC " MACSTR " -> " MACSTR
+                  " (reason=%u) (valid=%d)",
+                  MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
+                  reason, valid);
+       wpa_hexdump(MSG_MSGDUMP, "DISASSOC payload", data + 24, len - 24);
+
+       if (sta == NULL) {
+               if (valid && mgmt->da[0] == 0xff)
+                       disassoc_all_stas(bss);
+               return;
+       }
+
+       if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0) {
+               sta->counters[valid ? WLANTEST_STA_COUNTER_VALID_DISASSOC_RX :
+                             WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX]++;
+               if (sta->pwrmgt && !sta->pspoll)
+                       sta->counters[
+                               WLANTEST_STA_COUNTER_DISASSOC_RX_ASLEEP]++;
+               else
+                       sta->counters[
+                               WLANTEST_STA_COUNTER_DISASSOC_RX_AWAKE]++;
+
+               fc = le_to_host16(mgmt->frame_control);
+               if (!(fc & WLAN_FC_ISWEP) && reason == 6)
+                       sta->counters[WLANTEST_STA_COUNTER_DISASSOC_RX_RC6]++;
+               else if (!(fc & WLAN_FC_ISWEP) && reason == 7)
+                       sta->counters[WLANTEST_STA_COUNTER_DISASSOC_RX_RC7]++;
+       } else
+               sta->counters[valid ? WLANTEST_STA_COUNTER_VALID_DISASSOC_TX :
+                             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));
+               return;
+       }
+
+       if (sta->state < STATE2) {
+               wpa_printf(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));
+               sta->state = STATE2;
+       }
+       tdls_link_down(bss, sta);
+}
+
+
+static void rx_mgmt_action_sa_query_req(struct wlantest *wt,
+                                       struct wlantest_sta *sta,
+                                       const struct ieee80211_mgmt *mgmt,
+                                       size_t len, int valid)
+{
+       const u8 *rx_id;
+       u8 *id;
+
+       rx_id = (const u8 *) mgmt->u.action.u.sa_query_req.trans_id;
+       if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
+               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)");
+       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 ?
+                             WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_TX :
+                             WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_TX]++;
+       else
+               sta->counters[valid ?
+                             WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_RX :
+                             WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_RX]++;
+}
+
+
+static void rx_mgmt_action_sa_query_resp(struct wlantest *wt,
+                                        struct wlantest_sta *sta,
+                                        const struct ieee80211_mgmt *mgmt,
+                                        size_t len, int valid)
+{
+       const u8 *rx_id;
+       u8 *id;
+       int match;
+
+       rx_id = (const u8 *) mgmt->u.action.u.sa_query_resp.trans_id;
+       if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
+               id = sta->sta_sa_query_tr;
+       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)");
+       if (os_memcmp(mgmt->sa, sta->addr, ETH_ALEN) == 0)
+               sta->counters[(valid && match) ?
+                             WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_TX :
+                             WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_TX]++;
+       else
+               sta->counters[(valid && match) ?
+                             WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_RX :
+                             WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_RX]++;
+}
+
+
+static void rx_mgmt_action_sa_query(struct wlantest *wt,
+                                   struct wlantest_sta *sta,
+                                   const struct ieee80211_mgmt *mgmt,
+                                   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));
+               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));
+               wpa_hexdump(MSG_INFO, "SA Query extra data",
+                           ((const u8 *) mgmt) + len - elen, elen);
+       }
+
+       switch (mgmt->u.action.u.sa_query_req.action) {
+       case WLAN_SA_QUERY_REQUEST:
+               rx_mgmt_action_sa_query_req(wt, sta, mgmt, len, valid);
+               break;
+       case WLAN_SA_QUERY_RESPONSE:
+               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));
+       }
+}
+
+
+static void rx_mgmt_action(struct wlantest *wt, const u8 *data, size_t len,
+                          int valid)
+{
+       const struct ieee80211_mgmt *mgmt;
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+
+       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);
+               return; /* Ignore group addressed Action frames for now */
+       }
+       bss = bss_get(wt, mgmt->bssid);
+       if (bss == NULL)
+               return;
+       if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
+               sta = sta_get(bss, mgmt->da);
+       else
+               sta = sta_get(bss, mgmt->sa);
+       if (sta == NULL)
+               return;
+
+       if (len < 24 + 1) {
+               wpa_printf(MSG_INFO, "Too short Action frame from "
+                          MACSTR, MAC2STR(mgmt->sa));
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "ACTION " MACSTR " -> " MACSTR
+                  " (category=%u) (valid=%d)",
+                  MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
+                  mgmt->u.action.category, valid);
+       wpa_hexdump(MSG_MSGDUMP, "ACTION payload", data + 24, len - 24);
+
+       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));
+       }
+
+       switch (mgmt->u.action.category) {
+       case WLAN_ACTION_SA_QUERY:
+               rx_mgmt_action_sa_query(wt, sta, mgmt, len, valid);
+               break;
+       }
+}
+
+
+static int check_mmie_mic(const u8 *igtk, const u8 *data, size_t len)
+{
+       u8 *buf;
+       u8 mic[16];
+       u16 fc;
+       const struct ieee80211_hdr *hdr;
+
+       buf = os_malloc(len + 20 - 24);
+       if (buf == NULL)
+               return -1;
+
+       /* BIP AAD: FC(masked) A1 A2 A3 */
+       hdr = (const struct ieee80211_hdr *) data;
+       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);
+
+       /* Frame body with MMIE MIC masked to zero */
+       os_memcpy(buf + 20, data + 24, len - 24 - 8);
+       os_memset(buf + 20 + len - 24 - 8, 0, 8);
+
+       wpa_hexdump(MSG_MSGDUMP, "BIP: AAD|Body(masked)", buf, len + 20 - 24);
+       /* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */
+       if (omac1_aes_128(igtk, buf, len + 20 - 24, mic) < 0) {
+               os_free(buf);
+               return -1;
+       }
+
+       os_free(buf);
+
+       if (os_memcmp(data + len - 8, mic, 8) != 0)
+               return -1;
+
+       return 0;
+}
+
+
+static int check_bip(struct wlantest *wt, const u8 *data, size_t len)
+{
+       const struct ieee80211_mgmt *mgmt;
+       u16 fc, stype;
+       const u8 *mmie;
+       u16 keyid;
+       struct wlantest_bss *bss;
+
+       mgmt = (const struct ieee80211_mgmt *) data;
+       fc = le_to_host16(mgmt->frame_control);
+       stype = WLAN_FC_GET_STYPE(fc);
+
+       if (stype == WLAN_FC_STYPE_ACTION) {
+               if (len < 24 + 1)
+                       return 0;
+               if (mgmt->u.action.category == WLAN_ACTION_PUBLIC)
+                       return 0; /* Not a robust management frame */
+       }
+
+       bss = bss_get(wt, mgmt->bssid);
+       if (bss == NULL)
+               return 0; /* No key known yet */
+
+       if (len < 24 + 18 || data[len - 18] != WLAN_EID_MMIE ||
+           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));
+                       bss->counters[WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE]++;
+                       return -1;
+               }
+               return 0;
+       }
+
+       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));
+               keyid &= 0x0fff;
+       }
+       if (keyid < 4 || keyid > 5) {
+               wpa_printf(MSG_INFO, "Unexpected MMIE KeyID %u from " MACSTR,
+                          keyid, MAC2STR(mgmt->sa));
+               bss->counters[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE]++;
+               return 0;
+       }
+       wpa_printf(MSG_DEBUG, "MMIE KeyID %u", keyid);
+       wpa_hexdump(MSG_MSGDUMP, "MMIE IPN", mmie + 2, 6);
+       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");
+               return 0;
+       }
+
+       if (os_memcmp(mmie + 2, bss->ipn[keyid], 6) <= 0) {
+               wpa_printf(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));
+               bss->counters[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE]++;
+               return -1;
+       }
+
+       wpa_printf(MSG_DEBUG, "Valid MMIE MIC");
+       os_memcpy(bss->ipn[keyid], mmie + 2, 6);
+       bss->counters[WLANTEST_BSS_COUNTER_VALID_BIP_MMIE]++;
+
+       if (stype == WLAN_FC_STYPE_DEAUTH)
+               bss->counters[WLANTEST_BSS_COUNTER_BIP_DEAUTH]++;
+       else if (stype == WLAN_FC_STYPE_DISASSOC)
+               bss->counters[WLANTEST_BSS_COUNTER_BIP_DISASSOC]++;
+
+       return 0;
+}
+
+
+static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
+                             size_t *dlen)
+{
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+       const struct ieee80211_hdr *hdr;
+       int keyid;
+       u8 *decrypted, *frame = NULL;
+       u8 pn[6], *rsc;
+
+       hdr = (const struct ieee80211_hdr *) data;
+       bss = bss_get(wt, hdr->addr3);
+       if (bss == NULL)
+               return NULL;
+       if (os_memcmp(hdr->addr1, hdr->addr3, ETH_ALEN) == 0)
+               sta = sta_get(bss, hdr->addr2);
+       else
+               sta = sta_get(bss, hdr->addr1);
+       if (sta == NULL || !sta->ptk_set) {
+               wpa_printf(MSG_MSGDUMP, "No PTK known to decrypt the frame");
+               return NULL;
+       }
+
+       if (len < 24 + 4)
+               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));
+               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));
+       }
+
+       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));
+       }
+
+       if (os_memcmp(hdr->addr1, hdr->addr3, ETH_ALEN) == 0)
+               rsc = sta->rsc_tods[16];
+       else
+               rsc = sta->rsc_fromds[16];
+
+       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));
+               wpa_hexdump(MSG_INFO, "RX PN", pn, 6);
+               wpa_hexdump(MSG_INFO, "RSC", rsc, 6);
+       }
+
+       decrypted = ccmp_decrypt(sta->ptk.tk1, hdr, data + 24, len - 24, dlen);
+       if (decrypted) {
+               os_memcpy(rsc, pn, 6);
+               frame = os_malloc(24 + *dlen);
+               if (frame) {
+                       os_memcpy(frame, data, 24);
+                       os_memcpy(frame + 24, decrypted, *dlen);
+                       *dlen += 24;
+               }
+       }
+
+       os_free(decrypted);
+
+       return frame;
+}
+
+
+static int check_mgmt_ccmp(struct wlantest *wt, const u8 *data, size_t len)
+{
+       const struct ieee80211_mgmt *mgmt;
+       u16 fc;
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+
+       mgmt = (const struct ieee80211_mgmt *) data;
+       fc = le_to_host16(mgmt->frame_control);
+
+       if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
+               if (len > 24 &&
+                   mgmt->u.action.category == WLAN_ACTION_PUBLIC)
+                       return 0; /* Not a robust management frame */
+       }
+
+       bss = bss_get(wt, mgmt->bssid);
+       if (bss == NULL)
+               return 0;
+       if (os_memcmp(mgmt->da, mgmt->bssid, ETH_ALEN) == 0)
+               sta = sta_get(bss, mgmt->sa);
+       else
+               sta = sta_get(bss, mgmt->da);
+       if (sta == NULL)
+               return 0;
+
+       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));
+               return -1;
+       }
+
+       return 0;
+}
+
+
+void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len)
+{
+       const struct ieee80211_hdr *hdr;
+       u16 fc, stype;
+       int valid = 1;
+       u8 *decrypted = NULL;
+       size_t dlen;
+
+       if (len < 24)
+               return;
+
+       hdr = (const struct ieee80211_hdr *) data;
+       fc = le_to_host16(hdr->frame_control);
+       wt->rx_mgmt++;
+       stype = WLAN_FC_GET_STYPE(fc);
+
+       if ((hdr->addr1[0] & 0x01) &&
+           (stype == WLAN_FC_STYPE_DEAUTH ||
+            stype == WLAN_FC_STYPE_DISASSOC ||
+            stype == WLAN_FC_STYPE_ACTION)) {
+               if (check_bip(wt, data, len) < 0)
+                       valid = 0;
+       }
+
+       wpa_printf((stype == WLAN_FC_STYPE_BEACON ||
+                   stype == WLAN_FC_STYPE_PROBE_RESP ||
+                   stype == WLAN_FC_STYPE_PROBE_REQ) ?
+                  MSG_EXCESSIVE : MSG_MSGDUMP,
+                  "MGMT %s%s%s DA=" MACSTR " SA=" MACSTR " BSSID=" MACSTR,
+                  mgmt_stype(stype),
+                  fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
+                  fc & WLAN_FC_ISWEP ? " Prot" : "",
+                  MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
+                  MAC2STR(hdr->addr3));
+
+       if ((fc & WLAN_FC_ISWEP) &&
+           !(hdr->addr1[0] & 0x01) &&
+           (stype == WLAN_FC_STYPE_DEAUTH ||
+            stype == WLAN_FC_STYPE_DISASSOC ||
+            stype == WLAN_FC_STYPE_ACTION)) {
+               decrypted = mgmt_ccmp_decrypt(wt, data, len, &dlen);
+               if (decrypted) {
+                       write_pcap_decrypted(wt, decrypted, dlen, NULL, 0);
+                       data = decrypted;
+                       len = dlen;
+               } else
+                       valid = 0;
+       }
+
+       if (!(fc & WLAN_FC_ISWEP) &&
+           !(hdr->addr1[0] & 0x01) &&
+           (stype == WLAN_FC_STYPE_DEAUTH ||
+            stype == WLAN_FC_STYPE_DISASSOC ||
+            stype == WLAN_FC_STYPE_ACTION)) {
+               if (check_mgmt_ccmp(wt, data, len) < 0)
+                       valid = 0;
+       }
+
+       switch (stype) {
+       case WLAN_FC_STYPE_BEACON:
+               rx_mgmt_beacon(wt, data, len);
+               break;
+       case WLAN_FC_STYPE_PROBE_RESP:
+               rx_mgmt_probe_resp(wt, data, len);
+               break;
+       case WLAN_FC_STYPE_AUTH:
+               rx_mgmt_auth(wt, data, len);
+               break;
+       case WLAN_FC_STYPE_DEAUTH:
+               rx_mgmt_deauth(wt, data, len, valid);
+               break;
+       case WLAN_FC_STYPE_ASSOC_REQ:
+               rx_mgmt_assoc_req(wt, data, len);
+               break;
+       case WLAN_FC_STYPE_ASSOC_RESP:
+               rx_mgmt_assoc_resp(wt, data, len);
+               break;
+       case WLAN_FC_STYPE_REASSOC_REQ:
+               rx_mgmt_reassoc_req(wt, data, len);
+               break;
+       case WLAN_FC_STYPE_REASSOC_RESP:
+               rx_mgmt_reassoc_resp(wt, data, len);
+               break;
+       case WLAN_FC_STYPE_DISASSOC:
+               rx_mgmt_disassoc(wt, data, len, valid);
+               break;
+       case WLAN_FC_STYPE_ACTION:
+               rx_mgmt_action(wt, data, len, valid);
+               break;
+       }
+
+       os_free(decrypted);
+
+       wt->last_mgmt_valid = valid;
+}
+
+
+static void rx_mgmt_deauth_ack(struct wlantest *wt,
+                              const struct ieee80211_hdr *hdr)
+{
+       const struct ieee80211_mgmt *mgmt;
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+
+       mgmt = (const struct ieee80211_mgmt *) hdr;
+       bss = bss_get(wt, mgmt->bssid);
+       if (bss == NULL)
+               return;
+       if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
+               sta = sta_get(bss, mgmt->da);
+       else
+               sta = sta_get(bss, mgmt->sa);
+       if (sta == NULL)
+               return;
+
+       wpa_printf(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 ?
+                       WLANTEST_STA_COUNTER_VALID_DEAUTH_RX_ACK :
+                       WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX_ACK;
+               sta->counters[c]++;
+       }
+}
+
+
+static void rx_mgmt_disassoc_ack(struct wlantest *wt,
+                                const struct ieee80211_hdr *hdr)
+{
+       const struct ieee80211_mgmt *mgmt;
+       struct wlantest_bss *bss;
+       struct wlantest_sta *sta;
+
+       mgmt = (const struct ieee80211_mgmt *) hdr;
+       bss = bss_get(wt, mgmt->bssid);
+       if (bss == NULL)
+               return;
+       if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
+               sta = sta_get(bss, mgmt->da);
+       else
+               sta = sta_get(bss, mgmt->sa);
+       if (sta == NULL)
+               return;
+
+       wpa_printf(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 ?
+                       WLANTEST_STA_COUNTER_VALID_DISASSOC_RX_ACK :
+                       WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX_ACK;
+               sta->counters[c]++;
+       }
+}
+
+
+void rx_mgmt_ack(struct wlantest *wt, const struct ieee80211_hdr *hdr)
+{
+       u16 fc, stype;
+       fc = le_to_host16(hdr->frame_control);
+       stype = WLAN_FC_GET_STYPE(fc);
+
+       wpa_printf(MSG_MSGDUMP, "MGMT ACK: stype=%u a1=" MACSTR " a2=" MACSTR
+                  " a3=" MACSTR,
+                  stype, MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
+                  MAC2STR(hdr->addr3));
+
+       switch (stype) {
+       case WLAN_FC_STYPE_DEAUTH:
+               rx_mgmt_deauth_ack(wt, hdr);
+               break;
+       case WLAN_FC_STYPE_DISASSOC:
+               rx_mgmt_disassoc_ack(wt, hdr);
+               break;
+       }
+}
diff --git a/wlantest/rx_tdls.c b/wlantest/rx_tdls.c
new file mode 100644 (file)
index 0000000..f2e2ac7
--- /dev/null
@@ -0,0 +1,574 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "crypto/sha256.h"
+#include "crypto/crypto.h"
+#include "crypto/aes_wrap.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "wlantest.h"
+
+
+static struct wlantest_tdls * get_tdls(struct wlantest *wt, const u8 *linkid,
+                                      int create_new, const u8 *bssid)
+{
+       struct wlantest_bss *bss;
+       struct wlantest_sta *init, *resp;
+       struct wlantest_tdls *tdls;
+
+       bss = bss_find(wt, 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));
+       }
+       if (bss == NULL)
+               return NULL;
+
+       init = sta_find(bss, linkid + ETH_ALEN);
+       if (init == NULL)
+               return NULL;
+
+       resp = sta_find(bss, linkid + 2 * ETH_ALEN);
+       if (resp == NULL)
+               return NULL;
+
+       dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list) {
+               if (tdls->init == init && tdls->resp == resp)
+                       return tdls;
+       }
+
+       if (!create_new)
+               return NULL;
+
+       tdls = os_zalloc(sizeof(*tdls));
+       if (tdls == NULL)
+               return NULL;
+       tdls->init = init;
+       tdls->resp = resp;
+       dl_list_add(&bss->tdls, &tdls->list);
+       return tdls;
+}
+
+
+static int tdls_derive_tpk(struct wlantest_tdls *tdls, const u8 *bssid,
+                          const u8 *ftie, u8 ftie_len)
+{
+       const struct rsn_ftie *f;
+       u8 key_input[SHA256_MAC_LEN];
+       const u8 *nonce[2];
+       size_t len[2];
+       u8 data[3 * ETH_ALEN];
+
+       if (ftie == NULL || ftie_len < sizeof(struct rsn_ftie))
+               return 0;
+
+       f = (const struct rsn_ftie *) ftie;
+       wpa_hexdump(MSG_DEBUG, "TDLS ANonce", f->anonce, WPA_NONCE_LEN);
+       wpa_hexdump(MSG_DEBUG, "TDLS SNonce", f->snonce, WPA_NONCE_LEN);
+
+       /*
+        * IEEE Std 802.11z-2010 8.5.9.1:
+        * TPK-Key-Input = SHA-256(min(SNonce, ANonce) || max(SNonce, ANonce))
+        */
+       len[0] = WPA_NONCE_LEN;
+       len[1] = WPA_NONCE_LEN;
+       if (os_memcmp(f->anonce, f->snonce, WPA_NONCE_LEN) < 0) {
+               nonce[0] = f->anonce;
+               nonce[1] = f->snonce;
+       } else {
+               nonce[0] = f->snonce;
+               nonce[1] = f->anonce;
+       }
+       sha256_vector(2, nonce, len, key_input);
+       wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-Key-Input",
+                       key_input, SHA256_MAC_LEN);
+
+       /*
+        * TPK-Key-Data = KDF-N_KEY(TPK-Key-Input, "TDLS PMK",
+        *      min(MAC_I, MAC_R) || max(MAC_I, MAC_R) || BSSID || N_KEY)
+        * TODO: is N_KEY really included in KDF Context and if so, in which
+        * presentation format (little endian 16-bit?) is it used? It gets
+        * added by the KDF anyway..
+        */
+
+       if (os_memcmp(tdls->init->addr, tdls->resp->addr, ETH_ALEN) < 0) {
+               os_memcpy(data, tdls->init->addr, ETH_ALEN);
+               os_memcpy(data + ETH_ALEN, tdls->resp->addr, ETH_ALEN);
+       } else {
+               os_memcpy(data, tdls->resp->addr, ETH_ALEN);
+               os_memcpy(data + ETH_ALEN, tdls->init->addr, ETH_ALEN);
+       }
+       os_memcpy(data + 2 * ETH_ALEN, bssid, ETH_ALEN);
+       wpa_hexdump(MSG_DEBUG, "TDLS: KDF Context", data, sizeof(data));
+
+       sha256_prf(key_input, SHA256_MAC_LEN, "TDLS PMK", data, sizeof(data),
+                  (u8 *) &tdls->tpk, sizeof(tdls->tpk));
+       wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-KCK",
+                       tdls->tpk.kck, sizeof(tdls->tpk.kck));
+       wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-TK",
+                       tdls->tpk.tk, sizeof(tdls->tpk.tk));
+
+       return 1;
+}
+
+
+static int tdls_verify_mic(struct wlantest_tdls *tdls, u8 trans_seq,
+                          struct ieee802_11_elems *elems)
+{
+       u8 *buf, *pos;
+       int len;
+       u8 mic[16];
+       int ret;
+       const struct rsn_ftie *rx_ftie;
+       struct rsn_ftie *tmp_ftie;
+
+       if (elems->link_id == NULL || elems->rsn_ie == NULL ||
+           elems->timeout_int == NULL || elems->ftie == NULL)
+               return -1;
+
+       len = 2 * ETH_ALEN + 1 + 2 + 18 + 2 + elems->rsn_ie_len +
+               2 + elems->timeout_int_len + 2 + elems->ftie_len;
+
+       buf = os_zalloc(len);
+       if (buf == NULL)
+               return -1;
+
+       pos = buf;
+       /* 1) TDLS initiator STA MAC address */
+       os_memcpy(pos, elems->link_id + ETH_ALEN, ETH_ALEN);
+       pos += ETH_ALEN;
+       /* 2) TDLS responder STA MAC address */
+       os_memcpy(pos, elems->link_id + 2 * ETH_ALEN, ETH_ALEN);
+       pos += ETH_ALEN;
+       /* 3) Transaction Sequence number */
+       *pos++ = trans_seq;
+       /* 4) Link Identifier IE */
+       os_memcpy(pos, elems->link_id - 2, 2 + 18);
+       pos += 2 + 18;
+       /* 5) RSN IE */
+       os_memcpy(pos, elems->rsn_ie - 2, 2 + elems->rsn_ie_len);
+       pos += 2 + elems->rsn_ie_len;
+       /* 6) Timeout Interval IE */
+       os_memcpy(pos, elems->timeout_int - 2, 2 + elems->timeout_int_len);
+       pos += 2 + elems->timeout_int_len;
+       /* 7) FTIE, with the MIC field of the FTIE set to 0 */
+       os_memcpy(pos, elems->ftie - 2, 2 + elems->ftie_len);
+       pos += 2;
+       tmp_ftie = (struct rsn_ftie *) pos;
+       os_memset(tmp_ftie->mic, 0, 16);
+       pos += elems->ftie_len;
+
+       wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf);
+       wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", tdls->tpk.kck, 16);
+       ret = omac1_aes_128(tdls->tpk.kck, buf, pos - buf, mic);
+       os_free(buf);
+       if (ret)
+               return -1;
+       wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16);
+       rx_ftie = (const struct rsn_ftie *) elems->ftie;
+
+       if (os_memcmp(mic, rx_ftie->mic, 16) == 0) {
+               wpa_printf(MSG_DEBUG, "TDLS: Valid MIC");
+               return 0;
+       }
+       wpa_printf(MSG_DEBUG, "TDLS: Invalid MIC");
+       return -1;
+}
+
+
+static void rx_data_tdls_setup_request(struct wlantest *wt, const u8 *bssid,
+                                      const u8 *sta_addr, const u8 *dst,
+                                      const u8 *src,
+                                      const u8 *data, size_t len)
+{
+       struct ieee802_11_elems elems;
+       struct wlantest_tdls *tdls;
+
+       if (len < 3) {
+               wpa_printf(MSG_INFO, "Too short TDLS Setup Request " MACSTR
+                          " -> " MACSTR, MAC2STR(src), MAC2STR(dst));
+               return;
+       }
+       wpa_printf(MSG_DEBUG, "TDLS Setup Request " MACSTR " -> "
+                  MACSTR, MAC2STR(src), MAC2STR(dst));
+
+       if (ieee802_11_parse_elems(data + 3, len - 3, &elems, 1) ==
+           ParseFailed || elems.link_id == NULL)
+               return;
+       wpa_printf(MSG_DEBUG, "TDLS Link Identifier: BSSID " MACSTR
+                  " initiator STA " MACSTR " responder STA " MACSTR,
+                  MAC2STR(elems.link_id), MAC2STR(elems.link_id + ETH_ALEN),
+                  MAC2STR(elems.link_id + 2 * ETH_ALEN));
+       tdls = get_tdls(wt, elems.link_id, 1, bssid);
+       if (tdls) {
+               tdls->counters[WLANTEST_TDLS_COUNTER_SETUP_REQ]++;
+               tdls->dialog_token = data[0];
+       }
+}
+
+
+static void rx_data_tdls_setup_response_failure(struct wlantest *wt,
+                                               const u8 *bssid,
+                                               const u8 *sta_addr,
+                                               u8 dialog_token, u16 status)
+{
+       struct wlantest_bss *bss;
+       struct wlantest_tdls *tdls;
+       struct wlantest_sta *sta;
+
+       if (status == WLAN_STATUS_SUCCESS) {
+               wpa_printf(MSG_INFO, "TDLS: Invalid TDLS Setup Response from "
+                          MACSTR, MAC2STR(sta_addr));
+               return;
+       }
+
+       bss = bss_find(wt, bssid);
+       if (!bss)
+               return;
+       sta = sta_find(bss, sta_addr);
+       if (!sta)
+               return;
+
+       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)");
+                               break;
+                       }
+                       wpa_printf(MSG_DEBUG, "TDLS: Found matching TDLS "
+                                  "setup session based on dialog token");
+                       tdls->counters[
+                               WLANTEST_TDLS_COUNTER_SETUP_RESP_FAIL]++;
+                       break;
+               }
+       }
+}
+
+
+static void rx_data_tdls_setup_response(struct wlantest *wt, const u8 *bssid,
+                                       const u8 *sta_addr, const u8 *dst,
+                                       const u8 *src,
+                                       const u8 *data, size_t len)
+{
+       u16 status;
+       struct ieee802_11_elems elems;
+       struct wlantest_tdls *tdls;
+
+       if (len < 3) {
+               wpa_printf(MSG_INFO, "Too short TDLS Setup Response " MACSTR
+                          " -> " MACSTR, MAC2STR(src), MAC2STR(dst));
+               return;
+       }
+       status = WPA_GET_LE16(data);
+       wpa_printf(MSG_DEBUG, "TDLS Setup Response " MACSTR " -> "
+                  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));
+               return;
+       }
+
+       if (len < 5 ||
+           ieee802_11_parse_elems(data + 5, len - 5, &elems, 1) ==
+           ParseFailed || elems.link_id == NULL) {
+               /* Need to match TDLS link based on Dialog Token */
+               rx_data_tdls_setup_response_failure(wt, bssid, sta_addr,
+                                                   data[2], status);
+               return;
+       }
+       wpa_printf(MSG_DEBUG, "TDLS Link Identifier: BSSID " MACSTR
+                  " initiator STA " MACSTR " responder STA " MACSTR,
+                  MAC2STR(elems.link_id), MAC2STR(elems.link_id + ETH_ALEN),
+                  MAC2STR(elems.link_id + 2 * ETH_ALEN));
+
+       tdls = get_tdls(wt, elems.link_id, 1, bssid);
+       if (!tdls)
+               return;
+       if (status)
+               tdls->counters[WLANTEST_TDLS_COUNTER_SETUP_RESP_FAIL]++;
+       else
+               tdls->counters[WLANTEST_TDLS_COUNTER_SETUP_RESP_OK]++;
+
+       if (status != WLAN_STATUS_SUCCESS)
+               return;
+
+       if (tdls_derive_tpk(tdls, bssid, elems.ftie, elems.ftie_len) < 1)
+               return;
+       if (tdls_verify_mic(tdls, 2, &elems) == 0) {
+               tdls->dialog_token = data[2];
+               wpa_printf(MSG_DEBUG, "TDLS: Dialog Token for the link: %u",
+                          tdls->dialog_token);
+       }
+}
+
+
+static void rx_data_tdls_setup_confirm_failure(struct wlantest *wt,
+                                              const u8 *bssid,
+                                              const u8 *src,
+                                              u8 dialog_token, u16 status)
+{
+       struct wlantest_bss *bss;
+       struct wlantest_tdls *tdls;
+       struct wlantest_sta *sta;
+
+       if (status == WLAN_STATUS_SUCCESS) {
+               wpa_printf(MSG_INFO, "TDLS: Invalid TDLS Setup Confirm from "
+                          MACSTR, MAC2STR(src));
+               return;
+       }
+
+       bss = bss_find(wt, bssid);
+       if (!bss)
+               return;
+       sta = sta_find(bss, src);
+       if (!sta)
+               return;
+
+       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)");
+                               break;
+                       }
+                       wpa_printf(MSG_DEBUG, "TDLS: Found matching TDLS "
+                                  "setup session based on dialog token");
+                       tdls->counters[
+                               WLANTEST_TDLS_COUNTER_SETUP_CONF_FAIL]++;
+                       break;
+               }
+       }
+}
+
+
+static void rx_data_tdls_setup_confirm(struct wlantest *wt, const u8 *bssid,
+                                      const u8 *sta_addr, const u8 *dst,
+                                      const u8 *src,
+                                      const u8 *data, size_t len)
+{
+       u16 status;
+       struct ieee802_11_elems elems;
+       struct wlantest_tdls *tdls;
+       u8 link_id[3 * ETH_ALEN];
+
+       if (len < 3) {
+               wpa_printf(MSG_INFO, "Too short TDLS Setup Confirm " MACSTR
+                          " -> " MACSTR, MAC2STR(src), MAC2STR(dst));
+               return;
+       }
+       status = WPA_GET_LE16(data);
+       wpa_printf(MSG_DEBUG, "TDLS Setup Confirm " MACSTR " -> "
+                  MACSTR " (status %d)",
+                  MAC2STR(src), MAC2STR(dst), status);
+
+       if (ieee802_11_parse_elems(data + 3, len - 3, &elems, 1) ==
+           ParseFailed || elems.link_id == NULL) {
+               /* Need to match TDLS link based on Dialog Token */
+               rx_data_tdls_setup_confirm_failure(wt, bssid, src,
+                                                  data[2], status);
+               return;
+       }
+       wpa_printf(MSG_DEBUG, "TDLS Link Identifier: BSSID " MACSTR
+                  " initiator STA " MACSTR " responder STA " MACSTR,
+                  MAC2STR(elems.link_id), MAC2STR(elems.link_id + ETH_ALEN),
+                  MAC2STR(elems.link_id + 2 * ETH_ALEN));
+
+       tdls = get_tdls(wt, elems.link_id, 1, bssid);
+       if (tdls == NULL)
+               return;
+       if (status)
+               tdls->counters[WLANTEST_TDLS_COUNTER_SETUP_CONF_FAIL]++;
+       else
+               tdls->counters[WLANTEST_TDLS_COUNTER_SETUP_CONF_OK]++;
+
+       if (status != WLAN_STATUS_SUCCESS)
+               return;
+
+       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) {
+               tdls->dialog_token = data[2];
+               wpa_printf(MSG_DEBUG, "TDLS: Dialog Token for the link: %u",
+                          tdls->dialog_token);
+       }
+
+remove_reverse:
+       /*
+        * The TDLS link itself is bidirectional, but there is explicit
+        * initiator/responder roles. Remove the other direction of the link
+        * (if it exists) to make sure that the link counters are stored for
+        * the current TDLS entery.
+        */
+       os_memcpy(link_id, elems.link_id, ETH_ALEN);
+       os_memcpy(link_id + ETH_ALEN, elems.link_id + 2 * ETH_ALEN, ETH_ALEN);
+       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");
+               tdls_deinit(tdls);
+       }
+}
+
+
+static int tdls_verify_mic_teardown(struct wlantest_tdls *tdls, u8 trans_seq,
+                                   const u8 *reason_code,
+                                   struct ieee802_11_elems *elems)
+{
+       u8 *buf, *pos;
+       int len;
+       u8 mic[16];
+       int ret;
+       const struct rsn_ftie *rx_ftie;
+       struct rsn_ftie *tmp_ftie;
+
+       if (elems->link_id == NULL || elems->ftie == NULL)
+               return -1;
+
+       len = 2 + 18 + 2 + 1 + 1 + 2 + elems->ftie_len;
+
+       buf = os_zalloc(len);
+       if (buf == NULL)
+               return -1;
+
+       pos = buf;
+       /* 1) Link Identifier IE */
+       os_memcpy(pos, elems->link_id - 2, 2 + 18);
+       pos += 2 + 18;
+       /* 2) Reason Code */
+       os_memcpy(pos, reason_code, 2);
+       pos += 2;
+       /* 3) Dialog token */
+       *pos++ = tdls->dialog_token;
+       /* 4) Transaction Sequence number */
+       *pos++ = trans_seq;
+       /* 5) FTIE, with the MIC field of the FTIE set to 0 */
+       os_memcpy(pos, elems->ftie - 2, 2 + elems->ftie_len);
+       pos += 2;
+       tmp_ftie = (struct rsn_ftie *) pos;
+       os_memset(tmp_ftie->mic, 0, 16);
+       pos += elems->ftie_len;
+
+       wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf);
+       wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", tdls->tpk.kck, 16);
+       ret = omac1_aes_128(tdls->tpk.kck, buf, pos - buf, mic);
+       os_free(buf);
+       if (ret)
+               return -1;
+       wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16);
+       rx_ftie = (const struct rsn_ftie *) elems->ftie;
+
+       if (os_memcmp(mic, rx_ftie->mic, 16) == 0) {
+               wpa_printf(MSG_DEBUG, "TDLS: Valid MIC");
+               return 0;
+       }
+       wpa_printf(MSG_DEBUG, "TDLS: Invalid MIC");
+       return -1;
+}
+
+
+static void rx_data_tdls_teardown(struct wlantest *wt, const u8 *bssid,
+                                 const u8 *sta_addr, const u8 *dst,
+                                 const u8 *src,
+                                 const u8 *data, size_t len)
+{
+       u16 reason;
+       struct ieee802_11_elems elems;
+       struct wlantest_tdls *tdls;
+
+       if (len < 2)
+               return;
+       reason = WPA_GET_LE16(data);
+       wpa_printf(MSG_DEBUG, "TDLS Teardown " MACSTR " -> "
+                  MACSTR " (reason %d)",
+                  MAC2STR(src), MAC2STR(dst), reason);
+
+       if (ieee802_11_parse_elems(data + 2, len - 2, &elems, 1) ==
+           ParseFailed || elems.link_id == NULL)
+               return;
+       wpa_printf(MSG_DEBUG, "TDLS Link Identifier: BSSID " MACSTR
+                  " initiator STA " MACSTR " responder STA " MACSTR,
+                  MAC2STR(elems.link_id), MAC2STR(elems.link_id + ETH_ALEN),
+                  MAC2STR(elems.link_id + 2 * ETH_ALEN));
+
+       tdls = get_tdls(wt, elems.link_id, 1, bssid);
+       if (tdls) {
+               tdls->link_up = 0;
+               tdls->counters[WLANTEST_TDLS_COUNTER_TEARDOWN]++;
+               tdls_verify_mic_teardown(tdls, 4, data, &elems);
+       }
+}
+
+
+static void rx_data_tdls(struct wlantest *wt, const u8 *bssid,
+                        const u8 *sta_addr, const u8 *dst, const u8 *src,
+                        const u8 *data, size_t len)
+{
+       /* data contains the payload of a TDLS Action frame */
+       if (len < 2 || data[0] != WLAN_ACTION_TDLS) {
+               wpa_hexdump(MSG_DEBUG, "Unrecognized encapsulated TDLS frame",
+                           data, len);
+               return;
+       }
+
+       switch (data[1]) {
+       case WLAN_TDLS_SETUP_REQUEST:
+               rx_data_tdls_setup_request(wt, bssid, sta_addr, dst, src,
+                                          data + 2, len - 2);
+               break;
+       case WLAN_TDLS_SETUP_RESPONSE:
+               rx_data_tdls_setup_response(wt, bssid, sta_addr, dst, src,
+                                           data + 2, len - 2);
+               break;
+       case WLAN_TDLS_SETUP_CONFIRM:
+               rx_data_tdls_setup_confirm(wt, bssid, sta_addr, dst, src,
+                                          data + 2, len - 2);
+               break;
+       case WLAN_TDLS_TEARDOWN:
+               rx_data_tdls_teardown(wt, bssid, sta_addr, dst, src, data + 2,
+                                     len - 2);
+               break;
+       case WLAN_TDLS_DISCOVERY_REQUEST:
+               wpa_printf(MSG_DEBUG, "TDLS Discovery Request " MACSTR " -> "
+                          MACSTR, MAC2STR(src), MAC2STR(dst));
+               break;
+       }
+}
+
+
+void rx_data_80211_encap(struct wlantest *wt, const u8 *bssid,
+                        const u8 *sta_addr, const u8 *dst, const u8 *src,
+                        const u8 *data, size_t len)
+{
+       wpa_hexdump(MSG_EXCESSIVE, "802.11 data encap frame", data, len);
+       if (len < 1)
+               return;
+       if (data[0] == 0x02)
+               rx_data_tdls(wt, bssid, sta_addr, dst, src, data + 1, len - 1);
+}
diff --git a/wlantest/sta.c b/wlantest/sta.c
new file mode 100644 (file)
index 0000000..4b5d16d
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/defs.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "wlantest.h"
+
+
+struct wlantest_sta * sta_find(struct wlantest_bss *bss, const u8 *addr)
+{
+       struct wlantest_sta *sta;
+
+       dl_list_for_each(sta, &bss->sta, struct wlantest_sta, list) {
+               if (os_memcmp(sta->addr, addr, ETH_ALEN) == 0)
+                       return sta;
+       }
+
+       return NULL;
+}
+
+
+struct wlantest_sta * sta_get(struct wlantest_bss *bss, const u8 *addr)
+{
+       struct wlantest_sta *sta;
+
+       if (addr[0] & 0x01)
+               return NULL; /* Skip group addressed frames */
+
+       sta = sta_find(bss, addr);
+       if (sta)
+               return sta;
+
+       sta = os_zalloc(sizeof(*sta));
+       if (sta == NULL)
+               return NULL;
+       os_memset(sta->seq_ctrl_to_sta, 0xff, sizeof(sta->seq_ctrl_to_sta));
+       os_memset(sta->seq_ctrl_to_ap, 0xff, sizeof(sta->seq_ctrl_to_ap));
+       sta->bss = bss;
+       os_memcpy(sta->addr, addr, ETH_ALEN);
+       dl_list_add(&bss->sta, &sta->list);
+       wpa_printf(MSG_DEBUG, "Discovered new STA " MACSTR " in BSS " MACSTR,
+                  MAC2STR(sta->addr), MAC2STR(bss->bssid));
+       return sta;
+}
+
+
+void sta_deinit(struct wlantest_sta *sta)
+{
+       dl_list_del(&sta->list);
+       os_free(sta->assocreq_ies);
+       os_free(sta);
+}
+
+
+void sta_update_assoc(struct wlantest_sta *sta, struct ieee802_11_elems *elems)
+{
+       struct wpa_ie_data data;
+       struct wlantest_bss *bss = sta->bss;
+
+       if (elems->wpa_ie && !bss->wpaie[0]) {
+               wpa_printf(MSG_INFO, "WPA IE included in Association Request "
+                          "frame from " MACSTR " even though BSS does not "
+                          "use WPA - ignore IE",
+                          MAC2STR(sta->addr));
+               elems->wpa_ie = NULL;
+       }
+
+       if (elems->rsn_ie && !bss->rsnie[0]) {
+               wpa_printf(MSG_INFO, "RSN IE included in Association Request "
+                          "frame from " MACSTR " even though BSS does not "
+                          "use RSN - ignore IE",
+                          MAC2STR(sta->addr));
+               elems->rsn_ie = NULL;
+       }
+
+       if (elems->wpa_ie && elems->rsn_ie) {
+               wpa_printf(MSG_INFO, "Both WPA IE and RSN IE included in "
+                          "Association Request frame from " MACSTR,
+                          MAC2STR(sta->addr));
+       }
+
+       if (elems->rsn_ie) {
+               wpa_hexdump(MSG_DEBUG, "RSN IE", elems->rsn_ie - 2,
+                           elems->rsn_ie_len + 2);
+               os_memcpy(sta->rsnie, elems->rsn_ie - 2,
+                         elems->rsn_ie_len + 2);
+               if (wpa_parse_wpa_ie_rsn(sta->rsnie, 2 + sta->rsnie[1], &data)
+                   < 0) {
+                       wpa_printf(MSG_INFO, "Failed to parse RSN IE from "
+                                  MACSTR, MAC2STR(sta->addr));
+               }
+       } else if (elems->wpa_ie) {
+               wpa_hexdump(MSG_DEBUG, "WPA IE", elems->wpa_ie - 2,
+                           elems->wpa_ie_len + 2);
+               os_memcpy(sta->rsnie, elems->wpa_ie - 2,
+                         elems->wpa_ie_len + 2);
+               if (wpa_parse_wpa_ie_wpa(sta->rsnie, 2 + sta->rsnie[1], &data)
+                   < 0) {
+                       wpa_printf(MSG_INFO, "Failed to parse WPA IE from "
+                                  MACSTR, MAC2STR(sta->addr));
+               }
+       } else {
+               sta->rsnie[0] = 0;
+               sta->proto = 0;
+               sta->pairwise_cipher = 0;
+               sta->key_mgmt = 0;
+               sta->rsn_capab = 0;
+               if (sta->assocreq_capab_info & WLAN_CAPABILITY_PRIVACY)
+                       sta->pairwise_cipher = WPA_CIPHER_WEP40;
+               goto skip_rsn_wpa;
+       }
+
+       sta->proto = data.proto;
+       sta->pairwise_cipher = data.pairwise_cipher;
+       sta->key_mgmt = data.key_mgmt;
+       sta->rsn_capab = data.capabilities;
+       if (bss->proto && (sta->proto & bss->proto) == 0) {
+               wpa_printf(MSG_INFO, "Mismatch in WPA/WPA2 proto: STA "
+                          MACSTR " 0x%x  BSS " MACSTR " 0x%x",
+                          MAC2STR(sta->addr), sta->proto,
+                          MAC2STR(bss->bssid), bss->proto);
+       }
+       if (bss->pairwise_cipher &&
+           (sta->pairwise_cipher & bss->pairwise_cipher) == 0) {
+               wpa_printf(MSG_INFO, "Mismatch in pairwise cipher: STA "
+                          MACSTR " 0x%x  BSS " MACSTR " 0x%x",
+                          MAC2STR(sta->addr), sta->pairwise_cipher,
+                          MAC2STR(bss->bssid), bss->pairwise_cipher);
+       }
+       if (sta->proto && data.group_cipher != bss->group_cipher) {
+               wpa_printf(MSG_INFO, "Mismatch in group cipher: STA "
+                          MACSTR " 0x%x != BSS " MACSTR " 0x%x",
+                          MAC2STR(sta->addr), data.group_cipher,
+                          MAC2STR(bss->bssid), bss->group_cipher);
+       }
+       if ((bss->rsn_capab & WPA_CAPABILITY_MFPR) &&
+           !(sta->rsn_capab & WPA_CAPABILITY_MFPC)) {
+               wpa_printf(MSG_INFO, "STA " MACSTR " tries to associate "
+                          "without MFP to BSS " MACSTR " that advertises "
+                          "MFPR", MAC2STR(sta->addr), MAC2STR(bss->bssid));
+       }
+
+skip_rsn_wpa:
+       wpa_printf(MSG_INFO, "STA " MACSTR
+                  " proto=%s%s%s"
+                  "pairwise=%s%s%s%s"
+                  "key_mgmt=%s%s%s%s%s%s%s%s"
+                  "rsn_capab=%s%s%s%s%s",
+                  MAC2STR(sta->addr),
+                  sta->proto == 0 ? "OPEN " : "",
+                  sta->proto & WPA_PROTO_WPA ? "WPA " : "",
+                  sta->proto & WPA_PROTO_RSN ? "WPA2 " : "",
+                  sta->pairwise_cipher == 0 ? "N/A " : "",
+                  sta->pairwise_cipher & WPA_CIPHER_NONE ? "NONE " : "",
+                  sta->pairwise_cipher & WPA_CIPHER_TKIP ? "TKIP " : "",
+                  sta->pairwise_cipher & WPA_CIPHER_CCMP ? "CCMP " : "",
+                  sta->key_mgmt == 0 ? "N/A " : "",
+                  sta->key_mgmt & WPA_KEY_MGMT_IEEE8021X ? "EAP " : "",
+                  sta->key_mgmt & WPA_KEY_MGMT_PSK ? "PSK " : "",
+                  sta->key_mgmt & WPA_KEY_MGMT_WPA_NONE ? "WPA-NONE " : "",
+                  sta->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X ? "FT-EAP " : "",
+                  sta->key_mgmt & WPA_KEY_MGMT_FT_PSK ? "FT-PSK " : "",
+                  sta->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256 ?
+                  "EAP-SHA256 " : "",
+                  sta->key_mgmt & WPA_KEY_MGMT_PSK_SHA256 ?
+                  "PSK-SHA256 " : "",
+                  sta->rsn_capab & WPA_CAPABILITY_PREAUTH ? "PREAUTH " : "",
+                  sta->rsn_capab & WPA_CAPABILITY_NO_PAIRWISE ?
+                  "NO_PAIRWISE " : "",
+                  sta->rsn_capab & WPA_CAPABILITY_MFPR ? "MFPR " : "",
+                  sta->rsn_capab & WPA_CAPABILITY_MFPC ? "MFPC " : "",
+                  sta->rsn_capab & WPA_CAPABILITY_PEERKEY_ENABLED ?
+                  "PEERKEY " : "");
+}
diff --git a/wlantest/tkip.c b/wlantest/tkip.c
new file mode 100644 (file)
index 0000000..3533914
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "wlantest.h"
+
+
+void wep_crypt(u8 *key, u8 *buf, size_t plen);
+
+
+static inline u16 RotR1(u16 val)
+{
+       return (val >> 1) | (val << 15);
+}
+
+
+static inline u8 Lo8(u16 val)
+{
+       return val & 0xff;
+}
+
+
+static inline u8 Hi8(u16 val)
+{
+       return val >> 8;
+}
+
+
+static inline u16 Lo16(u32 val)
+{
+       return val & 0xffff;
+}
+
+
+static inline u16 Hi16(u32 val)
+{
+       return val >> 16;
+}
+
+
+static inline u16 Mk16(u8 hi, u8 lo)
+{
+       return lo | (((u16) hi) << 8);
+}
+
+
+static inline u16 Mk16_le(u16 *v)
+{
+       return le_to_host16(*v);
+}
+
+
+static const u16 Sbox[256] =
+{
+       0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
+       0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
+       0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
+       0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
+       0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
+       0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
+       0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
+       0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
+       0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
+       0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
+       0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
+       0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
+       0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
+       0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
+       0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
+       0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
+       0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
+       0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
+       0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
+       0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
+       0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
+       0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
+       0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
+       0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
+       0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
+       0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
+       0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
+       0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
+       0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
+       0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
+       0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
+       0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
+};
+
+
+static inline u16 _S_(u16 v)
+{
+       u16 t = Sbox[Hi8(v)];
+       return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
+}
+
+
+#define PHASE1_LOOP_COUNT 8
+
+static void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32)
+{
+       int i, j;
+
+       /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
+       TTAK[0] = Lo16(IV32);
+       TTAK[1] = Hi16(IV32);
+       TTAK[2] = Mk16(TA[1], TA[0]);
+       TTAK[3] = Mk16(TA[3], TA[2]);
+       TTAK[4] = Mk16(TA[5], TA[4]);
+
+       for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
+               j = 2 * (i & 1);
+               TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
+               TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
+               TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
+               TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
+               TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
+       }
+}
+
+
+static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK,
+                              u16 IV16)
+{
+       u16 PPK[6];
+
+       /* Step 1 - make copy of TTAK and bring in TSC */
+       PPK[0] = TTAK[0];
+       PPK[1] = TTAK[1];
+       PPK[2] = TTAK[2];
+       PPK[3] = TTAK[3];
+       PPK[4] = TTAK[4];
+       PPK[5] = TTAK[4] + IV16;
+
+       /* Step 2 - 96-bit bijective mixing using S-box */
+       PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *) &TK[0]));
+       PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *) &TK[2]));
+       PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *) &TK[4]));
+       PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *) &TK[6]));
+       PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *) &TK[8]));
+       PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *) &TK[10]));
+
+       PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *) &TK[12]));
+       PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *) &TK[14]));
+       PPK[2] += RotR1(PPK[1]);
+       PPK[3] += RotR1(PPK[2]);
+       PPK[4] += RotR1(PPK[3]);
+       PPK[5] += RotR1(PPK[4]);
+
+       /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
+        * WEPSeed[0..2] is transmitted as WEP IV */
+       WEPSeed[0] = Hi8(IV16);
+       WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
+       WEPSeed[2] = Lo8(IV16);
+       WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *) &TK[0])) >> 1);
+       WPA_PUT_LE16(&WEPSeed[4], PPK[0]);
+       WPA_PUT_LE16(&WEPSeed[6], PPK[1]);
+       WPA_PUT_LE16(&WEPSeed[8], PPK[2]);
+       WPA_PUT_LE16(&WEPSeed[10], PPK[3]);
+       WPA_PUT_LE16(&WEPSeed[12], PPK[4]);
+       WPA_PUT_LE16(&WEPSeed[14], PPK[5]);
+}
+
+
+static inline u32 rotl(u32 val, int bits)
+{
+       return (val << bits) | (val >> (32 - bits));
+}
+
+
+static inline u32 rotr(u32 val, int bits)
+{
+       return (val >> bits) | (val << (32 - bits));
+}
+
+
+static inline u32 xswap(u32 val)
+{
+       return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8);
+}
+
+
+#define michael_block(l, r)    \
+do {                           \
+       r ^= rotl(l, 17);       \
+       l += r;                 \
+       r ^= xswap(l);          \
+       l += r;                 \
+       r ^= rotl(l, 3);        \
+       l += r;                 \
+       r ^= rotr(l, 2);        \
+       l += r;                 \
+} while (0)
+
+
+static void michael_mic(const u8 *key, const u8 *hdr, const u8 *data,
+                       size_t data_len, u8 *mic)
+{
+       u32 l, r;
+       int i, blocks, last;
+
+       l = WPA_GET_LE32(key);
+       r = WPA_GET_LE32(key + 4);
+
+       /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */
+       l ^= WPA_GET_LE32(hdr);
+       michael_block(l, r);
+       l ^= WPA_GET_LE32(&hdr[4]);
+       michael_block(l, r);
+       l ^= WPA_GET_LE32(&hdr[8]);
+       michael_block(l, r);
+       l ^= WPA_GET_LE32(&hdr[12]);
+       michael_block(l, r);
+
+       /* 32-bit blocks of data */
+       blocks = data_len / 4;
+       last = data_len % 4;
+       for (i = 0; i < blocks; i++) {
+               l ^= WPA_GET_LE32(&data[4 * i]);
+               michael_block(l, r);
+       }
+
+       /* Last block and padding (0x5a, 4..7 x 0) */
+       switch (last) {
+       case 0:
+               l ^= 0x5a;
+               break;
+       case 1:
+               l ^= data[4 * i] | 0x5a00;
+               break;
+       case 2:
+               l ^= data[4 * i] | (data[4 * i + 1] << 8) | 0x5a0000;
+               break;
+       case 3:
+               l ^= data[4 * i] | (data[4 * i + 1] << 8) |
+                       (data[4 * i + 2] << 16) | 0x5a000000;
+               break;
+       }
+       michael_block(l, r);
+       /* l ^= 0; */
+       michael_block(l, r);
+
+       WPA_PUT_LE32(mic, l);
+       WPA_PUT_LE32(mic + 4, r);
+}
+
+
+static void michael_mic_hdr(const struct ieee80211_hdr *hdr11, u8 *hdr)
+{
+       int hdrlen = 24;
+       u16 fc = le_to_host16(hdr11->frame_control);
+
+       switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
+       case WLAN_FC_TODS:
+               os_memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
+               os_memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
+               break;
+       case WLAN_FC_FROMDS:
+               os_memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
+               os_memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */
+               break;
+       case WLAN_FC_FROMDS | WLAN_FC_TODS:
+               os_memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
+               os_memcpy(hdr + ETH_ALEN, hdr11 + 1, ETH_ALEN); /* SA */
+               hdrlen += ETH_ALEN;
+               break;
+       case 0:
+               os_memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
+               os_memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
+               break;
+       }
+
+       if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA &&
+           (WLAN_FC_GET_STYPE(fc) & 0x08)) {
+               const u8 *qos = ((const u8 *) hdr11) + hdrlen;
+               hdr[12] = qos[0] & 0x0f; /* priority */
+       } else
+               hdr[12] = 0; /* priority */
+
+       hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
+}
+
+
+u8 * tkip_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
+                 const u8 *data, size_t data_len, size_t *decrypted_len)
+{
+       u16 iv16;
+       u32 iv32;
+       u16 ttak[5];
+       u8 rc4key[16];
+       u8 *plain;
+       size_t plain_len;
+       u32 icv, rx_icv;
+       const u8 *mic_key;
+       u8 michael_hdr[16];
+       u8 mic[8];
+       u16 fc = le_to_host16(hdr->frame_control);
+
+       if (data_len < 8 + 4)
+               return NULL;
+
+       iv16 = (data[0] << 8) | data[2];
+       iv32 = WPA_GET_LE32(&data[4]);
+       wpa_printf(MSG_EXCESSIVE, "TKIP decrypt: iv32=%08x iv16=%04x",
+                  iv32, iv16);
+
+       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));
+
+       plain_len = data_len - 8;
+       plain = os_malloc(plain_len);
+       if (plain == NULL)
+               return NULL;
+       os_memcpy(plain, data + 8, plain_len);
+       wep_crypt(rc4key, plain, plain_len);
+
+       icv = crc32(plain, plain_len - 4);
+       rx_icv = WPA_GET_LE32(plain + plain_len - 4);
+       if (icv != rx_icv) {
+               wpa_printf(MSG_INFO, "TKIP ICV mismatch in frame from " MACSTR,
+                          MAC2STR(hdr->addr2));
+               wpa_printf(MSG_DEBUG, "TKIP calculated ICV %08x  received ICV "
+                          "%08x", icv, rx_icv);
+               os_free(plain);
+               return NULL;
+       }
+       plain_len -= 4;
+
+       /* TODO: MSDU reassembly */
+
+       if (plain_len < 8) {
+               wpa_printf(MSG_INFO, "TKIP: Not enough room for Michael MIC "
+                          "in a frame from " MACSTR, MAC2STR(hdr->addr2));
+               os_free(plain);
+               return NULL;
+       }
+
+       michael_mic_hdr(hdr, michael_hdr);
+       mic_key = tk + ((fc & WLAN_FC_FROMDS) ? 16 : 24);
+       michael_mic(mic_key, michael_hdr, plain, plain_len - 8, mic);
+       if (os_memcmp(mic, plain + plain_len - 8, 8) != 0) {
+               wpa_printf(MSG_INFO, "TKIP: Michael MIC mismatch in a frame "
+                          "from " MACSTR, MAC2STR(hdr->addr2));
+               wpa_hexdump(MSG_DEBUG, "TKIP: Calculated MIC", mic, 8);
+               wpa_hexdump(MSG_DEBUG, "TKIP: Received MIC",
+                           plain + plain_len - 8, 8);
+               os_free(plain);
+               return NULL;
+       }
+
+       *decrypted_len = plain_len - 8;
+       return plain;
+}
+
+
+void tkip_get_pn(u8 *pn, const u8 *data)
+{
+       pn[0] = data[7]; /* PN5 */
+       pn[1] = data[6]; /* PN4 */
+       pn[2] = data[5]; /* PN3 */
+       pn[3] = data[4]; /* PN2 */
+       pn[4] = data[0]; /* PN1 */
+       pn[5] = data[2]; /* PN0 */
+}
+
+
+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;
+}
diff --git a/wlantest/wep.c b/wlantest/wep.c
new file mode 100644 (file)
index 0000000..13ff218
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "wlantest.h"
+
+
+void wep_crypt(u8 *key, u8 *buf, size_t plen)
+{
+       u32 i, j, k;
+       u8 S[256];
+#define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
+       u8 *pos;
+
+       /* Setup RC4 state */
+       for (i = 0; i < 256; i++)
+               S[i] = i;
+       j = 0;
+       for (i = 0; i < 256; i++) {
+               j = (j + S[i] + key[i & 0x0f]) & 0xff;
+               S_SWAP(i, j);
+       }
+
+       /* Apply RC4 to data */
+       pos = buf;
+       i = j = 0;
+       for (k = 0; k < plen; k++) {
+               i = (i + 1) & 0xff;
+               j = (j + S[i]) & 0xff;
+               S_SWAP(i, j);
+               *pos ^= S[(S[i] + S[j]) & 0xff];
+               pos++;
+       }
+}
+
+
+static int try_wep(const u8 *key, size_t key_len, const u8 *data,
+                  size_t data_len, u8 *plain)
+{
+       u32 icv, rx_icv;
+       u8 k[16];
+       int i, j;
+
+       for (i = 0, j = 0; i < sizeof(k); i++) {
+               k[i] = key[j];
+               j++;
+               if (j >= key_len)
+                       j = 0;
+       }
+
+       os_memcpy(plain, data, data_len);
+       wep_crypt(k, plain, data_len);
+       icv = crc32(plain, data_len - 4);
+       rx_icv = WPA_GET_LE32(plain + data_len - 4);
+       if (icv != rx_icv)
+               return -1;
+
+       return 0;
+}
+
+
+u8 * wep_decrypt(struct wlantest *wt, const struct ieee80211_hdr *hdr,
+                const u8 *data, size_t data_len, size_t *decrypted_len)
+{
+       u8 *plain;
+       struct wlantest_wep *w;
+       int found = 0;
+       u8 key[16];
+
+       if (dl_list_empty(&wt->wep))
+               return NULL;
+
+       if (data_len < 4 + 4)
+               return NULL;
+       plain = os_malloc(data_len - 4);
+       if (plain == NULL)
+               return NULL;
+
+       dl_list_for_each(w, &wt->wep, struct wlantest_wep, list) {
+               os_memcpy(key, data, 3);
+               os_memcpy(key + 3, w->key, w->key_len);
+               if (try_wep(key, 3 + w->key_len, data + 4, data_len - 4, plain)
+                   == 0) {
+                       found = 1;
+                       break;
+               }
+       }
+       if (!found) {
+               os_free(plain);
+               return NULL;
+       }
+
+       *decrypted_len = data_len - 4 - 4;
+       return plain;
+}
diff --git a/wlantest/wired.c b/wlantest/wired.c
new file mode 100644 (file)
index 0000000..bf9f163
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+#include <net/ethernet.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+
+#include "utils/common.h"
+#include "radius/radius.h"
+#include "wlantest.h"
+
+
+static struct wlantest_radius * radius_get(struct wlantest *wt, u32 srv,
+                                          u32 cli)
+{
+       struct wlantest_radius *r;
+
+       dl_list_for_each(r, &wt->radius, struct wlantest_radius, list) {
+               if (r->srv == srv && r->cli == cli)
+                       return r;
+       }
+
+       r = os_zalloc(sizeof(*r));
+       if (r == NULL)
+               return NULL;
+
+       r->srv = srv;
+       r->cli = cli;
+       dl_list_add(&wt->radius, &r->list);
+
+       return r;
+}
+
+
+static const char * radius_code_string(u8 code)
+{
+       switch (code) {
+       case RADIUS_CODE_ACCESS_REQUEST:
+               return "Access-Request";
+       case RADIUS_CODE_ACCESS_ACCEPT:
+               return "Access-Accept";
+       case RADIUS_CODE_ACCESS_REJECT:
+               return "Access-Reject";
+       case RADIUS_CODE_ACCOUNTING_REQUEST:
+               return "Accounting-Request";
+       case RADIUS_CODE_ACCOUNTING_RESPONSE:
+               return "Accounting-Response";
+       case RADIUS_CODE_ACCESS_CHALLENGE:
+               return "Access-Challenge";
+       case RADIUS_CODE_STATUS_SERVER:
+               return "Status-Server";
+       case RADIUS_CODE_STATUS_CLIENT:
+               return "Status-Client";
+       case RADIUS_CODE_RESERVED:
+               return "Reserved";
+       default:
+               return "?Unknown?";
+       }
+}
+
+
+static void process_radius_access_request(struct wlantest *wt, u32 dst,
+                                         u32 src, const u8 *data, size_t len)
+{
+       struct radius_msg *msg;
+       struct wlantest_radius *r;
+
+       msg = radius_msg_parse(data, len);
+       if (msg == NULL) {
+               wpa_printf(MSG_DEBUG, "Failed to parse RADIUS Access-Request");
+               return;
+       }
+
+       r = radius_get(wt, dst, src);
+       if (r) {
+               radius_msg_free(r->last_req);
+               r->last_req = msg;
+               return;
+       }
+       radius_msg_free(msg);
+}
+
+
+static void wlantest_add_pmk(struct wlantest *wt, const u8 *pmk)
+{
+       struct wlantest_pmk *p;
+
+       p = os_zalloc(sizeof(*p));
+       if (p == NULL)
+               return;
+       os_memcpy(p->pmk, pmk, 32);
+       dl_list_add(&wt->pmk, &p->list);
+       wpa_hexdump(MSG_INFO, "Add PMK", pmk, 32);
+}
+
+
+static void process_radius_access_accept(struct wlantest *wt, u32 dst, u32 src,
+                                        const u8 *data, size_t len)
+{
+       struct radius_msg *msg;
+       struct wlantest_radius *r;
+       struct radius_ms_mppe_keys *keys;
+       struct wlantest_radius_secret *s;
+
+       r = radius_get(wt, src, dst);
+       if (r == NULL || r->last_req == NULL) {
+               wpa_printf(MSG_DEBUG, "No RADIUS Access-Challenge found for "
+                          "decrypting Access-Accept keys");
+               return;
+       }
+
+       msg = radius_msg_parse(data, len);
+       if (msg == NULL) {
+               wpa_printf(MSG_DEBUG, "Failed to parse RADIUS Access-Accept");
+               return;
+       }
+
+       dl_list_for_each(s, &wt->secret, struct wlantest_radius_secret, list) {
+               int found = 0;
+               keys = radius_msg_get_ms_keys(msg, r->last_req,
+                                             (u8 *) s->secret,
+                                             os_strlen(s->secret));
+               if (keys && keys->send && keys->recv) {
+                       u8 pmk[32];
+                       wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key",
+                                       keys->send, keys->send_len);
+                       wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key",
+                                       keys->recv, keys->recv_len);
+                       os_memcpy(pmk, keys->recv,
+                                 keys->recv_len > 32 ? 32 : keys->recv_len);
+                       if (keys->recv_len < 32) {
+                               os_memcpy(pmk + keys->recv_len,
+                                         keys->send,
+                                         keys->recv_len + keys->send_len > 32
+                                         ? 32 : 32 - keys->recv_len);
+                       }
+                       wlantest_add_pmk(wt, pmk);
+                       found = 1;
+               }
+
+               if (keys) {
+                       os_free(keys->send);
+                       os_free(keys->recv);
+                       os_free(keys);
+               }
+
+               if (found)
+                       break;
+       }
+
+       radius_msg_free(msg);
+}
+
+
+static void process_radius(struct wlantest *wt, u32 dst, u16 dport, u32 src,
+                          u16 sport, const u8 *data, size_t len)
+{
+       struct in_addr addr;
+       char buf[20];
+       const struct radius_hdr *hdr;
+       u16 rlen;
+
+       if (len < sizeof(*hdr))
+               return;
+       hdr = (const struct radius_hdr *) data;
+       rlen = be_to_host16(hdr->length);
+       if (len < rlen)
+               return;
+       if (len > rlen)
+               len = rlen;
+
+       addr.s_addr = dst;
+       snprintf(buf, sizeof(buf), "%s", inet_ntoa(addr));
+
+       addr.s_addr = src;
+       wpa_printf(MSG_DEBUG, "RADIUS %s:%u -> %s:%u id=%u %s",
+                  inet_ntoa(addr), sport, buf, dport, hdr->identifier,
+                  radius_code_string(hdr->code));
+
+       switch (hdr->code) {
+       case RADIUS_CODE_ACCESS_REQUEST:
+               process_radius_access_request(wt, dst, src, data, len);
+               break;
+       case RADIUS_CODE_ACCESS_ACCEPT:
+               process_radius_access_accept(wt, dst, src, data, len);
+               break;
+       }
+}
+
+
+static void process_udp(struct wlantest *wt, u32 dst, u32 src,
+                       const u8 *data, size_t len)
+{
+       const struct udphdr *udp;
+       u16 sport, dport, ulen;
+       const u8 *payload;
+       size_t plen;
+
+       if (len < sizeof(*udp))
+               return;
+       udp = (const struct udphdr *) data;
+       /* TODO: check UDP checksum */
+       sport = be_to_host16(udp->source);
+       dport = be_to_host16(udp->dest);
+       ulen = be_to_host16(udp->len);
+
+       if (ulen > len)
+               return;
+       if (len < ulen)
+               len = ulen;
+
+       payload = (const u8 *) (udp + 1);
+       plen = len - sizeof(*udp);
+
+       if (sport == 1812 || dport == 1812)
+               process_radius(wt, dst, dport, src, sport, payload, plen);
+}
+
+
+static void process_ipv4(struct wlantest *wt, const u8 *data, size_t len)
+{
+       const struct iphdr *ip;
+       const u8 *payload;
+       size_t plen;
+       u16 frag_off, tot_len;
+
+       if (len < sizeof(*ip))
+               return;
+
+       ip = (const struct iphdr *) data;
+       if (ip->version != 4)
+               return;
+       if (ip->ihl < 5)
+               return;
+
+       /* TODO: check header checksum in ip->check */
+
+       frag_off = be_to_host16(ip->frag_off);
+       if (frag_off & 0x1fff) {
+               wpa_printf(MSG_EXCESSIVE, "IP fragment reassembly not yet "
+                          "supported");
+               return;
+       }
+
+       tot_len = be_to_host16(ip->tot_len);
+       if (tot_len > len)
+               return;
+       if (tot_len < len)
+               len = tot_len;
+
+       payload = data + 4 * ip->ihl;
+       plen = len - 4 * ip->ihl;
+       if (payload + plen > data + len)
+               return;
+
+       switch (ip->protocol) {
+       case IPPROTO_UDP:
+               process_udp(wt, ip->daddr, ip->saddr, payload, plen);
+               break;
+       }
+}
+
+
+void wlantest_process_wired(struct wlantest *wt, const u8 *data, size_t len)
+{
+       const struct ether_header *eth;
+       u16 ethertype;
+
+       wpa_hexdump(MSG_EXCESSIVE, "Process wired frame", data, len);
+
+       if (len < sizeof(*eth))
+               return;
+
+       eth = (const struct ether_header *) data;
+       ethertype = be_to_host16(eth->ether_type);
+
+       switch (ethertype) {
+       case ETHERTYPE_IP:
+               process_ipv4(wt, data + sizeof(*eth), len - sizeof(*eth));
+               break;
+       }
+}
diff --git a/wlantest/wlantest.c b/wlantest/wlantest.c
new file mode 100644 (file)
index 0000000..a1a0b04
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * 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.
+ */
+
+#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 wlantest_terminate(int sig, void *signal_ctx)
+{
+       eloop_terminate();
+}
+
+
+static void usage(void)
+{
+       printf("wlantest [-cddhqq] [-i<ifname>] [-r<pcap file>] "
+              "[-p<passphrase>]\n"
+               "         [-I<wired ifname>] [-R<wired pcap file>] "
+              "[-P<RADIUS shared secret>]\n"
+               "         [-w<write pcap file>] [-f<MSK/PMK file>]\n");
+}
+
+
+static void passphrase_deinit(struct wlantest_passphrase *p)
+{
+       dl_list_del(&p->list);
+       os_free(p);
+}
+
+
+static void secret_deinit(struct wlantest_radius_secret *r)
+{
+       dl_list_del(&r->list);
+       os_free(r);
+}
+
+
+static void wlantest_init(struct wlantest *wt)
+{
+       int i;
+       os_memset(wt, 0, sizeof(*wt));
+       wt->monitor_sock = -1;
+       wt->ctrl_sock = -1;
+       for (i = 0; i < MAX_CTRL_CONNECTIONS; i++)
+               wt->ctrl_socks[i] = -1;
+       dl_list_init(&wt->passphrase);
+       dl_list_init(&wt->bss);
+       dl_list_init(&wt->secret);
+       dl_list_init(&wt->radius);
+       dl_list_init(&wt->pmk);
+       dl_list_init(&wt->wep);
+}
+
+
+void radius_deinit(struct wlantest_radius *r)
+{
+       dl_list_del(&r->list);
+       os_free(r);
+}
+
+
+static void wlantest_deinit(struct wlantest *wt)
+{
+       struct wlantest_passphrase *p, *pn;
+       struct wlantest_radius_secret *s, *sn;
+       struct wlantest_radius *r, *rn;
+       struct wlantest_pmk *pmk, *np;
+       struct wlantest_wep *wep, *nw;
+
+       if (wt->ctrl_sock >= 0)
+               ctrl_deinit(wt);
+       if (wt->monitor_sock >= 0)
+               monitor_deinit(wt);
+       bss_flush(wt);
+       dl_list_for_each_safe(p, pn, &wt->passphrase,
+                             struct wlantest_passphrase, list)
+               passphrase_deinit(p);
+       dl_list_for_each_safe(s, sn, &wt->secret,
+                             struct wlantest_radius_secret, list)
+               secret_deinit(s);
+       dl_list_for_each_safe(r, rn, &wt->radius, struct wlantest_radius, list)
+               radius_deinit(r);
+       dl_list_for_each_safe(pmk, np, &wt->pmk, struct wlantest_pmk, list)
+               pmk_deinit(pmk);
+       dl_list_for_each_safe(wep, nw, &wt->wep, struct wlantest_wep, list)
+               os_free(wep);
+       write_pcap_deinit(wt);
+}
+
+
+static void add_passphrase(struct wlantest *wt, const char *passphrase)
+{
+       struct wlantest_passphrase *p;
+       size_t len = os_strlen(passphrase);
+
+       if (len < 8 || len > 63)
+               return;
+       p = os_zalloc(sizeof(*p));
+       if (p == NULL)
+               return;
+       os_memcpy(p->passphrase, passphrase, len);
+       dl_list_add(&wt->passphrase, &p->list);
+}
+
+
+static void add_secret(struct wlantest *wt, const char *secret)
+{
+       struct wlantest_radius_secret *s;
+       size_t len = os_strlen(secret);
+
+       if (len >= MAX_RADIUS_SECRET_LEN)
+               return;
+       s = os_zalloc(sizeof(*s));
+       if (s == NULL)
+               return;
+       os_memcpy(s->secret, secret, len);
+       dl_list_add(&wt->secret, &s->list);
+}
+
+
+static int add_pmk_file(struct wlantest *wt, const char *pmk_file)
+{
+       FILE *f;
+       u8 pmk[32];
+       char buf[300], *pos;
+       struct wlantest_pmk *p;
+
+       f = fopen(pmk_file, "r");
+       if (f == NULL) {
+               wpa_printf(MSG_ERROR, "Could not open '%s'", pmk_file);
+               return -1;
+       }
+
+       while (fgets(buf, sizeof(buf), f)) {
+               pos = buf;
+               while (*pos && *pos != '\r' && *pos != '\n')
+                       pos++;
+               *pos = '\0';
+               if (pos - buf < 2 * 32)
+                       continue;
+               if (hexstr2bin(buf, pmk, 32) < 0)
+                       continue;
+               p = os_zalloc(sizeof(*p));
+               if (p == NULL)
+                       break;
+               os_memcpy(p->pmk, pmk, 32);
+               dl_list_add(&wt->pmk, &p->list);
+               wpa_hexdump(MSG_DEBUG, "Added PMK from file", pmk, 32);
+       }
+
+       fclose(f);
+       return 0;
+}
+
+
+int add_wep(struct wlantest *wt, const char *key)
+{
+       struct wlantest_wep *w;
+       size_t len = os_strlen(key);
+
+       if (len != 2 * 5 && len != 2 * 13) {
+               wpa_printf(MSG_INFO, "Invalid WEP key '%s'", key);
+               return -1;
+       }
+       w = os_zalloc(sizeof(*w));
+       if (w == NULL)
+               return -1;
+       if (hexstr2bin(key, w->key, len / 2) < 0) {
+               os_free(w);
+               wpa_printf(MSG_INFO, "Invalid WEP key '%s'", key);
+               return -1;
+       }
+       w->key_len = len / 2;
+       dl_list_add(&wt->wep, &w->list);
+       return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+       int c;
+       const char *read_file = NULL;
+       const char *read_wired_file = NULL;
+       const char *write_file = NULL;
+       const char *ifname = NULL;
+       const char *ifname_wired = NULL;
+       struct wlantest wt;
+       int ctrl_iface = 0;
+
+       wpa_debug_level = MSG_INFO;
+       wpa_debug_show_keys = 1;
+
+       if (os_program_init())
+               return -1;
+
+       wlantest_init(&wt);
+
+       for (;;) {
+               c = getopt(argc, argv, "cdf:hi:I:p:P:qr:R:w:W:");
+               if (c < 0)
+                       break;
+               switch (c) {
+               case 'c':
+                       ctrl_iface = 1;
+                       break;
+               case 'd':
+                       if (wpa_debug_level > 0)
+                               wpa_debug_level--;
+                       break;
+               case 'f':
+                       if (add_pmk_file(&wt, optarg) < 0)
+                               return -1;
+                       break;
+               case 'h':
+                       usage();
+                       return 0;
+               case 'i':
+                       ifname = optarg;
+                       break;
+               case 'I':
+                       ifname_wired = optarg;
+                       break;
+               case 'p':
+                       add_passphrase(&wt, optarg);
+                       break;
+               case 'P':
+                       add_secret(&wt, optarg);
+                       break;
+               case 'q':
+                       wpa_debug_level++;
+                       break;
+               case 'r':
+                       read_file = optarg;
+                       break;
+               case 'R':
+                       read_wired_file = optarg;
+                       break;
+               case 'w':
+                       write_file = optarg;
+                       break;
+               case 'W':
+                       if (add_wep(&wt, optarg) < 0)
+                               return -1;
+                       break;
+               default:
+                       usage();
+                       return -1;
+               }
+       }
+
+       if (ifname == NULL && ifname_wired == NULL &&
+           read_file == NULL && read_wired_file == NULL) {
+               usage();
+               return 0;
+       }
+
+       if (eloop_init())
+               return -1;
+
+       if (write_file && write_pcap_init(&wt, write_file) < 0)
+               return -1;
+
+       if (read_wired_file && read_wired_cap_file(&wt, read_wired_file) < 0)
+               return -1;
+
+       if (read_file && read_cap_file(&wt, read_file) < 0)
+               return -1;
+
+       if (ifname && monitor_init(&wt, ifname) < 0)
+               return -1;
+
+       if (ifname_wired && monitor_init_wired(&wt, ifname_wired) < 0)
+               return -1;
+
+       if (ctrl_iface && ctrl_init(&wt) < 0)
+               return -1;
+
+       eloop_register_signal_terminate(wlantest_terminate, &wt);
+
+       eloop_run();
+
+       wpa_printf(MSG_INFO, "Processed: rx_mgmt=%u rx_ctrl=%u rx_data=%u "
+                  "fcs_error=%u",
+                  wt.rx_mgmt, wt.rx_ctrl, wt.rx_data, wt.fcs_error);
+
+       wlantest_deinit(&wt);
+
+       eloop_destroy();
+       os_program_deinit();
+
+       return 0;
+}
diff --git a/wlantest/wlantest.h b/wlantest/wlantest.h
new file mode 100644 (file)
index 0000000..4c65d48
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * 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.
+ */
+
+#ifndef WLANTEST_H
+#define WLANTEST_H
+
+#include "utils/list.h"
+#include "common/wpa_common.h"
+#include "wlantest_ctrl.h"
+
+struct ieee802_11_elems;
+struct radius_msg;
+struct ieee80211_hdr;
+struct wlantest_bss;
+
+#define MAX_RADIUS_SECRET_LEN 128
+
+struct wlantest_radius_secret {
+       struct dl_list list;
+       char secret[MAX_RADIUS_SECRET_LEN];
+};
+
+struct wlantest_passphrase {
+       struct dl_list list;
+       char passphrase[64];
+       u8 ssid[32];
+       size_t ssid_len;
+       u8 bssid[ETH_ALEN];
+};
+
+struct wlantest_pmk {
+       struct dl_list list;
+       u8 pmk[32];
+};
+
+struct wlantest_wep {
+       struct dl_list list;
+       size_t key_len;
+       u8 key[13];
+};
+
+struct wlantest_sta {
+       struct dl_list list;
+       struct wlantest_bss *bss;
+       u8 addr[ETH_ALEN];
+       enum {
+               STATE1 /* not authenticated */,
+               STATE2 /* authenticated */,
+               STATE3 /* associated */
+       } state;
+       u16 aid;
+       u8 rsnie[257]; /* WPA/RSN IE */
+       int proto;
+       int pairwise_cipher;
+       int group_cipher;
+       int key_mgmt;
+       int rsn_capab;
+       u8 anonce[32]; /* ANonce from the previous EAPOL-Key msg 1/4 or 3/4 */
+       u8 snonce[32]; /* SNonce from the previous EAPOL-Key msg 2/4 */
+       struct wpa_ptk ptk; /* Derived PTK */
+       int ptk_set;
+       struct wpa_ptk tptk; /* Derived PTK during rekeying */
+       int tptk_set;
+       u8 rsc_tods[16 + 1][6];
+       u8 rsc_fromds[16 + 1][6];
+       u8 ap_sa_query_tr[2];
+       u8 sta_sa_query_tr[2];
+       u32 counters[NUM_WLANTEST_STA_COUNTER];
+       u16 assocreq_capab_info;
+       u16 assocreq_listen_int;
+       u8 *assocreq_ies;
+       size_t assocreq_ies_len;
+
+       /* Last ICMP Echo request information */
+       u32 icmp_echo_req_src;
+       u32 icmp_echo_req_dst;
+       u16 icmp_echo_req_id;
+       u16 icmp_echo_req_seq;
+
+       le16 seq_ctrl_to_sta[17];
+       le16 seq_ctrl_to_ap[17];
+
+       int pwrmgt;
+       int pspoll;
+};
+
+struct wlantest_tdls {
+       struct dl_list list;
+       struct wlantest_sta *init;
+       struct wlantest_sta *resp;
+       struct tpk {
+               u8 kck[16];
+               u8 tk[16];
+       } tpk;
+       int link_up;
+       u8 dialog_token;
+       u8 rsc_init[16 + 1][6];
+       u8 rsc_resp[16 + 1][6];
+       u32 counters[NUM_WLANTEST_TDLS_COUNTER];
+};
+
+struct wlantest_bss {
+       struct dl_list list;
+       u8 bssid[ETH_ALEN];
+       u16 capab_info;
+       u16 prev_capab_info;
+       u8 ssid[32];
+       size_t ssid_len;
+       int proberesp_seen;
+       int parse_error_reported;
+       u8 wpaie[257];
+       u8 rsnie[257];
+       int proto;
+       int pairwise_cipher;
+       int group_cipher;
+       int mgmt_group_cipher;
+       int key_mgmt;
+       int rsn_capab;
+       struct dl_list sta; /* struct wlantest_sta */
+       struct dl_list pmk; /* struct wlantest_pmk */
+       u8 gtk[4][32];
+       size_t gtk_len[4];
+       int gtk_idx;
+       u8 rsc[4][6];
+       u8 igtk[6][16];
+       int igtk_set[6];
+       int igtk_idx;
+       u8 ipn[6][6];
+       u32 counters[NUM_WLANTEST_BSS_COUNTER];
+       struct dl_list tdls; /* struct wlantest_tdls */
+};
+
+struct wlantest_radius {
+       struct dl_list list;
+       u32 srv;
+       u32 cli;
+       struct radius_msg *last_req;
+};
+
+
+#define MAX_CTRL_CONNECTIONS 10
+
+struct wlantest {
+       int monitor_sock;
+       int monitor_wired;
+
+       int ctrl_sock;
+       int ctrl_socks[MAX_CTRL_CONNECTIONS];
+
+       struct dl_list passphrase; /* struct wlantest_passphrase */
+       struct dl_list bss; /* struct wlantest_bss */
+       struct dl_list secret; /* struct wlantest_radius_secret */
+       struct dl_list radius; /* struct wlantest_radius */
+       struct dl_list pmk; /* struct wlantest_pmk */
+       struct dl_list wep; /* struct wlantest_wep */
+
+       unsigned int rx_mgmt;
+       unsigned int rx_ctrl;
+       unsigned int rx_data;
+       unsigned int fcs_error;
+
+       void *write_pcap; /* pcap_t* */
+       void *write_pcap_dumper; /* pcpa_dumper_t */
+       struct timeval write_pcap_time;
+
+       u8 last_hdr[30];
+       size_t last_len;
+       int last_mgmt_valid;
+};
+
+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);
+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);
+void wlantest_process_wired(struct wlantest *wt, const u8 *data, size_t len);
+u32 crc32(const u8 *frame, size_t frame_len);
+int monitor_init(struct wlantest *wt, const char *ifname);
+int monitor_init_wired(struct wlantest *wt, const char *ifname);
+void monitor_deinit(struct wlantest *wt);
+void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len);
+void rx_mgmt_ack(struct wlantest *wt, const struct ieee80211_hdr *hdr);
+void rx_data(struct wlantest *wt, const u8 *data, size_t len);
+void rx_data_eapol(struct wlantest *wt, const u8 *dst, const u8 *src,
+                  const u8 *data, size_t len, int prot);
+void rx_data_ip(struct wlantest *wt, const u8 *bssid, const u8 *sta_addr,
+               const u8 *dst, const u8 *src, const u8 *data, size_t len,
+               const u8 *peer_addr);
+void rx_data_80211_encap(struct wlantest *wt, const u8 *bssid,
+                        const u8 *sta_addr, const u8 *dst, const u8 *src,
+                        const u8 *data, size_t len);
+
+struct wlantest_bss * bss_find(struct wlantest *wt, const u8 *bssid);
+struct wlantest_bss * bss_get(struct wlantest *wt, const u8 *bssid);
+void bss_deinit(struct wlantest_bss *bss);
+void bss_update(struct wlantest *wt, struct wlantest_bss *bss,
+               struct ieee802_11_elems *elems);
+void bss_flush(struct wlantest *wt);
+int bss_add_pmk_from_passphrase(struct wlantest_bss *bss,
+                               const char *passphrase);
+void pmk_deinit(struct wlantest_pmk *pmk);
+void tdls_deinit(struct wlantest_tdls *tdls);
+
+struct wlantest_sta * sta_find(struct wlantest_bss *bss, const u8 *addr);
+struct wlantest_sta * sta_get(struct wlantest_bss *bss, const u8 *addr);
+void sta_deinit(struct wlantest_sta *sta);
+void sta_update_assoc(struct wlantest_sta *sta,
+                     struct ieee802_11_elems *elems);
+
+u8 * ccmp_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
+                 const u8 *data, size_t data_len, size_t *decrypted_len);
+u8 * ccmp_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos,
+                 u8 *pn, int keyid, size_t *encrypted_len);
+void ccmp_get_pn(u8 *pn, const u8 *data);
+
+u8 * tkip_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
+                 const u8 *data, size_t data_len, size_t *decrypted_len);
+u8 * tkip_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos,
+                 u8 *pn, int keyid, size_t *encrypted_len);
+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);
+
+int ctrl_init(struct wlantest *wt);
+void ctrl_deinit(struct wlantest *wt);
+
+int wlantest_inject(struct wlantest *wt, struct wlantest_bss *bss,
+                   struct wlantest_sta *sta, u8 *frame, size_t len,
+                   enum wlantest_inject_protection prot);
+
+#endif /* WLANTEST_H */
diff --git a/wlantest/wlantest_cli.c b/wlantest/wlantest_cli.c
new file mode 100644 (file)
index 0000000..6377fc1
--- /dev/null
@@ -0,0 +1,1719 @@
+/*
+ * wlantest controller
+ * 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.
+ */
+
+#include "utils/includes.h"
+#include <sys/un.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/edit.h"
+#include "wlantest_ctrl.h"
+
+
+static int get_cmd_arg_num(const char *str, int pos)
+{
+       int arg = 0, i;
+
+       for (i = 0; i <= pos; i++) {
+               if (str[i] != ' ') {
+                       arg++;
+                       while (i <= pos && str[i] != ' ')
+                               i++;
+               }
+       }
+
+       if (arg > 0)
+               arg--;
+       return arg;
+}
+
+
+static int get_prev_arg_pos(const char *str, int pos)
+{
+       while (pos > 0 && str[pos - 1] != ' ')
+               pos--;
+       while (pos > 0 && str[pos - 1] == ' ')
+               pos--;
+       while (pos > 0 && str[pos - 1] != ' ')
+               pos--;
+       return pos;
+}
+
+
+static u8 * attr_get(u8 *buf, size_t buflen, enum wlantest_ctrl_attr attr,
+                    size_t *len)
+{
+       u8 *pos = buf;
+
+       while (pos + 8 <= buf + buflen) {
+               enum wlantest_ctrl_attr a;
+               size_t alen;
+               a = WPA_GET_BE32(pos);
+               pos += 4;
+               alen = WPA_GET_BE32(pos);
+               pos += 4;
+               if (pos + alen > buf + buflen) {
+                       printf("Invalid control message attribute\n");
+                       return NULL;
+               }
+               if (a == attr) {
+                       *len = alen;
+                       return pos;
+               }
+               pos += alen;
+       }
+
+       return NULL;
+}
+
+
+static u8 * attr_hdr_add(u8 *pos, u8 *end, enum wlantest_ctrl_attr attr,
+                        size_t len)
+{
+       if (pos == NULL || end - pos < 8 + len)
+               return NULL;
+       WPA_PUT_BE32(pos, attr);
+       pos += 4;
+       WPA_PUT_BE32(pos, len);
+       pos += 4;
+       return pos;
+}
+
+
+static u8 * attr_add_str(u8 *pos, u8 *end, enum wlantest_ctrl_attr attr,
+                        const char *str)
+{
+       size_t len = os_strlen(str);
+
+       if (pos == NULL || end - pos < 8 + len)
+               return NULL;
+       WPA_PUT_BE32(pos, attr);
+       pos += 4;
+       WPA_PUT_BE32(pos, len);
+       pos += 4;
+       os_memcpy(pos, str, len);
+       pos += len;
+       return pos;
+}
+
+
+static u8 * attr_add_be32(u8 *pos, u8 *end, enum wlantest_ctrl_attr attr,
+                         u32 val)
+{
+       if (pos == NULL || end - pos < 12)
+               return NULL;
+       WPA_PUT_BE32(pos, attr);
+       pos += 4;
+       WPA_PUT_BE32(pos, 4);
+       pos += 4;
+       WPA_PUT_BE32(pos, val);
+       pos += 4;
+       return pos;
+}
+
+
+static int cmd_send_and_recv(int s, const u8 *cmd, size_t cmd_len,
+                            u8 *resp, size_t max_resp_len)
+{
+       int res;
+       enum wlantest_ctrl_cmd cmd_resp;
+
+       if (send(s, cmd, cmd_len, 0) < 0)
+               return -1;
+       res = recv(s, resp, max_resp_len, 0);
+       if (res < 4)
+               return -1;
+
+       cmd_resp = WPA_GET_BE32(resp);
+       if (cmd_resp == WLANTEST_CTRL_SUCCESS)
+               return res;
+
+       if (cmd_resp == WLANTEST_CTRL_UNKNOWN_CMD)
+               printf("Unknown command\n");
+       else if (cmd_resp == WLANTEST_CTRL_INVALID_CMD)
+               printf("Invalid command\n");
+
+       return -1;
+}
+
+
+static int cmd_simple(int s, enum wlantest_ctrl_cmd cmd)
+{
+       u8 buf[4];
+       int res;
+       WPA_PUT_BE32(buf, cmd);
+       res = cmd_send_and_recv(s, buf, sizeof(buf), buf, sizeof(buf));
+       return res < 0 ? -1 : 0;
+}
+
+
+static char ** get_bssid_list(int s)
+{
+       u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
+       u8 buf[4];
+       u8 *bssid;
+       size_t len;
+       int rlen, i;
+       char **res;
+
+       WPA_PUT_BE32(buf, WLANTEST_CTRL_LIST_BSS);
+       rlen = cmd_send_and_recv(s, buf, sizeof(buf), resp, sizeof(resp));
+       if (rlen < 0)
+               return NULL;
+
+       bssid = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_BSSID, &len);
+       if (bssid == NULL)
+               return NULL;
+
+       res = os_zalloc((len / ETH_ALEN + 1) * sizeof(char *));
+       if (res == NULL)
+               return NULL;
+       for (i = 0; i < len / ETH_ALEN; i++) {
+               res[i] = os_zalloc(18);
+               if (res[i] == NULL)
+                       break;
+               os_snprintf(res[i], 18, MACSTR, MAC2STR(bssid + ETH_ALEN * i));
+       }
+
+       return res;
+}
+
+
+static char ** get_sta_list(int s, const u8 *bssid, int add_bcast)
+{
+       u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
+       u8 buf[100], *pos, *end;
+       u8 *addr;
+       size_t len;
+       int rlen, i;
+       char **res;
+
+       pos = buf;
+       end = buf + sizeof(buf);
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_LIST_STA);
+       pos += 4;
+       pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
+       os_memcpy(pos, bssid, ETH_ALEN);
+       pos += ETH_ALEN;
+       rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
+       if (rlen < 0)
+               return NULL;
+
+       addr = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_STA_ADDR, &len);
+       if (addr == NULL)
+               return NULL;
+
+       res = os_zalloc((len / ETH_ALEN + 1 + add_bcast) * sizeof(char *));
+       if (res == NULL)
+               return NULL;
+       for (i = 0; i < len / ETH_ALEN; i++) {
+               res[i] = os_zalloc(18);
+               if (res[i] == NULL)
+                       break;
+               os_snprintf(res[i], 18, MACSTR, MAC2STR(addr + ETH_ALEN * i));
+       }
+       if (add_bcast)
+               res[i] = os_strdup("ff:ff:ff:ff:ff:ff");
+
+       return res;
+}
+
+
+static int cmd_ping(int s, int argc, char *argv[])
+{
+       int res = cmd_simple(s, WLANTEST_CTRL_PING);
+       if (res == 0)
+               printf("PONG\n");
+       return res == 0;
+}
+
+
+static int cmd_terminate(int s, int argc, char *argv[])
+{
+       return cmd_simple(s, WLANTEST_CTRL_TERMINATE);
+}
+
+
+static int cmd_list_bss(int s, int argc, char *argv[])
+{
+       u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
+       u8 buf[4];
+       u8 *bssid;
+       size_t len;
+       int rlen, i;
+
+       WPA_PUT_BE32(buf, WLANTEST_CTRL_LIST_BSS);
+       rlen = cmd_send_and_recv(s, buf, sizeof(buf), resp, sizeof(resp));
+       if (rlen < 0)
+               return -1;
+
+       bssid = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_BSSID, &len);
+       if (bssid == NULL)
+               return -1;
+
+       for (i = 0; i < len / ETH_ALEN; i++)
+               printf(MACSTR " ", MAC2STR(bssid + ETH_ALEN * i));
+       printf("\n");
+
+       return 0;
+}
+
+
+static int cmd_list_sta(int s, int argc, char *argv[])
+{
+       u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
+       u8 buf[100], *pos;
+       u8 *addr;
+       size_t len;
+       int rlen, i;
+
+       if (argc < 1) {
+               printf("list_sta needs one argument: BSSID\n");
+               return -1;
+       }
+
+       pos = buf;
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_LIST_STA);
+       pos += 4;
+       WPA_PUT_BE32(pos, WLANTEST_ATTR_BSSID);
+       pos += 4;
+       WPA_PUT_BE32(pos, ETH_ALEN);
+       pos += 4;
+       if (hwaddr_aton(argv[0], pos) < 0) {
+               printf("Invalid BSSID '%s'\n", argv[0]);
+               return -1;
+       }
+       pos += ETH_ALEN;
+
+       rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
+       if (rlen < 0)
+               return -1;
+
+       addr = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_STA_ADDR, &len);
+       if (addr == NULL)
+               return -1;
+
+       for (i = 0; i < len / ETH_ALEN; i++)
+               printf(MACSTR " ", MAC2STR(addr + ETH_ALEN * i));
+       printf("\n");
+
+       return 0;
+}
+
+
+static char ** complete_list_sta(int s, const char *str, int pos)
+{
+       if (get_cmd_arg_num(str, pos) == 1)
+               return get_bssid_list(s);
+       return NULL;
+}
+
+
+static int cmd_flush(int s, int argc, char *argv[])
+{
+       return cmd_simple(s, WLANTEST_CTRL_FLUSH);
+}
+
+
+static int cmd_clear_sta_counters(int s, int argc, char *argv[])
+{
+       u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
+       u8 buf[100], *pos;
+       int rlen;
+
+       if (argc < 2) {
+               printf("clear_sta_counters needs two arguments: BSSID and "
+                      "STA address\n");
+               return -1;
+       }
+
+       pos = buf;
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_CLEAR_STA_COUNTERS);
+       pos += 4;
+       WPA_PUT_BE32(pos, WLANTEST_ATTR_BSSID);
+       pos += 4;
+       WPA_PUT_BE32(pos, ETH_ALEN);
+       pos += 4;
+       if (hwaddr_aton(argv[0], pos) < 0) {
+               printf("Invalid BSSID '%s'\n", argv[0]);
+               return -1;
+       }
+       pos += ETH_ALEN;
+
+       WPA_PUT_BE32(pos, WLANTEST_ATTR_STA_ADDR);
+       pos += 4;
+       WPA_PUT_BE32(pos, ETH_ALEN);
+       pos += 4;
+       if (hwaddr_aton(argv[1], pos) < 0) {
+               printf("Invalid STA address '%s'\n", argv[1]);
+               return -1;
+       }
+       pos += ETH_ALEN;
+
+       rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
+       if (rlen < 0)
+               return -1;
+       printf("OK\n");
+       return 0;
+}
+
+
+static char ** complete_clear_sta_counters(int s, const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       char **res = NULL;
+       u8 addr[ETH_ALEN];
+
+       switch (arg) {
+       case 1:
+               res = get_bssid_list(s);
+               break;
+       case 2:
+               if (hwaddr_aton(&str[get_prev_arg_pos(str, pos)], addr) < 0)
+                       break;
+               res = get_sta_list(s, addr, 0);
+               break;
+       }
+
+       return res;
+}
+
+
+static int cmd_clear_bss_counters(int s, int argc, char *argv[])
+{
+       u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
+       u8 buf[100], *pos;
+       int rlen;
+
+       if (argc < 1) {
+               printf("clear_bss_counters needs one argument: BSSID\n");
+               return -1;
+       }
+
+       pos = buf;
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_CLEAR_BSS_COUNTERS);
+       pos += 4;
+       WPA_PUT_BE32(pos, WLANTEST_ATTR_BSSID);
+       pos += 4;
+       WPA_PUT_BE32(pos, ETH_ALEN);
+       pos += 4;
+       if (hwaddr_aton(argv[0], pos) < 0) {
+               printf("Invalid BSSID '%s'\n", argv[0]);
+               return -1;
+       }
+       pos += ETH_ALEN;
+
+       rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
+       if (rlen < 0)
+               return -1;
+       printf("OK\n");
+       return 0;
+}
+
+
+static char ** complete_clear_bss_counters(int s, const char *str, int pos)
+{
+       if (get_cmd_arg_num(str, pos) == 1)
+               return get_bssid_list(s);
+       return NULL;
+}
+
+
+static int cmd_clear_tdls_counters(int s, int argc, char *argv[])
+{
+       u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
+       u8 buf[100], *pos;
+       int rlen;
+
+       if (argc < 3) {
+               printf("clear_tdls_counters needs three arguments: BSSID, "
+                      "STA1 address, STA2 address\n");
+               return -1;
+       }
+
+       pos = buf;
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_CLEAR_TDLS_COUNTERS);
+       pos += 4;
+       WPA_PUT_BE32(pos, WLANTEST_ATTR_BSSID);
+       pos += 4;
+       WPA_PUT_BE32(pos, ETH_ALEN);
+       pos += 4;
+       if (hwaddr_aton(argv[0], pos) < 0) {
+               printf("Invalid BSSID '%s'\n", argv[0]);
+               return -1;
+       }
+       pos += ETH_ALEN;
+
+       WPA_PUT_BE32(pos, WLANTEST_ATTR_STA_ADDR);
+       pos += 4;
+       WPA_PUT_BE32(pos, ETH_ALEN);
+       pos += 4;
+       if (hwaddr_aton(argv[1], pos) < 0) {
+               printf("Invalid STA1 address '%s'\n", argv[1]);
+               return -1;
+       }
+       pos += ETH_ALEN;
+
+       WPA_PUT_BE32(pos, WLANTEST_ATTR_STA2_ADDR);
+       pos += 4;
+       WPA_PUT_BE32(pos, ETH_ALEN);
+       pos += 4;
+       if (hwaddr_aton(argv[2], pos) < 0) {
+               printf("Invalid STA2 address '%s'\n", argv[2]);
+               return -1;
+       }
+       pos += ETH_ALEN;
+
+       rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
+       if (rlen < 0)
+               return -1;
+       printf("OK\n");
+       return 0;
+}
+
+
+static char ** complete_clear_tdls_counters(int s, const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       char **res = NULL;
+       u8 addr[ETH_ALEN];
+
+       switch (arg) {
+       case 1:
+               res = get_bssid_list(s);
+               break;
+       case 2:
+       case 3:
+               if (hwaddr_aton(&str[get_prev_arg_pos(str, pos)], addr) < 0)
+                       break;
+               res = get_sta_list(s, addr, 0);
+               break;
+       }
+
+       return res;
+}
+
+
+struct sta_counters {
+       const char *name;
+       enum wlantest_sta_counter num;
+};
+
+static const struct sta_counters sta_counters[] = {
+       { "auth_tx", WLANTEST_STA_COUNTER_AUTH_TX },
+       { "auth_rx", WLANTEST_STA_COUNTER_AUTH_RX },
+       { "assocreq_tx", WLANTEST_STA_COUNTER_ASSOCREQ_TX },
+       { "reassocreq_tx", WLANTEST_STA_COUNTER_REASSOCREQ_TX },
+       { "ptk_learned", WLANTEST_STA_COUNTER_PTK_LEARNED },
+       { "valid_deauth_tx", WLANTEST_STA_COUNTER_VALID_DEAUTH_TX },
+       { "valid_deauth_rx", WLANTEST_STA_COUNTER_VALID_DEAUTH_RX },
+       { "invalid_deauth_tx", WLANTEST_STA_COUNTER_INVALID_DEAUTH_TX },
+       { "invalid_deauth_rx", WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX },
+       { "valid_disassoc_tx", WLANTEST_STA_COUNTER_VALID_DISASSOC_TX },
+       { "valid_disassoc_rx", WLANTEST_STA_COUNTER_VALID_DISASSOC_RX },
+       { "invalid_disassoc_tx", WLANTEST_STA_COUNTER_INVALID_DISASSOC_TX },
+       { "invalid_disassoc_rx", WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX },
+       { "valid_saqueryreq_tx", WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_TX },
+       { "valid_saqueryreq_rx", WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_RX },
+       { "invalid_saqueryreq_tx",
+         WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_TX },
+       { "invalid_saqueryreq_rx",
+         WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_RX },
+       { "valid_saqueryresp_tx", WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_TX },
+       { "valid_saqueryresp_rx", WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_RX },
+       { "invalid_saqueryresp_tx",
+         WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_TX },
+       { "invalid_saqueryresp_rx",
+         WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_RX },
+       { "ping_ok", WLANTEST_STA_COUNTER_PING_OK },
+       { "assocresp_comeback", WLANTEST_STA_COUNTER_ASSOCRESP_COMEBACK },
+       { "reassocresp_comeback", WLANTEST_STA_COUNTER_REASSOCRESP_COMEBACK },
+       { "ping_ok_first_assoc", WLANTEST_STA_COUNTER_PING_OK_FIRST_ASSOC },
+       { "valid_deauth_rx_ack", WLANTEST_STA_COUNTER_VALID_DEAUTH_RX_ACK },
+       { "valid_disassoc_rx_ack",
+         WLANTEST_STA_COUNTER_VALID_DISASSOC_RX_ACK },
+       { "invalid_deauth_rx_ack",
+         WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX_ACK },
+       { "invalid_disassoc_rx_ack",
+         WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX_ACK },
+       { "deauth_rx_asleep", WLANTEST_STA_COUNTER_DEAUTH_RX_ASLEEP },
+       { "deauth_rx_awake", WLANTEST_STA_COUNTER_DEAUTH_RX_AWAKE },
+       { "disassoc_rx_asleep", WLANTEST_STA_COUNTER_DISASSOC_RX_ASLEEP },
+       { "disassoc_rx_awake", WLANTEST_STA_COUNTER_DISASSOC_RX_AWAKE },
+       { "prot_data_tx", WLANTEST_STA_COUNTER_PROT_DATA_TX },
+       { "deauth_rx_rc6", WLANTEST_STA_COUNTER_DEAUTH_RX_RC6 },
+       { "deauth_rx_rc7", WLANTEST_STA_COUNTER_DEAUTH_RX_RC7 },
+       { "disassoc_rx_rc6", WLANTEST_STA_COUNTER_DISASSOC_RX_RC6 },
+       { "disassoc_rx_rc7", WLANTEST_STA_COUNTER_DISASSOC_RX_RC7 },
+       { NULL, 0 }
+};
+
+static int cmd_get_sta_counter(int s, int argc, char *argv[])
+{
+       u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
+       u8 buf[100], *end, *pos;
+       int rlen, i;
+       size_t len;
+
+       if (argc != 3) {
+               printf("get_sta_counter needs at three arguments: "
+                      "counter name, BSSID, and STA address\n");
+               return -1;
+       }
+
+       pos = buf;
+       end = buf + sizeof(buf);
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_GET_STA_COUNTER);
+       pos += 4;
+
+       for (i = 0; sta_counters[i].name; i++) {
+               if (os_strcasecmp(sta_counters[i].name, argv[0]) == 0)
+                       break;
+       }
+       if (sta_counters[i].name == NULL) {
+               printf("Unknown STA counter '%s'\n", argv[0]);
+               printf("Counters:");
+               for (i = 0; sta_counters[i].name; i++)
+                       printf(" %s", sta_counters[i].name);
+               printf("\n");
+               return -1;
+       }
+
+       pos = attr_add_be32(pos, end, WLANTEST_ATTR_STA_COUNTER,
+                           sta_counters[i].num);
+       pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
+       if (hwaddr_aton(argv[1], pos) < 0) {
+               printf("Invalid BSSID '%s'\n", argv[1]);
+               return -1;
+       }
+       pos += ETH_ALEN;
+
+       pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN);
+       if (hwaddr_aton(argv[2], pos) < 0) {
+               printf("Invalid STA address '%s'\n", argv[2]);
+               return -1;
+       }
+       pos += ETH_ALEN;
+
+       rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
+       if (rlen < 0)
+               return -1;
+
+       pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_COUNTER, &len);
+       if (pos == NULL || len != 4)
+               return -1;
+       printf("%u\n", WPA_GET_BE32(pos));
+       return 0;
+}
+
+
+static char ** complete_get_sta_counter(int s, const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       char **res = NULL;
+       int i, count;
+       u8 addr[ETH_ALEN];
+
+       switch (arg) {
+       case 1:
+               /* counter list */
+               count = sizeof(sta_counters) / sizeof(sta_counters[0]);
+               res = os_zalloc(count * sizeof(char *));
+               if (res == NULL)
+                       return NULL;
+               for (i = 0; sta_counters[i].name; i++) {
+                       res[i] = os_strdup(sta_counters[i].name);
+                       if (res[i] == NULL)
+                               break;
+               }
+               break;
+       case 2:
+               res = get_bssid_list(s);
+               break;
+       case 3:
+               if (hwaddr_aton(&str[get_prev_arg_pos(str, pos)], addr) < 0)
+                       break;
+               res = get_sta_list(s, addr, 0);
+               break;
+       }
+
+       return res;
+}
+
+
+struct bss_counters {
+       const char *name;
+       enum wlantest_bss_counter num;
+};
+
+static const struct bss_counters bss_counters[] = {
+       { "valid_bip_mmie", WLANTEST_BSS_COUNTER_VALID_BIP_MMIE },
+       { "invalid_bip_mmie", WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE },
+       { "missing_bip_mmie", WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE },
+       { "bip_deauth", WLANTEST_BSS_COUNTER_BIP_DEAUTH },
+       { "bip_disassoc", WLANTEST_BSS_COUNTER_BIP_DISASSOC },
+       { NULL, 0 }
+};
+
+static int cmd_get_bss_counter(int s, int argc, char *argv[])
+{
+       u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
+       u8 buf[100], *end, *pos;
+       int rlen, i;
+       size_t len;
+
+       if (argc != 2) {
+               printf("get_bss_counter needs at two arguments: "
+                      "counter name and BSSID\n");
+               return -1;
+       }
+
+       pos = buf;
+       end = buf + sizeof(buf);
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_GET_BSS_COUNTER);
+       pos += 4;
+
+       for (i = 0; bss_counters[i].name; i++) {
+               if (os_strcasecmp(bss_counters[i].name, argv[0]) == 0)
+                       break;
+       }
+       if (bss_counters[i].name == NULL) {
+               printf("Unknown BSS counter '%s'\n", argv[0]);
+               printf("Counters:");
+               for (i = 0; bss_counters[i].name; i++)
+                       printf(" %s", bss_counters[i].name);
+               printf("\n");
+               return -1;
+       }
+
+       pos = attr_add_be32(pos, end, WLANTEST_ATTR_BSS_COUNTER,
+                           bss_counters[i].num);
+       pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
+       if (hwaddr_aton(argv[1], pos) < 0) {
+               printf("Invalid BSSID '%s'\n", argv[1]);
+               return -1;
+       }
+       pos += ETH_ALEN;
+
+       rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
+       if (rlen < 0)
+               return -1;
+
+       pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_COUNTER, &len);
+       if (pos == NULL || len != 4)
+               return -1;
+       printf("%u\n", WPA_GET_BE32(pos));
+       return 0;
+}
+
+
+static char ** complete_get_bss_counter(int s, const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       char **res = NULL;
+       int i, count;
+
+       switch (arg) {
+       case 1:
+               /* counter list */
+               count = sizeof(bss_counters) / sizeof(bss_counters[0]);
+               res = os_zalloc(count * sizeof(char *));
+               if (res == NULL)
+                       return NULL;
+               for (i = 0; bss_counters[i].name; i++) {
+                       res[i] = os_strdup(bss_counters[i].name);
+                       if (res[i] == NULL)
+                               break;
+               }
+               break;
+       case 2:
+               res = get_bssid_list(s);
+               break;
+       }
+
+       return res;
+}
+
+
+struct tdls_counters {
+       const char *name;
+       enum wlantest_tdls_counter num;
+};
+
+static const struct tdls_counters tdls_counters[] = {
+       { "valid_direct_link", WLANTEST_TDLS_COUNTER_VALID_DIRECT_LINK },
+       { "invalid_direct_link", WLANTEST_TDLS_COUNTER_INVALID_DIRECT_LINK },
+       { "valid_ap_path", WLANTEST_TDLS_COUNTER_VALID_AP_PATH },
+       { "invalid_ap_path", WLANTEST_TDLS_COUNTER_INVALID_AP_PATH },
+       { "setup_req", WLANTEST_TDLS_COUNTER_SETUP_REQ },
+       { "setup_resp_ok", WLANTEST_TDLS_COUNTER_SETUP_RESP_OK },
+       { "setup_resp_fail", WLANTEST_TDLS_COUNTER_SETUP_RESP_FAIL },
+       { "setup_conf_ok", WLANTEST_TDLS_COUNTER_SETUP_CONF_OK },
+       { "setup_conf_fail", WLANTEST_TDLS_COUNTER_SETUP_CONF_FAIL },
+       { "teardown", WLANTEST_TDLS_COUNTER_TEARDOWN },
+       { NULL, 0 }
+};
+
+static int cmd_get_tdls_counter(int s, int argc, char *argv[])
+{
+       u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
+       u8 buf[100], *end, *pos;
+       int rlen, i;
+       size_t len;
+
+       if (argc != 4) {
+               printf("get_tdls_counter needs four arguments: "
+                      "counter name, BSSID, STA1 address, STA2 address\n");
+               return -1;
+       }
+
+       pos = buf;
+       end = buf + sizeof(buf);
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_GET_TDLS_COUNTER);
+       pos += 4;
+
+       for (i = 0; tdls_counters[i].name; i++) {
+               if (os_strcasecmp(tdls_counters[i].name, argv[0]) == 0)
+                       break;
+       }
+       if (tdls_counters[i].name == NULL) {
+               printf("Unknown TDLS counter '%s'\n", argv[0]);
+               printf("Counters:");
+               for (i = 0; tdls_counters[i].name; i++)
+                       printf(" %s", tdls_counters[i].name);
+               printf("\n");
+               return -1;
+       }
+
+       pos = attr_add_be32(pos, end, WLANTEST_ATTR_TDLS_COUNTER,
+                           tdls_counters[i].num);
+       pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
+       if (hwaddr_aton(argv[1], pos) < 0) {
+               printf("Invalid BSSID '%s'\n", argv[1]);
+               return -1;
+       }
+       pos += ETH_ALEN;
+
+       pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN);
+       if (hwaddr_aton(argv[2], pos) < 0) {
+               printf("Invalid STA1 address '%s'\n", argv[2]);
+               return -1;
+       }
+       pos += ETH_ALEN;
+
+       pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA2_ADDR, ETH_ALEN);
+       if (hwaddr_aton(argv[3], pos) < 0) {
+               printf("Invalid STA2 address '%s'\n", argv[3]);
+               return -1;
+       }
+       pos += ETH_ALEN;
+
+       rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
+       if (rlen < 0)
+               return -1;
+
+       pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_COUNTER, &len);
+       if (pos == NULL || len != 4)
+               return -1;
+       printf("%u\n", WPA_GET_BE32(pos));
+       return 0;
+}
+
+
+static char ** complete_get_tdls_counter(int s, const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       char **res = NULL;
+       int i, count;
+       u8 addr[ETH_ALEN];
+
+       switch (arg) {
+       case 1:
+               /* counter list */
+               count = sizeof(tdls_counters) / sizeof(tdls_counters[0]);
+               res = os_zalloc(count * sizeof(char *));
+               if (res == NULL)
+                       return NULL;
+               for (i = 0; tdls_counters[i].name; i++) {
+                       res[i] = os_strdup(tdls_counters[i].name);
+                       if (res[i] == NULL)
+                               break;
+               }
+               break;
+       case 2:
+               res = get_bssid_list(s);
+               break;
+       case 3:
+       case 4:
+               if (hwaddr_aton(&str[get_prev_arg_pos(str, pos)], addr) < 0)
+                       break;
+               res = get_sta_list(s, addr, 0);
+               break;
+       }
+
+       return res;
+}
+
+
+struct inject_frames {
+       const char *name;
+       enum wlantest_inject_frame frame;
+};
+
+static const struct inject_frames inject_frames[] = {
+       { "auth", WLANTEST_FRAME_AUTH },
+       { "assocreq", WLANTEST_FRAME_ASSOCREQ },
+       { "reassocreq", WLANTEST_FRAME_REASSOCREQ },
+       { "deauth", WLANTEST_FRAME_DEAUTH },
+       { "disassoc", WLANTEST_FRAME_DISASSOC },
+       { "saqueryreq", WLANTEST_FRAME_SAQUERYREQ },
+       { NULL, 0 }
+};
+
+static int cmd_inject(int s, int argc, char *argv[])
+{
+       u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
+       u8 buf[100], *end, *pos;
+       int rlen, i;
+       enum wlantest_inject_protection prot;
+
+       /* <frame> <prot> <sender> <BSSID> <STA/ff:ff:ff:ff:ff:ff> */
+
+       if (argc < 5) {
+               printf("inject needs five arguments: frame, protection, "
+                      "sender, BSSID, STA/ff:ff:ff:ff:ff:ff\n");
+               return -1;
+       }
+
+       pos = buf;
+       end = buf + sizeof(buf);
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_INJECT);
+       pos += 4;
+
+       for (i = 0; inject_frames[i].name; i++) {
+               if (os_strcasecmp(inject_frames[i].name, argv[0]) == 0)
+                       break;
+       }
+       if (inject_frames[i].name == NULL) {
+               printf("Unknown inject frame '%s'\n", argv[0]);
+               printf("Frames:");
+               for (i = 0; inject_frames[i].name; i++)
+                       printf(" %s", inject_frames[i].name);
+               printf("\n");
+               return -1;
+       }
+
+       pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_FRAME,
+                           inject_frames[i].frame);
+
+       if (os_strcasecmp(argv[1], "normal") == 0)
+               prot = WLANTEST_INJECT_NORMAL;
+       else if (os_strcasecmp(argv[1], "protected") == 0)
+               prot = WLANTEST_INJECT_PROTECTED;
+       else if (os_strcasecmp(argv[1], "unprotected") == 0)
+               prot = WLANTEST_INJECT_UNPROTECTED;
+       else if (os_strcasecmp(argv[1], "incorrect") == 0)
+               prot = WLANTEST_INJECT_INCORRECT_KEY;
+       else {
+               printf("Unknown protection type '%s'\n", argv[1]);
+               printf("Protection types: normal protected unprotected "
+                      "incorrect\n");
+               return -1;
+       }
+       pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_PROTECTION, prot);
+
+       if (os_strcasecmp(argv[2], "ap") == 0) {
+               pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_SENDER_AP,
+                                   1);
+       } else if (os_strcasecmp(argv[2], "sta") == 0) {
+               pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_SENDER_AP,
+                                   0);
+       } else {
+               printf("Unknown sender '%s'\n", argv[2]);
+               printf("Sender types: ap sta\n");
+               return -1;
+       }
+
+       pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
+       if (hwaddr_aton(argv[3], pos) < 0) {
+               printf("Invalid BSSID '%s'\n", argv[3]);
+               return -1;
+       }
+       pos += ETH_ALEN;
+
+       pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN);
+       if (hwaddr_aton(argv[4], pos) < 0) {
+               printf("Invalid STA '%s'\n", argv[4]);
+               return -1;
+       }
+       pos += ETH_ALEN;
+
+       rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
+       if (rlen < 0)
+               return -1;
+       printf("OK\n");
+       return 0;
+}
+
+
+static char ** complete_inject(int s, const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       char **res = NULL;
+       int i, count;
+       u8 addr[ETH_ALEN];
+
+       switch (arg) {
+       case 1:
+               /* frame list */
+               count = sizeof(inject_frames) / sizeof(inject_frames[0]);
+               res = os_zalloc(count * sizeof(char *));
+               if (res == NULL)
+                       break;
+               for (i = 0; inject_frames[i].name; i++) {
+                       res[i] = os_strdup(inject_frames[i].name);
+                       if (res[i] == NULL)
+                               break;
+               }
+               break;
+       case 2:
+               res = os_zalloc(5 * sizeof(char *));
+               if (res == NULL)
+                       break;
+               res[0] = os_strdup("normal");
+               if (res[0] == NULL)
+                       break;
+               res[1] = os_strdup("protected");
+               if (res[1] == NULL)
+                       break;
+               res[2] = os_strdup("unprotected");
+               if (res[2] == NULL)
+                       break;
+               res[3] = os_strdup("incorrect");
+               if (res[3] == NULL)
+                       break;
+               break;
+       case 3:
+               res = os_zalloc(3 * sizeof(char *));
+               if (res == NULL)
+                       break;
+               res[0] = os_strdup("ap");
+               if (res[0] == NULL)
+                       break;
+               res[1] = os_strdup("sta");
+               if (res[1] == NULL)
+                       break;
+               break;
+       case 4:
+               res = get_bssid_list(s);
+               break;
+       case 5:
+               if (hwaddr_aton(&str[get_prev_arg_pos(str, pos)], addr) < 0)
+                       break;
+               res = get_sta_list(s, addr, 1);
+               break;
+       }
+
+       return res;
+}
+
+
+static u8 * add_hex(u8 *pos, u8 *end, const char *str)
+{
+       const char *s;
+       int val;
+
+       s = str;
+       while (*s) {
+               while (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n' ||
+                      *s == ':')
+                       s++;
+               if (*s == '\0')
+                       break;
+               if (*s == '#') {
+                       while (*s != '\0' && *s != '\r' && *s != '\n')
+                               s++;
+                       continue;
+               }
+
+               val = hex2byte(s);
+               if (val < 0) {
+                       printf("Invalid hex encoding '%s'\n", s);
+                       return NULL;
+               }
+               if (pos == end) {
+                       printf("Too long frame\n");
+                       return NULL;
+               }
+               *pos++ = val;
+               s += 2;
+       }
+
+       return pos;
+}
+
+
+static int cmd_send(int s, int argc, char *argv[])
+{
+       u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
+       u8 buf[WLANTEST_CTRL_MAX_CMD_LEN], *end, *pos, *len_pos;
+       int rlen;
+       enum wlantest_inject_protection prot;
+       int arg;
+
+       /* <prot> <raw frame as hex dump> */
+
+       if (argc < 2) {
+               printf("send needs two arguments: protected/unprotected, "
+                      "raw frame as hex dump\n");
+               return -1;
+       }
+
+       pos = buf;
+       end = buf + sizeof(buf);
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_SEND);
+       pos += 4;
+
+       if (os_strcasecmp(argv[0], "normal") == 0)
+               prot = WLANTEST_INJECT_NORMAL;
+       else if (os_strcasecmp(argv[0], "protected") == 0)
+               prot = WLANTEST_INJECT_PROTECTED;
+       else if (os_strcasecmp(argv[0], "unprotected") == 0)
+               prot = WLANTEST_INJECT_UNPROTECTED;
+       else if (os_strcasecmp(argv[0], "incorrect") == 0)
+               prot = WLANTEST_INJECT_INCORRECT_KEY;
+       else {
+               printf("Unknown protection type '%s'\n", argv[1]);
+               printf("Protection types: normal protected unprotected "
+                      "incorrect\n");
+               return -1;
+       }
+       pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_PROTECTION, prot);
+
+       WPA_PUT_BE32(pos, WLANTEST_ATTR_FRAME);
+       pos += 4;
+       len_pos = pos;
+       pos += 4;
+
+       for (arg = 1; pos && arg < argc; arg++)
+               pos = add_hex(pos, end, argv[arg]);
+       if (pos == NULL)
+               return -1;
+
+       WPA_PUT_BE32(len_pos, pos - len_pos - 4);
+
+       rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
+       if (rlen < 0)
+               return -1;
+       printf("OK\n");
+       return 0;
+}
+
+
+static char ** complete_send(int s, const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       char **res = NULL;
+
+       switch (arg) {
+       case 1:
+               res = os_zalloc(5 * sizeof(char *));
+               if (res == NULL)
+                       break;
+               res[0] = os_strdup("normal");
+               if (res[0] == NULL)
+                       break;
+               res[1] = os_strdup("protected");
+               if (res[1] == NULL)
+                       break;
+               res[2] = os_strdup("unprotected");
+               if (res[2] == NULL)
+                       break;
+               res[3] = os_strdup("incorrect");
+               if (res[3] == NULL)
+                       break;
+               break;
+       }
+
+       return res;
+}
+
+
+static int cmd_version(int s, int argc, char *argv[])
+{
+       u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
+       u8 buf[4];
+       char *version;
+       size_t len;
+       int rlen, i;
+
+       WPA_PUT_BE32(buf, WLANTEST_CTRL_VERSION);
+       rlen = cmd_send_and_recv(s, buf, sizeof(buf), resp, sizeof(resp));
+       if (rlen < 0)
+               return -1;
+
+       version = (char *) attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_VERSION,
+                                   &len);
+       if (version == NULL)
+               return -1;
+
+       for (i = 0; i < len; i++)
+               putchar(version[i]);
+       printf("\n");
+
+       return 0;
+}
+
+
+static int cmd_add_passphrase(int s, int argc, char *argv[])
+{
+       u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
+       u8 buf[100], *pos, *end;
+       size_t len;
+       int rlen;
+
+       if (argc < 1) {
+               printf("add_passphrase needs one argument: passphrase\n");
+               return -1;
+       }
+
+       len = os_strlen(argv[0]);
+       if (len < 8 || len > 63) {
+               printf("Invalid passphrase '%s'\n", argv[0]);
+               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_PASSPHRASE,
+                          argv[0]);
+       if (argc > 1) {
+               pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
+               if (hwaddr_aton(argv[1], pos) < 0) {
+                       printf("Invalid BSSID '%s'\n", argv[3]);
+                       return -1;
+               }
+               pos += ETH_ALEN;
+       }
+
+       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;
+};
+
+static const struct sta_infos sta_infos[] = {
+       { "proto", WLANTEST_STA_INFO_PROTO },
+       { "pairwise", WLANTEST_STA_INFO_PAIRWISE },
+       { "key_mgmt", WLANTEST_STA_INFO_KEY_MGMT },
+       { "rsn_capab", WLANTEST_STA_INFO_RSN_CAPAB },
+       { "state", WLANTEST_STA_INFO_STATE },
+       { NULL, 0 }
+};
+
+static int cmd_info_sta(int s, int argc, char *argv[])
+{
+       u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
+       u8 buf[100], *end, *pos;
+       int rlen, i;
+       size_t len;
+       char info[100];
+
+       if (argc != 3) {
+               printf("sta_info needs at three arguments: "
+                      "counter name, BSSID, and STA address\n");
+               return -1;
+       }
+
+       pos = buf;
+       end = buf + sizeof(buf);
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_INFO_STA);
+       pos += 4;
+
+       for (i = 0; sta_infos[i].name; i++) {
+               if (os_strcasecmp(sta_infos[i].name, argv[0]) == 0)
+                       break;
+       }
+       if (sta_infos[i].name == NULL) {
+               printf("Unknown STA info '%s'\n", argv[0]);
+               printf("Info fields:");
+               for (i = 0; sta_infos[i].name; i++)
+                       printf(" %s", sta_infos[i].name);
+               printf("\n");
+               return -1;
+       }
+
+       pos = attr_add_be32(pos, end, WLANTEST_ATTR_STA_INFO,
+                           sta_infos[i].num);
+       pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
+       if (hwaddr_aton(argv[1], pos) < 0) {
+               printf("Invalid BSSID '%s'\n", argv[1]);
+               return -1;
+       }
+       pos += ETH_ALEN;
+
+       pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN);
+       if (hwaddr_aton(argv[2], pos) < 0) {
+               printf("Invalid STA address '%s'\n", argv[2]);
+               return -1;
+       }
+       pos += ETH_ALEN;
+
+       rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
+       if (rlen < 0)
+               return -1;
+
+       pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_INFO, &len);
+       if (pos == NULL)
+               return -1;
+       if (len >= sizeof(info))
+               len = sizeof(info) - 1;
+       os_memcpy(info, pos, len);
+       info[len] = '\0';
+       printf("%s\n", info);
+       return 0;
+}
+
+
+static char ** complete_info_sta(int s, const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       char **res = NULL;
+       int i, count;
+       u8 addr[ETH_ALEN];
+
+       switch (arg) {
+       case 1:
+               /* counter list */
+               count = sizeof(sta_infos) / sizeof(sta_infos[0]);
+               res = os_zalloc(count * sizeof(char *));
+               if (res == NULL)
+                       return NULL;
+               for (i = 0; sta_infos[i].name; i++) {
+                       res[i] = os_strdup(sta_infos[i].name);
+                       if (res[i] == NULL)
+                               break;
+               }
+               break;
+       case 2:
+               res = get_bssid_list(s);
+               break;
+       case 3:
+               if (hwaddr_aton(&str[get_prev_arg_pos(str, pos)], addr) < 0)
+                       break;
+               res = get_sta_list(s, addr, 0);
+               break;
+       }
+
+       return res;
+}
+
+
+struct bss_infos {
+       const char *name;
+       enum wlantest_bss_info num;
+};
+
+static const struct bss_infos bss_infos[] = {
+       { "proto", WLANTEST_BSS_INFO_PROTO },
+       { "pairwise", WLANTEST_BSS_INFO_PAIRWISE },
+       { "group", WLANTEST_BSS_INFO_GROUP },
+       { "group_mgmt", WLANTEST_BSS_INFO_GROUP_MGMT },
+       { "key_mgmt", WLANTEST_BSS_INFO_KEY_MGMT },
+       { "rsn_capab", WLANTEST_BSS_INFO_RSN_CAPAB },
+       { NULL, 0 }
+};
+
+static int cmd_info_bss(int s, int argc, char *argv[])
+{
+       u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
+       u8 buf[100], *end, *pos;
+       int rlen, i;
+       size_t len;
+       char info[100];
+
+       if (argc != 2) {
+               printf("bss_info needs at two arguments: "
+                      "field name and BSSID\n");
+               return -1;
+       }
+
+       pos = buf;
+       end = buf + sizeof(buf);
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_INFO_BSS);
+       pos += 4;
+
+       for (i = 0; bss_infos[i].name; i++) {
+               if (os_strcasecmp(bss_infos[i].name, argv[0]) == 0)
+                       break;
+       }
+       if (bss_infos[i].name == NULL) {
+               printf("Unknown BSS info '%s'\n", argv[0]);
+               printf("Info fields:");
+               for (i = 0; bss_infos[i].name; i++)
+                       printf(" %s", bss_infos[i].name);
+               printf("\n");
+               return -1;
+       }
+
+       pos = attr_add_be32(pos, end, WLANTEST_ATTR_BSS_INFO,
+                           bss_infos[i].num);
+       pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
+       if (hwaddr_aton(argv[1], pos) < 0) {
+               printf("Invalid BSSID '%s'\n", argv[1]);
+               return -1;
+       }
+       pos += ETH_ALEN;
+
+       rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
+       if (rlen < 0)
+               return -1;
+
+       pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_INFO, &len);
+       if (pos == NULL)
+               return -1;
+       if (len >= sizeof(info))
+               len = sizeof(info) - 1;
+       os_memcpy(info, pos, len);
+       info[len] = '\0';
+       printf("%s\n", info);
+       return 0;
+}
+
+
+static char ** complete_info_bss(int s, const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       char **res = NULL;
+       int i, count;
+
+       switch (arg) {
+       case 1:
+               /* counter list */
+               count = sizeof(bss_infos) / sizeof(bss_infos[0]);
+               res = os_zalloc(count * sizeof(char *));
+               if (res == NULL)
+                       return NULL;
+               for (i = 0; bss_infos[i].name; i++) {
+                       res[i] = os_strdup(bss_infos[i].name);
+                       if (res[i] == NULL)
+                               break;
+               }
+               break;
+       case 2:
+               res = get_bssid_list(s);
+               break;
+       }
+
+       return res;
+}
+
+
+struct wlantest_cli_cmd {
+       const char *cmd;
+       int (*handler)(int s, int argc, char *argv[]);
+       const char *usage;
+       char ** (*complete)(int s, const char *str, int pos);
+};
+
+static const struct wlantest_cli_cmd wlantest_cli_commands[] = {
+       { "ping", cmd_ping, "= test connection to wlantest", NULL },
+       { "terminate", cmd_terminate, "= terminate wlantest", NULL },
+       { "list_bss", cmd_list_bss, "= get BSS list", NULL },
+       { "list_sta", cmd_list_sta, "<BSSID> = get STA list",
+         complete_list_sta },
+       { "flush", cmd_flush, "= drop all collected BSS data", NULL },
+       { "clear_sta_counters", cmd_clear_sta_counters,
+         "<BSSID> <STA> = clear STA counters", complete_clear_sta_counters },
+       { "clear_bss_counters", cmd_clear_bss_counters,
+         "<BSSID> = clear BSS counters", complete_clear_bss_counters },
+       { "get_sta_counter", cmd_get_sta_counter,
+         "<counter> <BSSID> <STA> = get STA counter value",
+         complete_get_sta_counter },
+       { "get_bss_counter", cmd_get_bss_counter,
+         "<counter> <BSSID> = get BSS counter value",
+         complete_get_bss_counter },
+       { "inject", cmd_inject,
+         "<frame> <prot> <sender> <BSSID> <STA/ff:ff:ff:ff:ff:ff>",
+         complete_inject },
+       { "send", cmd_send,
+         "<prot> <raw frame as hex dump>",
+         complete_send },
+       { "version", cmd_version, "= get wlantest version", NULL },
+       { "add_passphrase", cmd_add_passphrase,
+         "<passphrase> = add a known passphrase", NULL },
+       { "info_sta", cmd_info_sta,
+         "<field> <BSSID> <STA> = get STA information",
+         complete_info_sta },
+       { "info_bss", cmd_info_bss,
+         "<field> <BSSID> = get BSS information",
+         complete_info_bss },
+       { "clear_tdls_counters", cmd_clear_tdls_counters,
+         "<BSSID> <STA1> <STA2> = clear TDLS counters",
+         complete_clear_tdls_counters },
+       { "get_tdls_counter", cmd_get_tdls_counter,
+         "<counter> <BSSID> <STA1> <STA2> = get TDLS counter value",
+         complete_get_tdls_counter },
+       { "get_bss_counter", cmd_get_bss_counter,
+         "<counter> <BSSID> = get BSS counter value",
+         complete_get_bss_counter },
+       { NULL, NULL, NULL, NULL }
+};
+
+
+static int ctrl_command(int s, int argc, char *argv[])
+{
+       const struct wlantest_cli_cmd *cmd, *match = NULL;
+       int count = 0;
+       int ret = 0;
+
+       for (cmd = wlantest_cli_commands; cmd->cmd; cmd++) {
+               if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0)
+               {
+                       match = cmd;
+                       if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
+                               /* exact match */
+                               count = 1;
+                               break;
+                       }
+                       count++;
+               }
+       }
+
+       if (count > 1) {
+               printf("Ambiguous command '%s'; possible commands:", argv[0]);
+               for (cmd = wlantest_cli_commands; cmd->cmd; cmd++) {
+                       if (os_strncasecmp(cmd->cmd, argv[0],
+                                          os_strlen(argv[0])) == 0) {
+                               printf(" %s", cmd->cmd);
+                       }
+               }
+               printf("\n");
+               ret = 1;
+       } else if (count == 0) {
+               printf("Unknown command '%s'\n", argv[0]);
+               ret = 1;
+       } else {
+               ret = match->handler(s, argc - 1, &argv[1]);
+       }
+
+       return ret;
+}
+
+
+struct wlantest_cli {
+       int s;
+};
+
+
+#define max_args 10
+
+static int tokenize_cmd(char *cmd, char *argv[])
+{
+       char *pos;
+       int argc = 0;
+
+       pos = cmd;
+       for (;;) {
+               while (*pos == ' ')
+                       pos++;
+               if (*pos == '\0')
+                       break;
+               argv[argc] = pos;
+               argc++;
+               if (argc == max_args)
+                       break;
+               if (*pos == '"') {
+                       char *pos2 = os_strrchr(pos, '"');
+                       if (pos2)
+                               pos = pos2 + 1;
+               }
+               while (*pos != '\0' && *pos != ' ')
+                       pos++;
+               if (*pos == ' ')
+                       *pos++ = '\0';
+       }
+
+       return argc;
+}
+
+
+static void wlantest_cli_edit_cmd_cb(void *ctx, char *cmd)
+{
+       struct wlantest_cli *cli = ctx;
+       char *argv[max_args];
+       int argc;
+       argc = tokenize_cmd(cmd, argv);
+       if (argc) {
+               int ret = ctrl_command(cli->s, argc, argv);
+               if (ret < 0)
+                       printf("FAIL\n");
+       }
+}
+
+
+static void wlantest_cli_eloop_terminate(int sig, void *signal_ctx)
+{
+       eloop_terminate();
+}
+
+
+static void wlantest_cli_edit_eof_cb(void *ctx)
+{
+       eloop_terminate();
+}
+
+
+static char ** wlantest_cli_cmd_list(void)
+{
+       char **res;
+       int i, count;
+
+       count = sizeof(wlantest_cli_commands) /
+               sizeof(wlantest_cli_commands[0]);
+       res = os_zalloc(count * sizeof(char *));
+       if (res == NULL)
+               return NULL;
+
+       for (i = 0; wlantest_cli_commands[i].cmd; i++) {
+               res[i] = os_strdup(wlantest_cli_commands[i].cmd);
+               if (res[i] == NULL)
+                       break;
+       }
+
+       return res;
+}
+
+
+static char ** wlantest_cli_cmd_completion(struct wlantest_cli *cli,
+                                          const char *cmd, const char *str,
+                                          int pos)
+{
+       int i;
+
+       for (i = 0; wlantest_cli_commands[i].cmd; i++) {
+               const struct wlantest_cli_cmd *c = &wlantest_cli_commands[i];
+               if (os_strcasecmp(c->cmd, cmd) == 0) {
+                       edit_clear_line();
+                       printf("\r%s\n", c->usage);
+                       edit_redraw();
+                       if (c->complete)
+                               return c->complete(cli->s, str, pos);
+                       break;
+               }
+       }
+
+       return NULL;
+}
+
+
+static char ** wlantest_cli_edit_completion_cb(void *ctx, const char *str,
+                                              int pos)
+{
+       struct wlantest_cli *cli = ctx;
+       char **res;
+       const char *end;
+       char *cmd;
+
+       end = os_strchr(str, ' ');
+       if (end == NULL || str + pos < end)
+               return wlantest_cli_cmd_list();
+
+       cmd = os_malloc(pos + 1);
+       if (cmd == NULL)
+               return NULL;
+       os_memcpy(cmd, str, pos);
+       cmd[end - str] = '\0';
+       res = wlantest_cli_cmd_completion(cli, cmd, str, pos);
+       os_free(cmd);
+       return res;
+}
+
+
+static void wlantest_cli_interactive(int s)
+{
+       struct wlantest_cli cli;
+       char *home, *hfile = NULL;
+
+       if (eloop_init())
+               return;
+
+       home = getenv("HOME");
+       if (home) {
+               const char *fname = ".wlantest_cli_history";
+               int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
+               hfile = os_malloc(hfile_len);
+               if (hfile)
+                       os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
+       }
+
+       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);
+
+       eloop_run();
+
+       edit_deinit(hfile, NULL);
+       os_free(hfile);
+       eloop_destroy();
+}
+
+
+int main(int argc, char *argv[])
+{
+       int s;
+       struct sockaddr_un addr;
+       int ret = 0;
+
+       if (os_program_init())
+               return -1;
+
+       s = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+       if (s < 0) {
+               perror("socket");
+               return -1;
+       }
+
+       os_memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       os_strlcpy(addr.sun_path + 1, WLANTEST_SOCK_NAME,
+                  sizeof(addr.sun_path) - 1);
+       if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               perror("connect");
+               close(s);
+               return -1;
+       }
+
+       if (argc > 1) {
+               ret = ctrl_command(s, argc - 1, &argv[1]);
+               if (ret < 0)
+                       printf("FAIL\n");
+       } else {
+               wlantest_cli_interactive(s);
+       }
+
+       close(s);
+
+       os_program_deinit();
+
+       return ret;
+}
diff --git a/wlantest/wlantest_ctrl.h b/wlantest/wlantest_ctrl.h
new file mode 100644 (file)
index 0000000..9731bd6
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+#ifndef WLANTEST_CTRL_H
+#define WLANTEST_CTRL_H
+
+#define WLANTEST_SOCK_NAME "w1.fi.wlantest"
+#define WLANTEST_CTRL_MAX_CMD_LEN 1000
+#define WLANTEST_CTRL_MAX_RESP_LEN 1000
+
+enum wlantest_ctrl_cmd {
+       WLANTEST_CTRL_SUCCESS,
+       WLANTEST_CTRL_FAILURE,
+       WLANTEST_CTRL_INVALID_CMD,
+       WLANTEST_CTRL_UNKNOWN_CMD,
+       WLANTEST_CTRL_PING,
+       WLANTEST_CTRL_TERMINATE,
+       WLANTEST_CTRL_LIST_BSS,
+       WLANTEST_CTRL_LIST_STA,
+       WLANTEST_CTRL_FLUSH,
+       WLANTEST_CTRL_CLEAR_STA_COUNTERS,
+       WLANTEST_CTRL_CLEAR_BSS_COUNTERS,
+       WLANTEST_CTRL_GET_STA_COUNTER,
+       WLANTEST_CTRL_GET_BSS_COUNTER,
+       WLANTEST_CTRL_INJECT,
+       WLANTEST_CTRL_VERSION,
+       WLANTEST_CTRL_ADD_PASSPHRASE,
+       WLANTEST_CTRL_INFO_STA,
+       WLANTEST_CTRL_INFO_BSS,
+       WLANTEST_CTRL_SEND,
+       WLANTEST_CTRL_CLEAR_TDLS_COUNTERS,
+       WLANTEST_CTRL_GET_TDLS_COUNTER,
+};
+
+enum wlantest_ctrl_attr {
+       WLANTEST_ATTR_BSSID,
+       WLANTEST_ATTR_STA_ADDR,
+       WLANTEST_ATTR_STA_COUNTER,
+       WLANTEST_ATTR_BSS_COUNTER,
+       WLANTEST_ATTR_COUNTER,
+       WLANTEST_ATTR_INJECT_FRAME,
+       WLANTEST_ATTR_INJECT_SENDER_AP,
+       WLANTEST_ATTR_INJECT_PROTECTION,
+       WLANTEST_ATTR_VERSION,
+       WLANTEST_ATTR_PASSPHRASE,
+       WLANTEST_ATTR_STA_INFO,
+       WLANTEST_ATTR_BSS_INFO,
+       WLANTEST_ATTR_INFO,
+       WLANTEST_ATTR_FRAME,
+       WLANTEST_ATTR_TDLS_COUNTER,
+       WLANTEST_ATTR_STA2_ADDR,
+       WLANTEST_ATTR_WEPKEY,
+};
+
+enum wlantest_bss_counter {
+       WLANTEST_BSS_COUNTER_VALID_BIP_MMIE,
+       WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE,
+       WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE,
+       WLANTEST_BSS_COUNTER_BIP_DEAUTH,
+       WLANTEST_BSS_COUNTER_BIP_DISASSOC,
+       NUM_WLANTEST_BSS_COUNTER
+};
+
+enum wlantest_sta_counter {
+       WLANTEST_STA_COUNTER_AUTH_TX,
+       WLANTEST_STA_COUNTER_AUTH_RX,
+       WLANTEST_STA_COUNTER_ASSOCREQ_TX,
+       WLANTEST_STA_COUNTER_REASSOCREQ_TX,
+       WLANTEST_STA_COUNTER_PTK_LEARNED,
+       WLANTEST_STA_COUNTER_VALID_DEAUTH_TX,
+       WLANTEST_STA_COUNTER_VALID_DEAUTH_RX,
+       WLANTEST_STA_COUNTER_INVALID_DEAUTH_TX,
+       WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX,
+       WLANTEST_STA_COUNTER_VALID_DISASSOC_TX,
+       WLANTEST_STA_COUNTER_VALID_DISASSOC_RX,
+       WLANTEST_STA_COUNTER_INVALID_DISASSOC_TX,
+       WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX,
+       WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_TX,
+       WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_RX,
+       WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_TX,
+       WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_RX,
+       WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_TX,
+       WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_RX,
+       WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_TX,
+       WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_RX,
+       WLANTEST_STA_COUNTER_PING_OK,
+       WLANTEST_STA_COUNTER_ASSOCRESP_COMEBACK,
+       WLANTEST_STA_COUNTER_REASSOCRESP_COMEBACK,
+       WLANTEST_STA_COUNTER_PING_OK_FIRST_ASSOC,
+       WLANTEST_STA_COUNTER_VALID_DEAUTH_RX_ACK,
+       WLANTEST_STA_COUNTER_VALID_DISASSOC_RX_ACK,
+       WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX_ACK,
+       WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX_ACK,
+       WLANTEST_STA_COUNTER_DEAUTH_RX_ASLEEP,
+       WLANTEST_STA_COUNTER_DEAUTH_RX_AWAKE,
+       WLANTEST_STA_COUNTER_DISASSOC_RX_ASLEEP,
+       WLANTEST_STA_COUNTER_DISASSOC_RX_AWAKE,
+       WLANTEST_STA_COUNTER_PROT_DATA_TX,
+       WLANTEST_STA_COUNTER_DEAUTH_RX_RC6,
+       WLANTEST_STA_COUNTER_DEAUTH_RX_RC7,
+       WLANTEST_STA_COUNTER_DISASSOC_RX_RC6,
+       WLANTEST_STA_COUNTER_DISASSOC_RX_RC7,
+       NUM_WLANTEST_STA_COUNTER
+};
+
+enum wlantest_tdls_counter {
+       WLANTEST_TDLS_COUNTER_VALID_DIRECT_LINK,
+       WLANTEST_TDLS_COUNTER_INVALID_DIRECT_LINK,
+       WLANTEST_TDLS_COUNTER_VALID_AP_PATH,
+       WLANTEST_TDLS_COUNTER_INVALID_AP_PATH,
+       WLANTEST_TDLS_COUNTER_SETUP_REQ,
+       WLANTEST_TDLS_COUNTER_SETUP_RESP_OK,
+       WLANTEST_TDLS_COUNTER_SETUP_RESP_FAIL,
+       WLANTEST_TDLS_COUNTER_SETUP_CONF_OK,
+       WLANTEST_TDLS_COUNTER_SETUP_CONF_FAIL,
+       WLANTEST_TDLS_COUNTER_TEARDOWN,
+       NUM_WLANTEST_TDLS_COUNTER
+};
+
+enum wlantest_inject_frame {
+       WLANTEST_FRAME_AUTH,
+       WLANTEST_FRAME_ASSOCREQ,
+       WLANTEST_FRAME_REASSOCREQ,
+       WLANTEST_FRAME_DEAUTH,
+       WLANTEST_FRAME_DISASSOC,
+       WLANTEST_FRAME_SAQUERYREQ,
+};
+
+/**
+ * enum wlantest_inject_protection - WLANTEST_CTRL_INJECT protection
+ * @WLANTEST_INJECT_NORMAL: Use normal rules (protect if key is set)
+ * @WLANTEST_INJECT_PROTECTED: Force protection (fail if not possible)
+ * @WLANTEST_INJECT_UNPROTECTED: Force unprotected
+ * @WLANTEST_INJECT_INCORRECT_KEY: Force protection with incorrect key
+ */
+enum wlantest_inject_protection {
+       WLANTEST_INJECT_NORMAL,
+       WLANTEST_INJECT_PROTECTED,
+       WLANTEST_INJECT_UNPROTECTED,
+       WLANTEST_INJECT_INCORRECT_KEY,
+};
+
+enum wlantest_sta_info {
+       WLANTEST_STA_INFO_PROTO,
+       WLANTEST_STA_INFO_PAIRWISE,
+       WLANTEST_STA_INFO_KEY_MGMT,
+       WLANTEST_STA_INFO_RSN_CAPAB,
+       WLANTEST_STA_INFO_STATE,
+};
+
+enum wlantest_bss_info {
+       WLANTEST_BSS_INFO_PROTO,
+       WLANTEST_BSS_INFO_PAIRWISE,
+       WLANTEST_BSS_INFO_GROUP,
+       WLANTEST_BSS_INFO_GROUP_MGMT,
+       WLANTEST_BSS_INFO_KEY_MGMT,
+       WLANTEST_BSS_INFO_RSN_CAPAB,
+};
+
+#endif /* WLANTEST_CTRL_H */
diff --git a/wlantest/writepcap.c b/wlantest/writepcap.c
new file mode 100644 (file)
index 0000000..b59a1c2
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+#include "utils/includes.h"
+#include <pcap.h>
+#include <pcap-bpf.h>
+
+#include "utils/common.h"
+#include "wlantest.h"
+
+
+int write_pcap_init(struct wlantest *wt, const char *fname)
+{
+       wt->write_pcap = pcap_open_dead(DLT_IEEE802_11_RADIO, 4000);
+       if (wt->write_pcap == NULL)
+               return -1;
+       wt->write_pcap_dumper = pcap_dump_open(wt->write_pcap, fname);
+       if (wt->write_pcap_dumper == NULL) {
+               pcap_close(wt->write_pcap);
+               wt->write_pcap = NULL;
+               return -1;
+       }
+
+       wpa_printf(MSG_DEBUG, "Writing PCAP dump to '%s'", fname);
+
+       return 0;
+}
+
+
+void write_pcap_deinit(struct wlantest *wt)
+{
+       if (wt->write_pcap_dumper) {
+               pcap_dump_close(wt->write_pcap_dumper);
+               wt->write_pcap_dumper = NULL;
+       }
+       if (wt->write_pcap) {
+               pcap_close(wt->write_pcap);
+               wt->write_pcap = NULL;
+       }
+}
+
+
+void write_pcap_captured(struct wlantest *wt, const u8 *buf, size_t len)
+{
+       struct pcap_pkthdr h;
+
+       if (!wt->write_pcap_dumper)
+               return;
+
+       os_memset(&h, 0, sizeof(h));
+       gettimeofday(&wt->write_pcap_time, NULL);
+       h.ts = wt->write_pcap_time;
+       h.caplen = len;
+       h.len = len;
+       pcap_dump(wt->write_pcap_dumper, &h, buf);
+}
+
+
+void write_pcap_decrypted(struct wlantest *wt, const u8 *buf1, size_t len1,
+                         const u8 *buf2, size_t len2)
+{
+       struct pcap_pkthdr h;
+       u8 rtap[] = {
+               0x00 /* rev */,
+               0x00 /* pad */,
+               0x08, 0x00, /* header len */
+               0x00, 0x00, 0x00, 0x00 /* present flags */
+       };
+       u8 *buf;
+       size_t len;
+
+       if (!wt->write_pcap_dumper)
+               return;
+
+       os_memset(&h, 0, sizeof(h));
+       h.ts = wt->write_pcap_time;
+       len = sizeof(rtap) + len1 + len2;
+       buf = os_malloc(len);
+       if (buf == NULL)
+               return;
+       os_memcpy(buf, rtap, sizeof(rtap));
+       if (buf1) {
+               os_memcpy(buf + sizeof(rtap), buf1, len1);
+               buf[sizeof(rtap) + 1] &= ~0x40; /* Clear Protected flag */
+       }
+       if (buf2)
+               os_memcpy(buf + sizeof(rtap) + len1, buf2, len2);
+       h.caplen = len;
+       h.len = len;
+       pcap_dump(wt->write_pcap_dumper, &h, buf);
+       os_free(buf);
+}
diff --git a/wpa_supplicant/.gitignore b/wpa_supplicant/.gitignore
deleted file mode 100644 (file)
index e7e034c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-*.d
-.config
-eapol_test
-preauth_test
-wpa_cli
-wpa_passphrase
-wpa_supplicant
-wpa_priv
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
new file mode 100644 (file)
index 0000000..a656239
--- /dev/null
@@ -0,0 +1,1472 @@
+#
+# 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.
+#
+#
+
+LOCAL_PATH := $(call my-dir)
+PKG_CONFIG ?= pkg-config
+
+WPA_BUILD_SUPPLICANT := false
+ifneq ($(BOARD_WPA_SUPPLICANT_DRIVER),)
+  WPA_BUILD_SUPPLICANT := true
+  CONFIG_DRIVER_$(BOARD_WPA_SUPPLICANT_DRIVER) := y
+endif
+
+ifeq ($(WPA_BUILD_SUPPLICANT),true)
+
+include $(LOCAL_PATH)/.config
+
+# To ignore possible wrong network configurations
+L_CFLAGS = -DWPA_IGNORE_CONFIG_ERRORS
+
+# Set Android log name
+L_CFLAGS += -DANDROID_LOG_NAME=\"wpa_supplicant\"
+
+# 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\"
+
+# To force sizeof(enum) = 4
+ifeq ($(TARGET_ARCH),arm)
+L_CFLAGS += -mabi=aapcs-linux
+endif
+
+# To allow non-ASCII characters in SSID
+L_CFLAGS += -DWPA_UNICODE_SSID
+
+# OpenSSL is configured without engines on Android
+L_CFLAGS += -DOPENSSL_NO_ENGINE
+
+INCLUDES = $(LOCAL_PATH)
+INCLUDES += $(LOCAL_PATH)/src
+INCLUDES += $(LOCAL_PATH)/src/common
+# INCLUDES += $(LOCAL_PATH)/src/crypto # To force proper includes
+INCLUDES += $(LOCAL_PATH)/src/drivers
+INCLUDES += $(LOCAL_PATH)/src/eap_common
+INCLUDES += $(LOCAL_PATH)/src/eapol_supp
+INCLUDES += $(LOCAL_PATH)/src/eap_peer
+INCLUDES += $(LOCAL_PATH)/src/eap_server
+INCLUDES += $(LOCAL_PATH)/src/hlr_auc_gw
+INCLUDES += $(LOCAL_PATH)/src/l2_packet
+INCLUDES += $(LOCAL_PATH)/src/radius
+INCLUDES += $(LOCAL_PATH)/src/rsn_supp
+INCLUDES += $(LOCAL_PATH)/src/tls
+INCLUDES += $(LOCAL_PATH)/src/utils
+INCLUDES += $(LOCAL_PATH)/src/wps
+INCLUDES += external/openssl/include
+INCLUDES += frameworks/base/cmds/keystore
+ifdef CONFIG_DRIVER_NL80211
+INCLUDES += external/libnl-headers
+endif
+
+OBJS = config.c
+OBJS += notify.c
+OBJS += bss.c
+OBJS += eap_register.c
+OBJS += src/utils/common.c
+OBJS += src/utils/wpa_debug.c
+OBJS += src/utils/wpabuf.c
+OBJS_p = wpa_passphrase.c
+OBJS_p += src/utils/common.c
+OBJS_p += src/utils/wpa_debug.c
+OBJS_p += src/utils/wpabuf.c
+OBJS_c = wpa_cli.c src/common/wpa_ctrl.c
+OBJS_c += src/utils/wpa_debug.c
+OBJS_c += src/utils/common.c
+OBJS_d =
+OBJS_priv =
+
+ifndef CONFIG_OS
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_OS=win32
+else
+CONFIG_OS=unix
+endif
+endif
+
+ifeq ($(CONFIG_OS), internal)
+L_CFLAGS += -DOS_NO_C_LIB_DEFINES
+endif
+
+OBJS += src/utils/os_$(CONFIG_OS).c
+OBJS_p += src/utils/os_$(CONFIG_OS).c
+OBJS_c += src/utils/os_$(CONFIG_OS).c
+
+ifdef CONFIG_WPA_TRACE
+L_CFLAGS += -DWPA_TRACE
+OBJS += src/utils/trace.c
+OBJS_p += src/utils/trace.c
+OBJS_c += src/utils/trace.c
+LDFLAGS += -rdynamic
+L_CFLAGS += -funwind-tables
+ifdef CONFIG_WPA_TRACE_BFD
+L_CFLAGS += -DWPA_TRACE_BFD
+LIBS += -lbfd
+LIBS_p += -lbfd
+LIBS_c += -lbfd
+endif
+endif
+
+ifndef CONFIG_ELOOP
+CONFIG_ELOOP=eloop
+endif
+OBJS += src/utils/$(CONFIG_ELOOP).c
+OBJS_c += src/utils/$(CONFIG_ELOOP).c
+
+
+ifdef CONFIG_EAPOL_TEST
+L_CFLAGS += -Werror -DEAPOL_TEST
+endif
+
+ifndef CONFIG_BACKEND
+CONFIG_BACKEND=file
+endif
+
+ifeq ($(CONFIG_BACKEND), file)
+OBJS += config_file.c
+ifndef CONFIG_NO_CONFIG_BLOBS
+NEED_BASE64=y
+endif
+L_CFLAGS += -DCONFIG_BACKEND_FILE
+endif
+
+ifeq ($(CONFIG_BACKEND), winreg)
+OBJS += config_winreg.c
+endif
+
+ifeq ($(CONFIG_BACKEND), none)
+OBJS += config_none.c
+endif
+
+ifdef CONFIG_NO_CONFIG_WRITE
+L_CFLAGS += -DCONFIG_NO_CONFIG_WRITE
+endif
+
+ifdef CONFIG_NO_CONFIG_BLOBS
+L_CFLAGS += -DCONFIG_NO_CONFIG_BLOBS
+endif
+
+ifdef CONFIG_NO_SCAN_PROCESSING
+L_CFLAGS += -DCONFIG_NO_SCAN_PROCESSING
+endif
+
+ifdef CONFIG_IEEE80211W
+L_CFLAGS += -DCONFIG_IEEE80211W
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_IEEE80211R
+L_CFLAGS += -DCONFIG_IEEE80211R
+OBJS += src/rsn_supp/wpa_ft.c
+NEED_80211_COMMON=y
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_TDLS
+L_CFLAGS += -DCONFIG_TDLS
+OBJS += src/rsn_supp/tdls.c
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_TDLS_TESTING
+L_CFLAGS += -DCONFIG_TDLS_TESTING
+endif
+
+ifdef CONFIG_PEERKEY
+L_CFLAGS += -DCONFIG_PEERKEY
+endif
+
+ifndef CONFIG_NO_WPA
+OBJS += src/rsn_supp/wpa.c
+OBJS += src/rsn_supp/preauth.c
+OBJS += src/rsn_supp/pmksa_cache.c
+OBJS += src/rsn_supp/peerkey.c
+OBJS += src/rsn_supp/wpa_ie.c
+OBJS += src/common/wpa_common.c
+NEED_AES=y
+NEED_SHA1=y
+NEED_MD5=y
+NEED_RC4=y
+else
+L_CFLAGS += -DCONFIG_NO_WPA -DCONFIG_NO_WPA2
+endif
+
+ifdef CONFIG_IBSS_RSN
+NEED_RSN_AUTHENTICATOR=y
+L_CFLAGS += -DCONFIG_IBSS_RSN
+OBJS += ibss_rsn.c
+endif
+
+ifdef CONFIG_P2P
+OBJS += p2p_supplicant.c
+OBJS += src/p2p/p2p.c
+OBJS += src/p2p/p2p_utils.c
+OBJS += src/p2p/p2p_parse.c
+OBJS += src/p2p/p2p_build.c
+OBJS += src/p2p/p2p_go_neg.c
+OBJS += src/p2p/p2p_sd.c
+OBJS += src/p2p/p2p_pd.c
+OBJS += src/p2p/p2p_invitation.c
+OBJS += src/p2p/p2p_dev_disc.c
+OBJS += src/p2p/p2p_group.c
+OBJS += src/ap/p2p_hostapd.c
+L_CFLAGS += -DCONFIG_P2P
+NEED_GAS=y
+NEED_OFFCHANNEL=y
+NEED_80211_COMMON=y
+CONFIG_WPS=y
+CONFIG_AP=y
+ifdef CONFIG_P2P_STRICT
+L_CFLAGS += -DCONFIG_P2P_STRICT
+endif
+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
+OBJS_d += $(DRV_BOTH_OBJS)
+L_CFLAGS += $(DRV_BOTH_CFLAGS)
+LDFLAGS += $(DRV_BOTH_LDFLAGS)
+LIBS += $(DRV_BOTH_LIBS)
+else
+NEED_AP_MLME=
+OBJS_d += $(DRV_WPA_OBJS)
+L_CFLAGS += $(DRV_WPA_CFLAGS)
+LDFLAGS += $(DRV_WPA_LDFLAGS)
+LIBS += $(DRV_WPA_LIBS)
+endif
+
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=linux
+endif
+
+OBJS_l2 += src/l2_packet/l2_packet_$(CONFIG_L2_PACKET).c
+
+ifeq ($(CONFIG_L2_PACKET), pcap)
+ifdef CONFIG_WINPCAP
+L_CFLAGS += -DCONFIG_WINPCAP
+LIBS += -lwpcap -lpacket
+LIBS_w += -lwpcap
+else
+LIBS += -ldnet -lpcap
+endif
+endif
+
+ifeq ($(CONFIG_L2_PACKET), winpcap)
+LIBS += -lwpcap -lpacket
+LIBS_w += -lwpcap
+endif
+
+ifeq ($(CONFIG_L2_PACKET), freebsd)
+LIBS += -lpcap
+endif
+
+ifdef CONFIG_EAP_TLS
+# EAP-TLS
+ifeq ($(CONFIG_EAP_TLS), dyn)
+L_CFLAGS += -DEAP_TLS_DYNAMIC
+EAPDYN += src/eap_peer/eap_tls.so
+else
+L_CFLAGS += -DEAP_TLS
+OBJS += src/eap_peer/eap_tls.c
+OBJS_h += src/eap_server/eap_server_tls.c
+endif
+TLS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_PEAP
+# EAP-PEAP
+ifeq ($(CONFIG_EAP_PEAP), dyn)
+L_CFLAGS += -DEAP_PEAP_DYNAMIC
+EAPDYN += src/eap_peer/eap_peap.so
+else
+L_CFLAGS += -DEAP_PEAP
+OBJS += src/eap_peer/eap_peap.c
+OBJS += src/eap_common/eap_peap_common.c
+OBJS_h += src/eap_server/eap_server_peap.c
+endif
+TLS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_TTLS
+# EAP-TTLS
+ifeq ($(CONFIG_EAP_TTLS), dyn)
+L_CFLAGS += -DEAP_TTLS_DYNAMIC
+EAPDYN += src/eap_peer/eap_ttls.so
+else
+L_CFLAGS += -DEAP_TTLS
+OBJS += src/eap_peer/eap_ttls.c
+OBJS_h += src/eap_server/eap_server_ttls.c
+endif
+MS_FUNCS=y
+TLS_FUNCS=y
+CHAP=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_MD5
+# EAP-MD5
+ifeq ($(CONFIG_EAP_MD5), dyn)
+L_CFLAGS += -DEAP_MD5_DYNAMIC
+EAPDYN += src/eap_peer/eap_md5.so
+else
+L_CFLAGS += -DEAP_MD5
+OBJS += src/eap_peer/eap_md5.c
+OBJS_h += src/eap_server/eap_server_md5.c
+endif
+CHAP=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+# backwards compatibility for old spelling
+ifdef CONFIG_MSCHAPV2
+ifndef CONFIG_EAP_MSCHAPV2
+CONFIG_EAP_MSCHAPV2=y
+endif
+endif
+
+ifdef CONFIG_EAP_MSCHAPV2
+# EAP-MSCHAPv2
+ifeq ($(CONFIG_EAP_MSCHAPV2), dyn)
+L_CFLAGS += -DEAP_MSCHAPv2_DYNAMIC
+EAPDYN += src/eap_peer/eap_mschapv2.so
+EAPDYN += src/eap_peer/mschapv2.so
+else
+L_CFLAGS += -DEAP_MSCHAPv2
+OBJS += src/eap_peer/eap_mschapv2.c
+OBJS += src/eap_peer/mschapv2.c
+OBJS_h += src/eap_server/eap_server_mschapv2.c
+endif
+MS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_GTC
+# EAP-GTC
+ifeq ($(CONFIG_EAP_GTC), dyn)
+L_CFLAGS += -DEAP_GTC_DYNAMIC
+EAPDYN += src/eap_peer/eap_gtc.so
+else
+L_CFLAGS += -DEAP_GTC
+OBJS += src/eap_peer/eap_gtc.c
+OBJS_h += src/eap_server/eap_server_gtc.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_OTP
+# EAP-OTP
+ifeq ($(CONFIG_EAP_OTP), dyn)
+L_CFLAGS += -DEAP_OTP_DYNAMIC
+EAPDYN += src/eap_peer/eap_otp.so
+else
+L_CFLAGS += -DEAP_OTP
+OBJS += src/eap_peer/eap_otp.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_SIM
+# EAP-SIM
+ifeq ($(CONFIG_EAP_SIM), dyn)
+L_CFLAGS += -DEAP_SIM_DYNAMIC
+EAPDYN += src/eap_peer/eap_sim.so
+else
+L_CFLAGS += -DEAP_SIM
+OBJS += src/eap_peer/eap_sim.c
+OBJS_h += src/eap_server/eap_server_sim.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+CONFIG_EAP_SIM_COMMON=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_LEAP
+# EAP-LEAP
+ifeq ($(CONFIG_EAP_LEAP), dyn)
+L_CFLAGS += -DEAP_LEAP_DYNAMIC
+EAPDYN += src/eap_peer/eap_leap.so
+else
+L_CFLAGS += -DEAP_LEAP
+OBJS += src/eap_peer/eap_leap.c
+endif
+MS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_PSK
+# EAP-PSK
+ifeq ($(CONFIG_EAP_PSK), dyn)
+L_CFLAGS += -DEAP_PSK_DYNAMIC
+EAPDYN += src/eap_peer/eap_psk.so
+else
+L_CFLAGS += -DEAP_PSK
+OBJS += src/eap_peer/eap_psk.c src/eap_common/eap_psk_common.c
+OBJS_h += src/eap_server/eap_server_psk.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+NEED_AES=y
+NEED_AES_OMAC1=y
+NEED_AES_ENCBLOCK=y
+NEED_AES_EAX=y
+endif
+
+ifdef CONFIG_EAP_AKA
+# EAP-AKA
+ifeq ($(CONFIG_EAP_AKA), dyn)
+L_CFLAGS += -DEAP_AKA_DYNAMIC
+EAPDYN += src/eap_peer/eap_aka.so
+else
+L_CFLAGS += -DEAP_AKA
+OBJS += src/eap_peer/eap_aka.c
+OBJS_h += src/eap_server/eap_server_aka.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+CONFIG_EAP_SIM_COMMON=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_AKA_PRIME
+# EAP-AKA'
+ifeq ($(CONFIG_EAP_AKA_PRIME), dyn)
+L_CFLAGS += -DEAP_AKA_PRIME_DYNAMIC
+else
+L_CFLAGS += -DEAP_AKA_PRIME
+endif
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_EAP_SIM_COMMON
+OBJS += src/eap_common/eap_sim_common.c
+OBJS_h += src/eap_server/eap_sim_db.c
+NEED_AES=y
+NEED_FIPS186_2_PRF=y
+endif
+
+ifdef CONFIG_EAP_FAST
+# EAP-FAST
+ifeq ($(CONFIG_EAP_FAST), dyn)
+L_CFLAGS += -DEAP_FAST_DYNAMIC
+EAPDYN += src/eap_peer/eap_fast.so
+EAPDYN += src/eap_common/eap_fast_common.c
+else
+L_CFLAGS += -DEAP_FAST
+OBJS += src/eap_peer/eap_fast.c src/eap_peer/eap_fast_pac.c
+OBJS += src/eap_common/eap_fast_common.c
+OBJS_h += src/eap_server/eap_server_fast.c
+endif
+TLS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+NEED_T_PRF=y
+endif
+
+ifdef CONFIG_EAP_PAX
+# EAP-PAX
+ifeq ($(CONFIG_EAP_PAX), dyn)
+L_CFLAGS += -DEAP_PAX_DYNAMIC
+EAPDYN += src/eap_peer/eap_pax.so
+else
+L_CFLAGS += -DEAP_PAX
+OBJS += src/eap_peer/eap_pax.c src/eap_common/eap_pax_common.c
+OBJS_h += src/eap_server/eap_server_pax.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_SAKE
+# EAP-SAKE
+ifeq ($(CONFIG_EAP_SAKE), dyn)
+L_CFLAGS += -DEAP_SAKE_DYNAMIC
+EAPDYN += src/eap_peer/eap_sake.so
+else
+L_CFLAGS += -DEAP_SAKE
+OBJS += src/eap_peer/eap_sake.c src/eap_common/eap_sake_common.c
+OBJS_h += src/eap_server/eap_server_sake.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_GPSK
+# EAP-GPSK
+ifeq ($(CONFIG_EAP_GPSK), dyn)
+L_CFLAGS += -DEAP_GPSK_DYNAMIC
+EAPDYN += src/eap_peer/eap_gpsk.so
+else
+L_CFLAGS += -DEAP_GPSK
+OBJS += src/eap_peer/eap_gpsk.c src/eap_common/eap_gpsk_common.c
+OBJS_h += src/eap_server/eap_server_gpsk.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+ifdef CONFIG_EAP_GPSK_SHA256
+L_CFLAGS += -DEAP_GPSK_SHA256
+endif
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_EAP_PWD
+L_CFLAGS += -DEAP_PWD
+OBJS += src/eap_peer/eap_pwd.c src/eap_common/eap_pwd_common.c
+OBJS_h += src/eap_server/eap_pwd.c
+CONFIG_IEEE8021X_EAPOL=y
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_WPS
+ifdef CONFIG_WPS2
+L_CFLAGS += -DCONFIG_WPS2
+endif
+
+# EAP-WSC
+L_CFLAGS += -DCONFIG_WPS -DEAP_WSC
+OBJS += wps_supplicant.c
+OBJS += src/utils/uuid.c
+OBJS += src/eap_peer/eap_wsc.c src/eap_common/eap_wsc_common.c
+OBJS += src/wps/wps.c
+OBJS += src/wps/wps_common.c
+OBJS += src/wps/wps_attr_parse.c
+OBJS += src/wps/wps_attr_build.c
+OBJS += src/wps/wps_attr_process.c
+OBJS += src/wps/wps_dev_attr.c
+OBJS += src/wps/wps_enrollee.c
+OBJS += src/wps/wps_registrar.c
+OBJS_h += src/eap_server/eap_server_wsc.c
+CONFIG_IEEE8021X_EAPOL=y
+NEED_DH_GROUPS=y
+NEED_SHA256=y
+NEED_BASE64=y
+NEED_80211_COMMON=y
+NEED_AES_CBC=y
+NEED_MODEXP=y
+
+ifdef CONFIG_WPS_UFD
+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
+L_CFLAGS += -DCONFIG_WPS_OOB
+endif
+
+ifdef CONFIG_WPS_ER
+CONFIG_WPS_UPNP=y
+L_CFLAGS += -DCONFIG_WPS_ER
+OBJS += src/wps/wps_er.c
+OBJS += src/wps/wps_er_ssdp.c
+endif
+
+ifdef CONFIG_WPS_UPNP
+L_CFLAGS += -DCONFIG_WPS_UPNP
+OBJS += src/wps/wps_upnp.c
+OBJS += src/wps/wps_upnp_ssdp.c
+OBJS += src/wps/wps_upnp_web.c
+OBJS += src/wps/wps_upnp_event.c
+OBJS += src/wps/wps_upnp_ap.c
+OBJS += src/wps/upnp_xml.c
+OBJS += src/wps/httpread.c
+OBJS += src/wps/http_client.c
+OBJS += src/wps/http_server.c
+endif
+
+ifdef CONFIG_WPS_STRICT
+L_CFLAGS += -DCONFIG_WPS_STRICT
+OBJS += src/wps/wps_validate.c
+endif
+
+ifdef CONFIG_WPS_TESTING
+L_CFLAGS += -DCONFIG_WPS_TESTING
+endif
+
+ifdef CONFIG_WPS_REG_DISABLE_OPEN
+L_CFLAGS += -DCONFIG_WPS_REG_DISABLE_OPEN
+endif
+
+endif
+
+ifdef CONFIG_EAP_IKEV2
+# EAP-IKEv2
+ifeq ($(CONFIG_EAP_IKEV2), dyn)
+L_CFLAGS += -DEAP_IKEV2_DYNAMIC
+EAPDYN += src/eap_peer/eap_ikev2.so src/eap_peer/ikev2.c
+EAPDYN += src/eap_common/eap_ikev2_common.c src/eap_common/ikev2_common.c
+else
+L_CFLAGS += -DEAP_IKEV2
+OBJS += src/eap_peer/eap_ikev2.c src/eap_peer/ikev2.c
+OBJS += src/eap_common/eap_ikev2_common.c src/eap_common/ikev2_common.c
+OBJS_h += src/eap_server/eap_server_ikev2.c
+OBJS_h += src/eap_server/ikev2.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+NEED_MODEXP=y
+NEED_CIPHER=y
+endif
+
+ifdef CONFIG_EAP_VENDOR_TEST
+ifeq ($(CONFIG_EAP_VENDOR_TEST), dyn)
+L_CFLAGS += -DEAP_VENDOR_TEST_DYNAMIC
+EAPDYN += src/eap_peer/eap_vendor_test.so
+else
+L_CFLAGS += -DEAP_VENDOR_TEST
+OBJS += src/eap_peer/eap_vendor_test.c
+OBJS_h += src/eap_server/eap_server_vendor_test.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_TNC
+# EAP-TNC
+L_CFLAGS += -DEAP_TNC
+OBJS += src/eap_peer/eap_tnc.c
+OBJS += src/eap_peer/tncc.c
+OBJS_h += src/eap_server/eap_server_tnc.c
+OBJS_h += src/eap_server/tncs.c
+NEED_BASE64=y
+ifndef CONFIG_NATIVE_WINDOWS
+ifndef CONFIG_DRIVER_BSD
+LIBS += -ldl
+endif
+endif
+endif
+
+ifdef CONFIG_IEEE8021X_EAPOL
+# IEEE 802.1X/EAPOL state machines (e.g., for RADIUS authentication)
+L_CFLAGS += -DIEEE8021X_EAPOL
+OBJS += src/eapol_supp/eapol_supp_sm.c
+OBJS += src/eap_peer/eap.c src/eap_peer/eap_methods.c
+NEED_EAP_COMMON=y
+ifdef CONFIG_DYNAMIC_EAP_METHODS
+L_CFLAGS += -DCONFIG_DYNAMIC_EAP_METHODS
+LIBS += -ldl -rdynamic
+endif
+endif
+
+ifdef CONFIG_AP
+NEED_80211_COMMON=y
+NEED_EAP_COMMON=y
+NEED_RSN_AUTHENTICATOR=y
+L_CFLAGS += -DCONFIG_AP
+OBJS += ap.c
+L_CFLAGS += -DCONFIG_NO_RADIUS
+L_CFLAGS += -DCONFIG_NO_ACCOUNTING
+L_CFLAGS += -DCONFIG_NO_VLAN
+OBJS += src/ap/hostapd.c
+OBJS += src/ap/wpa_auth_glue.c
+OBJS += src/ap/utils.c
+OBJS += src/ap/authsrv.c
+OBJS += src/ap/ap_config.c
+OBJS += src/utils/ip_addr.c
+OBJS += src/ap/sta_info.c
+OBJS += src/ap/tkip_countermeasures.c
+OBJS += src/ap/ap_mlme.c
+OBJS += src/ap/ieee802_1x.c
+OBJS += src/eapol_auth/eapol_auth_sm.c
+OBJS += src/ap/ieee802_11_auth.c
+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
+ifdef CONFIG_IEEE80211N
+OBJS += src/ap/ieee802_11_ht.c
+endif
+ifdef CONFIG_CTRL_IFACE
+OBJS += src/ap/ctrl_iface_ap.c
+endif
+
+L_CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY
+OBJS += src/eap_server/eap_server.c
+OBJS += src/eap_server/eap_server_identity.c
+OBJS += src/eap_server/eap_server_methods.c
+
+ifdef CONFIG_IEEE80211N
+L_CFLAGS += -DCONFIG_IEEE80211N
+endif
+
+ifdef NEED_AP_MLME
+OBJS += src/ap/wmm.c
+OBJS += src/ap/ap_list.c
+OBJS += src/ap/ieee802_11.c
+OBJS += src/ap/hw_features.c
+L_CFLAGS += -DNEED_AP_MLME
+endif
+ifdef CONFIG_WPS
+L_CFLAGS += -DEAP_SERVER_WSC
+OBJS += src/ap/wps_hostapd.c
+OBJS += src/eap_server/eap_server_wsc.c
+endif
+endif
+
+ifdef NEED_RSN_AUTHENTICATOR
+L_CFLAGS += -DCONFIG_NO_RADIUS
+NEED_AES_WRAP=y
+OBJS += src/ap/wpa_auth.c
+OBJS += src/ap/wpa_auth_ie.c
+OBJS += src/ap/pmksa_cache_auth.c
+ifdef CONFIG_IEEE80211R
+OBJS += src/ap/wpa_auth_ft.c
+endif
+ifdef CONFIG_PEERKEY
+OBJS += src/ap/peerkey_auth.c
+endif
+endif
+
+ifdef CONFIG_EAP_SERVER
+L_CFLAGS += -DEAP_SERVER
+OBJS_h += src/eap_server/eap_server.c
+OBJS_h += src/eap_server/eap_server_identity.c
+OBJS_h += src/eap_server/eap_server_methods.c
+endif
+
+ifdef CONFIG_RADIUS_CLIENT
+OBJS_h += src/utils/ip_addr.c
+OBJS_h += src/radius/radius.c
+OBJS_h += src/radius/radius_client.c
+endif
+
+ifdef CONFIG_AUTHENTICATOR
+OBJS_h += src/eapol_auth/eapol_auth_sm.c
+OBJS_h += src/ap/ieee802_1x.c
+endif
+
+ifdef CONFIG_WPA_AUTHENTICATOR
+OBJS_h += src/ap/wpa_auth.c
+OBJS_h += src/ap/wpa_auth_ie.c
+OBJS_h += src/ap/pmksa_cache_auth.c
+ifdef CONFIG_IEEE80211R
+OBJS_h += src/ap/wpa_auth_ft.c
+endif
+ifdef CONFIG_PEERKEY
+OBJS_h += src/ap/peerkey_auth.c
+endif
+endif
+
+ifdef CONFIG_PCSC
+# PC/SC interface for smartcards (USIM, GSM SIM)
+L_CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC
+OBJS += src/utils/pcsc_funcs.c
+# -lpthread may not be needed depending on how pcsc-lite was configured
+ifdef CONFIG_NATIVE_WINDOWS
+#Once MinGW gets support for WinScard, -lwinscard could be used instead of the
+#dynamic symbol loading that is now used in pcsc_funcs.c
+#LIBS += -lwinscard
+else
+LIBS += -lpcsclite -lpthread
+endif
+endif
+
+ifdef CONFIG_SIM_SIMULATOR
+L_CFLAGS += -DCONFIG_SIM_SIMULATOR
+NEED_MILENAGE=y
+endif
+
+ifdef CONFIG_USIM_SIMULATOR
+L_CFLAGS += -DCONFIG_USIM_SIMULATOR
+NEED_MILENAGE=y
+endif
+
+ifdef NEED_MILENAGE
+OBJS += src/crypto/milenage.c
+NEED_AES_ENCBLOCK=y
+endif
+
+ifdef CONFIG_PKCS12
+L_CFLAGS += -DPKCS12_FUNCS
+endif
+
+ifdef CONFIG_SMARTCARD
+L_CFLAGS += -DCONFIG_SMARTCARD
+endif
+
+ifdef MS_FUNCS
+OBJS += src/crypto/ms_funcs.c
+NEED_DES=y
+NEED_MD4=y
+endif
+
+ifdef CHAP
+OBJS += src/eap_common/chap.c
+endif
+
+ifdef TLS_FUNCS
+NEED_DES=y
+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST)
+OBJS += src/eap_peer/eap_tls_common.c
+OBJS_h += src/eap_server/eap_server_tls_common.c
+NEED_TLS_PRF=y
+endif
+
+ifndef CONFIG_TLS
+CONFIG_TLS=openssl
+endif
+
+ifdef CONFIG_TLSV11
+L_CFLAGS += -DCONFIG_TLSV11
+endif
+
+ifeq ($(CONFIG_TLS), openssl)
+ifdef TLS_FUNCS
+L_CFLAGS += -DEAP_TLS_OPENSSL
+OBJS += src/crypto/tls_openssl.c
+LIBS += -lssl
+endif
+OBJS += src/crypto/crypto_openssl.c
+OBJS_p += src/crypto/crypto_openssl.c
+ifdef NEED_FIPS186_2_PRF
+OBJS += src/crypto/fips_prf_openssl.c
+endif
+LIBS += -lcrypto
+LIBS_p += -lcrypto
+endif
+
+ifeq ($(CONFIG_TLS), gnutls)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_gnutls.c
+LIBS += -lgnutls -lgpg-error
+endif
+OBJS += src/crypto/crypto_gnutls.c
+OBJS_p += src/crypto/crypto_gnutls.c
+ifdef NEED_FIPS186_2_PRF
+OBJS += src/crypto/fips_prf_gnutls.c
+endif
+LIBS += -lgcrypt
+LIBS_p += -lgcrypt
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), schannel)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_schannel.c
+endif
+OBJS += src/crypto/crypto_cryptoapi.c
+OBJS_p += src/crypto/crypto_cryptoapi.c
+ifdef NEED_FIPS186_2_PRF
+OBJS += src/crypto/fips_prf_cryptoapi.c
+endif
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), nss)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_nss.c
+LIBS += -lssl3
+endif
+OBJS += src/crypto/crypto_nss.c
+OBJS_p += src/crypto/crypto_nss.c
+ifdef NEED_FIPS186_2_PRF
+OBJS += src/crypto/fips_prf_nss.c
+endif
+LIBS += -lnss3
+LIBS_p += -lnss3
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), internal)
+ifndef CONFIG_CRYPTO
+CONFIG_CRYPTO=internal
+endif
+ifdef TLS_FUNCS
+OBJS += src/crypto/crypto_internal-rsa.c
+OBJS += src/crypto/tls_internal.c
+OBJS += src/tls/tlsv1_common.c
+OBJS += src/tls/tlsv1_record.c
+OBJS += src/tls/tlsv1_cred.c
+OBJS += src/tls/tlsv1_client.c
+OBJS += src/tls/tlsv1_client_write.c
+OBJS += src/tls/tlsv1_client_read.c
+OBJS += src/tls/asn1.c
+OBJS += src/tls/rsa.c
+OBJS += src/tls/x509v3.c
+OBJS += src/tls/pkcs1.c
+OBJS += src/tls/pkcs5.c
+OBJS += src/tls/pkcs8.c
+NEED_SHA256=y
+NEED_BASE64=y
+NEED_TLS_PRF=y
+NEED_MODEXP=y
+NEED_CIPHER=y
+L_CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
+endif
+ifdef NEED_CIPHER
+NEED_DES=y
+OBJS += src/crypto/crypto_internal-cipher.c
+endif
+ifdef NEED_MODEXP
+OBJS += src/crypto/crypto_internal-modexp.c
+OBJS += src/tls/bignum.c
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+OBJS += src/crypto/crypto_libtomcrypt.c
+OBJS_p += src/crypto/crypto_libtomcrypt.c
+LIBS += -ltomcrypt -ltfm
+LIBS_p += -ltomcrypt -ltfm
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+OBJS += src/crypto/crypto_internal.c
+OBJS_p += src/crypto/crypto_internal.c
+NEED_AES_ENC=y
+L_CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+ifdef CONFIG_INTERNAL_LIBTOMMATH
+L_CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST
+L_CFLAGS += -DLTM_FAST
+endif
+else
+LIBS += -ltommath
+LIBS_p += -ltommath
+endif
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_DES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+OBJS += src/crypto/crypto_cryptoapi.c
+OBJS_p += src/crypto/crypto_cryptoapi.c
+L_CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+ifeq ($(CONFIG_TLS), none)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_none.c
+L_CFLAGS += -DEAP_TLS_NONE
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+endif
+OBJS += src/crypto/crypto_none.c
+OBJS_p += src/crypto/crypto_none.c
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+
+ifdef TLS_FUNCS
+ifdef CONFIG_SMARTCARD
+ifndef CONFIG_NATIVE_WINDOWS
+ifneq ($(CONFIG_L2_PACKET), freebsd)
+LIBS += -ldl
+endif
+endif
+endif
+endif
+
+ifndef TLS_FUNCS
+OBJS += src/crypto/tls_none.c
+ifeq ($(CONFIG_TLS), internal)
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+AESOBJS = # none so far (see below)
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += src/crypto/aes-internal.c src/crypto/aes-internal-dec.c
+endif
+
+AESOBJS += src/crypto/aes-unwrap.c
+ifdef NEED_AES_EAX
+AESOBJS += src/crypto/aes-eax.c
+NEED_AES_CTR=y
+endif
+ifdef NEED_AES_CTR
+AESOBJS += src/crypto/aes-ctr.c
+endif
+ifdef NEED_AES_ENCBLOCK
+AESOBJS += src/crypto/aes-encblock.c
+endif
+ifdef NEED_AES_OMAC1
+NEED_AES_ENC=y
+AESOBJS += src/crypto/aes-omac1.c
+endif
+ifdef NEED_AES_WRAP
+NEED_AES_ENC=y
+AESOBJS += src/crypto/aes-wrap.c
+endif
+ifdef NEED_AES_CBC
+NEED_AES_ENC=y
+AESOBJS += src/crypto/aes-cbc.c
+endif
+ifdef NEED_AES_ENC
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += src/crypto/aes-internal-enc.c
+endif
+endif
+ifdef NEED_AES
+OBJS += $(AESOBJS)
+endif
+
+SHA1OBJS =
+ifdef NEED_SHA1
+SHA1OBJS += src/crypto/sha1.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
+ifdef CONFIG_NO_WPA_PASSPHRASE
+L_CFLAGS += -DCONFIG_NO_PBKDF2
+else
+SHA1OBJS += src/crypto/sha1-pbkdf2.c
+endif
+ifdef NEED_T_PRF
+SHA1OBJS += src/crypto/sha1-tprf.c
+endif
+ifdef NEED_TLS_PRF
+SHA1OBJS += src/crypto/sha1-tlsprf.c
+endif
+endif
+
+MD5OBJS = src/crypto/md5.c
+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
+
+ifdef NEED_MD4
+ifdef CONFIG_INTERNAL_MD4
+OBJS += src/crypto/md4-internal.c
+endif
+endif
+
+DESOBJS = # none needed when not internal
+ifdef NEED_DES
+ifdef CONFIG_INTERNAL_DES
+DESOBJS += src/crypto/des-internal.c
+endif
+endif
+
+ifdef NEED_RC4
+ifdef CONFIG_INTERNAL_RC4
+OBJS += src/crypto/rc4.c
+endif
+endif
+
+SHA256OBJS = # none by default
+ifdef NEED_SHA256
+L_CFLAGS += -DCONFIG_SHA256
+SHA256OBJS += src/crypto/sha256.c
+ifdef CONFIG_INTERNAL_SHA256
+SHA256OBJS += src/crypto/sha256-internal.c
+endif
+OBJS += $(SHA256OBJS)
+endif
+
+ifdef NEED_DH_GROUPS
+OBJS += src/crypto/dh_groups.c
+endif
+ifdef NEED_DH_GROUPS_ALL
+L_CFLAGS += -DALL_DH_GROUPS
+endif
+ifdef CONFIG_INTERNAL_DH_GROUP5
+ifdef NEED_DH_GROUPS
+OBJS += src/crypto/dh_group5.c
+endif
+endif
+
+ifdef CONFIG_NO_RANDOM_POOL
+L_CFLAGS += -DCONFIG_NO_RANDOM_POOL
+else
+OBJS += src/crypto/random.c
+endif
+
+ifdef CONFIG_CTRL_IFACE
+ifeq ($(CONFIG_CTRL_IFACE), y)
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_CTRL_IFACE=named_pipe
+else
+CONFIG_CTRL_IFACE=unix
+endif
+endif
+L_CFLAGS += -DCONFIG_CTRL_IFACE
+ifeq ($(CONFIG_CTRL_IFACE), unix)
+L_CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
+endif
+ifeq ($(CONFIG_CTRL_IFACE), udp)
+L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+endif
+ifeq ($(CONFIG_CTRL_IFACE), named_pipe)
+L_CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE
+endif
+OBJS += ctrl_iface.c ctrl_iface_$(CONFIG_CTRL_IFACE).c
+endif
+
+ifdef CONFIG_CTRL_IFACE_DBUS
+DBUS=y
+DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS -DDBUS_API_SUBJECT_TO_CHANGE
+DBUS_OBJS += dbus/dbus_old.c dbus/dbus_old_handlers.c
+ifdef CONFIG_WPS
+DBUS_OBJS += dbus/dbus_old_handlers_wps.c
+endif
+DBUS_OBJS += dbus/dbus_dict_helpers.c
+ifndef DBUS_LIBS
+DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1)
+endif
+ifndef DBUS_INCLUDE
+DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1)
+endif
+dbus_version=$(subst ., ,$(shell $(PKG_CONFIG) --modversion dbus-1))
+DBUS_VERSION_MAJOR=$(word 1,$(dbus_version))
+DBUS_VERSION_MINOR=$(word 2,$(dbus_version))
+ifeq ($(DBUS_VERSION_MAJOR),)
+DBUS_VERSION_MAJOR=0
+endif
+ifeq ($(DBUS_VERSION_MINOR),)
+DBUS_VERSION_MINOR=0
+endif
+DBUS_INCLUDE += -DDBUS_VERSION_MAJOR=$(DBUS_VERSION_MAJOR)
+DBUS_INCLUDE += -DDBUS_VERSION_MINOR=$(DBUS_VERSION_MINOR)
+DBUS_CFLAGS += $(DBUS_INCLUDE)
+endif
+
+ifdef CONFIG_CTRL_IFACE_DBUS_NEW
+DBUS=y
+DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW
+DBUS_OBJS ?= dbus/dbus_dict_helpers.c
+DBUS_OBJS += dbus/dbus_new_helpers.c
+DBUS_OBJS += dbus/dbus_new.c dbus/dbus_new_handlers.c
+ifdef CONFIG_WPS
+DBUS_OBJS += dbus/dbus_new_handlers_wps.c
+endif
+ifdef CONFIG_P2P
+DBUS_OBJS += dbus/dbus_new_handlers_p2p.c
+endif
+ifndef DBUS_LIBS
+DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1)
+endif
+ifndef DBUS_INCLUDE
+DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1)
+endif
+ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
+DBUS_OBJS += dbus/dbus_new_introspect.c
+DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
+endif
+DBUS_CFLAGS += $(DBUS_INCLUDE)
+endif
+
+ifdef DBUS
+DBUS_CFLAGS += -DCONFIG_DBUS
+DBUS_OBJS += dbus/dbus_common.c
+endif
+
+OBJS += $(DBUS_OBJS)
+L_CFLAGS += $(DBUS_CFLAGS)
+LIBS += $(DBUS_LIBS)
+
+ifdef CONFIG_READLINE
+OBJS_c += src/utils/edit_readline.c
+LIBS_c += -lncurses -lreadline
+else
+ifdef CONFIG_WPA_CLI_EDIT
+OBJS_c += src/utils/edit.c
+else
+OBJS_c += src/utils/edit_simple.c
+endif
+endif
+
+ifdef CONFIG_NATIVE_WINDOWS
+L_CFLAGS += -DCONFIG_NATIVE_WINDOWS
+LIBS += -lws2_32 -lgdi32 -lcrypt32
+LIBS_c += -lws2_32
+LIBS_p += -lws2_32 -lgdi32
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+LIBS_p += -lcrypt32
+endif
+endif
+
+ifdef CONFIG_NO_STDOUT_DEBUG
+L_CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
+ifndef CONFIG_CTRL_IFACE
+L_CFLAGS += -DCONFIG_NO_WPA_MSG
+endif
+endif
+
+ifdef CONFIG_ANDROID_LOG
+L_CFLAGS += -DCONFIG_ANDROID_LOG
+endif
+
+ifdef CONFIG_IPV6
+# for eapol_test only
+L_CFLAGS += -DCONFIG_IPV6
+endif
+
+ifdef NEED_BASE64
+OBJS += src/utils/base64.c
+endif
+
+ifdef NEED_SME
+NEED_80211_COMMON=y
+OBJS += sme.c
+L_CFLAGS += -DCONFIG_SME
+endif
+
+ifdef NEED_80211_COMMON
+OBJS += src/common/ieee802_11_common.c
+endif
+
+ifdef NEED_EAP_COMMON
+OBJS += src/eap_common/eap_common.c
+endif
+
+ifndef CONFIG_MAIN
+CONFIG_MAIN=main
+endif
+
+ifdef CONFIG_DEBUG_SYSLOG
+L_CFLAGS += -DCONFIG_DEBUG_SYSLOG
+ifdef CONFIG_DEBUG_SYSLOG_FACILITY
+L_CFLAGS += -DLOG_HOSTAPD="$(CONFIG_DEBUG_SYSLOG_FACILITY)"
+endif
+endif
+
+ifdef CONFIG_DEBUG_FILE
+L_CFLAGS += -DCONFIG_DEBUG_FILE
+endif
+
+ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
+L_CFLAGS += -DCONFIG_DELAYED_MIC_ERROR_REPORT
+endif
+
+ifdef CONFIG_FIPS
+L_CFLAGS += -DCONFIG_FIPS
+endif
+
+OBJS += $(SHA1OBJS) $(DESOBJS)
+
+OBJS_p += $(SHA1OBJS)
+
+ifdef CONFIG_BGSCAN_SIMPLE
+L_CFLAGS += -DCONFIG_BGSCAN_SIMPLE
+OBJS += bgscan_simple.c
+NEED_BGSCAN=y
+endif
+
+ifdef CONFIG_BGSCAN_LEARN
+L_CFLAGS += -DCONFIG_BGSCAN_LEARN
+OBJS += bgscan_learn.c
+NEED_BGSCAN=y
+endif
+
+ifdef NEED_BGSCAN
+L_CFLAGS += -DCONFIG_BGSCAN
+OBJS += bgscan.c
+endif
+
+ifdef NEED_GAS
+OBJS += ../src/common/gas.c
+OBJS += gas_query.c
+L_CFLAGS += -DCONFIG_GAS
+NEED_OFFCHANNEL=y
+endif
+
+ifdef NEED_OFFCHANNEL
+OBJS += offchannel.c
+L_CFLAGS += -DCONFIG_OFFCHANNEL
+endif
+
+OBJS += src/drivers/driver_common.c
+
+OBJS_wpa_rm := ctrl_iface.c ctrl_iface_unix.c
+OBJS_wpa := $(filter-out $(OBJS_wpa_rm),$(OBJS)) $(OBJS_h) tests/test_wpa.c
+ifdef CONFIG_AUTHENTICATOR
+OBJS_wpa += tests/link_test.c
+endif
+OBJS_wpa += $(OBJS_l2)
+OBJS += wpa_supplicant.c events.c blacklist.c wpas_glue.c scan.c
+OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.c
+OBJS_t += src/radius/radius_client.c
+OBJS_t += src/radius/radius.c
+ifndef CONFIG_AP
+OBJS_t += src/utils/ip_addr.c
+endif
+OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.c
+OBJS += $(CONFIG_MAIN).c
+
+ifdef CONFIG_PRIVSEP
+OBJS_priv += $(OBJS_d) src/drivers/drivers.c
+OBJS_priv += $(OBJS_l2)
+OBJS_priv += src/utils/os_$(CONFIG_OS).c
+OBJS_priv += src/utils/$(CONFIG_ELOOP).c
+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_TEST
+OBJS_priv += $(SHA1OBJS)
+OBJS_priv += $(MD5OBJS)
+ifeq ($(CONFIG_TLS), openssl)
+OBJS_priv += src/crypto/crypto_openssl.c
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+OBJS_priv += src/crypto/crypto_gnutls.c
+endif
+ifeq ($(CONFIG_TLS), nss)
+OBJS_priv += src/crypto/crypto_nss.c
+endif
+ifeq ($(CONFIG_TLS), internal)
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+OBJS_priv += src/crypto/crypto_libtomcrypt.c
+else
+OBJS_priv += src/crypto/crypto_internal.c
+endif
+endif
+endif # CONFIG_DRIVER_TEST
+OBJS += src/l2_packet/l2_packet_privsep.c
+OBJS += src/drivers/driver_privsep.c
+EXTRA_progs += wpa_priv
+else
+OBJS += $(OBJS_d) src/drivers/drivers.c
+OBJS += $(OBJS_l2)
+endif
+
+ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+L_CFLAGS += -DCONFIG_NDIS_EVENTS_INTEGRATED
+OBJS += src/drivers/ndis_events.c
+EXTRALIBS += -loleaut32 -lole32 -luuid
+ifdef PLATFORMSDKLIB
+EXTRALIBS += $(PLATFORMSDKLIB)/WbemUuid.Lib
+else
+EXTRALIBS += WbemUuid.Lib
+endif
+endif
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+########################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := wpa_cli
+LOCAL_MODULE_TAGS := debug
+LOCAL_SHARED_LIBRARIES := libc libcutils
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_SRC_FILES := $(OBJS_c)
+LOCAL_C_INCLUDES := $(INCLUDES)
+include $(BUILD_EXECUTABLE)
+
+########################
+include $(CLEAR_VARS)
+LOCAL_MODULE := wpa_supplicant
+ifdef CONFIG_DRIVER_CUSTOM
+LOCAL_STATIC_LIBRARIES := libCustomWifi
+endif
+ifneq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB),)
+LOCAL_STATIC_LIBRARIES += $(BOARD_WPA_SUPPLICANT_PRIVATE_LIB)
+endif
+LOCAL_SHARED_LIBRARIES := libc libcutils
+ifeq ($(CONFIG_TLS), openssl)
+LOCAL_SHARED_LIBRARIES += libcrypto libssl
+endif
+ifdef CONFIG_DRIVER_NL80211
+LOCAL_STATIC_LIBRARIES += libnl_2
+endif
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_SRC_FILES := $(OBJS)
+LOCAL_C_INCLUDES := $(INCLUDES)
+include $(BUILD_EXECUTABLE)
+
+########################
+#
+#include $(CLEAR_VARS)
+#LOCAL_MODULE := eapol_test
+#ifdef CONFIG_DRIVER_CUSTOM
+#LOCAL_STATIC_LIBRARIES := libCustomWifi
+#endif
+#LOCAL_SHARED_LIBRARIES := libc libcrypto libssl
+#LOCAL_CFLAGS := $(L_CFLAGS)
+#LOCAL_SRC_FILES := $(OBJS_t)
+#LOCAL_C_INCLUDES := $(INCLUDES)
+#include $(BUILD_EXECUTABLE)
+#
+########################
+#
+#local_target_dir := $(TARGET_OUT)/etc/wifi
+#
+#include $(CLEAR_VARS)
+#LOCAL_MODULE := wpa_supplicant.conf
+#LOCAL_MODULE_TAGS := user
+#LOCAL_MODULE_CLASS := ETC
+#LOCAL_MODULE_PATH := $(local_target_dir)
+#LOCAL_SRC_FILES := $(LOCAL_MODULE)
+#include $(BUILD_PREBUILT)
+#
+########################
+
+endif # ifeq ($(WPA_BUILD_SUPPLICANT),true)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE = libwpa_client
+LOCAL_CFLAGS = $(L_CFLAGS)
+LOCAL_SRC_FILES = src/common/wpa_ctrl.c src/utils/os_$(CONFIG_OS).c
+LOCAL_C_INCLUDES = $(INCLUDES)
+LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_COPY_HEADERS_TO := libwpa_client
+LOCAL_COPY_HEADERS := src/common/wpa_ctrl.h
+include $(BUILD_SHARED_LIBRARY)
index 56046c3..06119c6 100644 (file)
@@ -1,24 +1,5 @@
 ChangeLog for wpa_supplicant
 
-2010-09-07 - v0.7.3
-       * fixed fallback from failed PMKSA caching into full EAP authentication
-         [Bug 355]
-       * fixed issue with early D-Bus signals during initialization
-       * fixed X.509 name handling in internal TLS
-       * fixed WPS ER to use corrent Enrollee MAC Address in Credential
-       * fixed scanning routines ot improve AP selection for WPS
-       * added WPS workaround for open networks
-       * fixed WPS Diffie-Hellman derivation to use correct public key length
-       * fixed wpa_supplicant AP mode operations to ignore Supplicant and
-         scan result events
-       * improved SME operations with nl80211
-       * fixed WPS ER event_id handling in some cases
-       * fixed some issues with bgscan simple to avoid unnecessary scans
-       * fixed issue with l2_packet_ndis overlapped writes corrupting stack
-         [Bug 328]
-       * updated WinPcap to the latest stable version 4.1.2 in Windows
-         installer
-
 2010-04-18 - v0.7.2
        * nl80211: fixed number of issues with roaming
        * avoid unnecessary roaming if multiple APs with similar signal
index 1d25623..cab9dfd 100644 (file)
@@ -6,13 +6,28 @@ ifndef CFLAGS
 CFLAGS = -MMD -O2 -Wall -g
 endif
 
-export LIBDIR ?= /usr/local/lib/
-export BINDIR ?= /usr/local/sbin/
+export LIBDIR ?= /usr/lib
+export BINDIR ?= /usr/sbin
+PKG_CONFIG ?= pkg-config
 
 CFLAGS += -I../src
 CFLAGS += -I../src/utils
 
-ALL=wpa_supplicant wpa_passphrase wpa_cli
+-include .config
+
+ALL=wpa_supplicant wpa_cli
+
+ifndef CONFIG_NO_WPA_PASSPHRASE
+ALL += wpa_passphrase
+endif
+
+ALL += systemd/wpa_supplicant.service
+ALL += systemd/wpa_supplicant@.service
+ALL += systemd/wpa_supplicant-nl80211@.service
+ALL += systemd/wpa_supplicant-wired@.service
+ALL += dbus/fi.epitest.hostap.WPASupplicant.service
+ALL += dbus/fi.w1.wpa_supplicant1.service
+
 
 all: verify_config $(ALL) dynamic_eap_methods
 
@@ -50,8 +65,11 @@ OBJS_p += ../src/utils/common.o
 OBJS_p += ../src/utils/wpa_debug.o
 OBJS_p += ../src/utils/wpabuf.o
 OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o
+OBJS_c += ../src/utils/wpa_debug.o
+OBJS_c += ../src/utils/common.o
 
--include .config
+
+CFLAGS += -DTIZEN_EXT
 
 ifndef CONFIG_OS
 ifdef CONFIG_NATIVE_WINDOWS
@@ -74,7 +92,7 @@ CFLAGS += -DWPA_TRACE
 OBJS += ../src/utils/trace.o
 OBJS_p += ../src/utils/trace.o
 OBJS_c += ../src/utils/trace.o
-OBJS_c += ../src/utils/wpa_debug.o
+OBJS_priv += ../src/utils/trace.o
 LDFLAGS += -rdynamic
 CFLAGS += -funwind-tables
 ifdef CONFIG_WPA_TRACE_BFD
@@ -89,6 +107,7 @@ ifndef CONFIG_ELOOP
 CONFIG_ELOOP=eloop
 endif
 OBJS += ../src/utils/$(CONFIG_ELOOP).o
+OBJS_c += ../src/utils/$(CONFIG_ELOOP).o
 
 
 ifdef CONFIG_EAPOL_TEST
@@ -141,6 +160,17 @@ NEED_SHA256=y
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_TDLS
+CFLAGS += -DCONFIG_TDLS
+OBJS += ../src/rsn_supp/tdls.o
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_TDLS_TESTING
+CFLAGS += -DCONFIG_TDLS_TESTING
+endif
+
 ifdef CONFIG_PEERKEY
 CFLAGS += -DCONFIG_PEERKEY
 endif
@@ -166,6 +196,36 @@ CFLAGS += -DCONFIG_IBSS_RSN
 OBJS += ibss_rsn.o
 endif
 
+ifdef CONFIG_P2P
+OBJS += p2p_supplicant.o
+OBJS += ../src/p2p/p2p.o
+OBJS += ../src/p2p/p2p_utils.o
+OBJS += ../src/p2p/p2p_parse.o
+OBJS += ../src/p2p/p2p_build.o
+OBJS += ../src/p2p/p2p_go_neg.o
+OBJS += ../src/p2p/p2p_sd.o
+OBJS += ../src/p2p/p2p_pd.o
+OBJS += ../src/p2p/p2p_invitation.o
+OBJS += ../src/p2p/p2p_dev_disc.o
+OBJS += ../src/p2p/p2p_group.o
+OBJS += ../src/ap/p2p_hostapd.o
+CFLAGS += -DCONFIG_P2P
+NEED_GAS=y
+NEED_OFFCHANNEL=y
+NEED_80211_COMMON=y
+CONFIG_WPS=y
+CONFIG_AP=y
+ifdef CONFIG_P2P_STRICT
+CFLAGS += -DCONFIG_P2P_STRICT
+endif
+endif
+
+ifdef CONFIG_INTERWORKING
+OBJS += interworking.o
+CFLAGS += -DCONFIG_INTERWORKING
+NEED_GAS=y
+endif
+
 ifdef CONFIG_NO_WPA2
 CFLAGS += -DCONFIG_NO_WPA2
 endif
@@ -454,7 +514,19 @@ NEED_SHA256=y
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_EAP_PWD
+CFLAGS += -DEAP_PWD
+OBJS += ../src/eap_peer/eap_pwd.o ../src/eap_common/eap_pwd_common.o
+OBJS_h += ../src/eap_server/eap_pwd.o
+CONFIG_IEEE8021X_EAPOL=y
+NEED_SHA256=y
+endif
+
 ifdef CONFIG_WPS
+ifdef CONFIG_WPS2
+CFLAGS += -DCONFIG_WPS2
+endif
+
 # EAP-WSC
 CFLAGS += -DCONFIG_WPS -DEAP_WSC
 OBJS += wps_supplicant.o
@@ -522,6 +594,19 @@ OBJS += ../src/wps/http_client.o
 OBJS += ../src/wps/http_server.o
 endif
 
+ifdef CONFIG_WPS_STRICT
+CFLAGS += -DCONFIG_WPS_STRICT
+OBJS += ../src/wps/wps_validate.o
+endif
+
+ifdef CONFIG_WPS_TESTING
+CFLAGS += -DCONFIG_WPS_TESTING
+endif
+
+ifdef CONFIG_WPS_REG_DISABLE_OPEN
+CFLAGS += -DCONFIG_WPS_REG_DISABLE_OPEN
+endif
+
 endif
 
 ifdef CONFIG_EAP_IKEV2
@@ -604,8 +689,13 @@ OBJS += ../src/ap/ap_mlme.o
 OBJS += ../src/ap/ieee802_1x.o
 OBJS += ../src/eapol_auth/eapol_auth_sm.o
 OBJS += ../src/ap/ieee802_11_auth.o
+OBJS += ../src/ap/ieee802_11_shared.o
 OBJS += ../src/ap/drv_callbacks.o
 OBJS += ../src/ap/ap_drv_ops.o
+OBJS += ../src/ap/beacon.o
+ifdef CONFIG_IEEE80211N
+OBJS += ../src/ap/ieee802_11_ht.o
+endif
 ifdef CONFIG_CTRL_IFACE
 OBJS += ../src/ap/ctrl_iface_ap.o
 endif
@@ -620,14 +710,10 @@ CFLAGS += -DCONFIG_IEEE80211N
 endif
 
 ifdef NEED_AP_MLME
-OBJS += ../src/ap/beacon.o
 OBJS += ../src/ap/wmm.o
 OBJS += ../src/ap/ap_list.o
 OBJS += ../src/ap/ieee802_11.o
 OBJS += ../src/ap/hw_features.o
-ifdef CONFIG_IEEE80211N
-OBJS += ../src/ap/ieee802_11_ht.o
-endif
 CFLAGS += -DNEED_AP_MLME
 endif
 ifdef CONFIG_WPS
@@ -707,6 +793,7 @@ endif
 
 ifdef NEED_MILENAGE
 OBJS += ../src/crypto/milenage.o
+NEED_AES_ENCBLOCK=y
 endif
 
 ifdef CONFIG_PKCS12
@@ -739,6 +826,15 @@ ifndef CONFIG_TLS
 CONFIG_TLS=openssl
 endif
 
+ifdef CONFIG_TLSV11
+CFLAGS += -DCONFIG_TLSV11
+endif
+
+ifdef CONFIG_TLSV12
+CFLAGS += -DCONFIG_TLSV12
+NEED_SHA256=y
+endif
+
 ifeq ($(CONFIG_TLS), openssl)
 ifdef TLS_FUNCS
 CFLAGS += -DEAP_TLS_OPENSSL
@@ -758,10 +854,6 @@ ifeq ($(CONFIG_TLS), gnutls)
 ifdef TLS_FUNCS
 OBJS += ../src/crypto/tls_gnutls.o
 LIBS += -lgnutls -lgpg-error
-ifdef CONFIG_GNUTLS_EXTRA
-CFLAGS += -DCONFIG_GNUTLS_EXTRA
-LIBS += -lgnutls-extra
-endif
 endif
 OBJS += ../src/crypto/crypto_gnutls.o
 OBJS_p += ../src/crypto/crypto_gnutls.o
@@ -827,6 +919,9 @@ OBJS += ../src/tls/pkcs8.o
 NEED_SHA256=y
 NEED_BASE64=y
 NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
 NEED_MODEXP=y
 NEED_CIPHER=y
 CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
@@ -959,7 +1054,9 @@ ifdef NEED_FIPS186_2_PRF
 SHA1OBJS += ../src/crypto/fips_prf_internal.o
 endif
 endif
-ifndef CONFIG_NO_WPA_PASSPHRASE
+ifdef CONFIG_NO_WPA_PASSPHRASE
+CFLAGS += -DCONFIG_NO_PBKDF2
+else
 SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
 endif
 ifdef NEED_T_PRF
@@ -1008,6 +1105,9 @@ SHA256OBJS += ../src/crypto/sha256.o
 ifdef CONFIG_INTERNAL_SHA256
 SHA256OBJS += ../src/crypto/sha256-internal.o
 endif
+ifdef NEED_TLS_PRF_SHA256
+SHA256OBJS += ../src/crypto/sha256-tlsprf.o
+endif
 OBJS += $(SHA256OBJS)
 endif
 
@@ -1023,6 +1123,12 @@ OBJS += ../src/crypto/dh_group5.o
 endif
 endif
 
+ifdef CONFIG_NO_RANDOM_POOL
+CFLAGS += -DCONFIG_NO_RANDOM_POOL
+else
+OBJS += ../src/crypto/random.o
+endif
+
 ifdef CONFIG_CTRL_IFACE
 ifeq ($(CONFIG_CTRL_IFACE), y)
 ifdef CONFIG_NATIVE_WINDOWS
@@ -1053,12 +1159,12 @@ DBUS_OBJS += dbus/dbus_old_handlers_wps.o
 endif
 DBUS_OBJS += dbus/dbus_dict_helpers.o
 ifndef DBUS_LIBS
-DBUS_LIBS := $(shell pkg-config --libs dbus-1)
+DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1)
 endif
 ifndef DBUS_INCLUDE
-DBUS_INCLUDE := $(shell pkg-config --cflags dbus-1)
+DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1)
 endif
-dbus_version=$(subst ., ,$(shell pkg-config --modversion dbus-1))
+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),)
@@ -1081,11 +1187,14 @@ DBUS_OBJS += dbus/dbus_new.o dbus/dbus_new_handlers.o
 ifdef CONFIG_WPS
 DBUS_OBJS += dbus/dbus_new_handlers_wps.o
 endif
+ifdef CONFIG_P2P
+DBUS_OBJS += dbus/dbus_new_handlers_p2p.o
+endif
 ifndef DBUS_LIBS
-DBUS_LIBS := $(shell pkg-config --libs dbus-1)
+DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1)
 endif
 ifndef DBUS_INCLUDE
-DBUS_INCLUDE := $(shell pkg-config --cflags dbus-1)
+DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1)
 endif
 ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
 DBUS_OBJS += dbus/dbus_new_introspect.o
@@ -1104,8 +1213,14 @@ CFLAGS += $(DBUS_CFLAGS)
 LIBS += $(DBUS_LIBS)
 
 ifdef CONFIG_READLINE
-CFLAGS += -DCONFIG_READLINE
+OBJS_c += ../src/utils/edit_readline.o
 LIBS_c += -lncurses -lreadline
+else
+ifdef CONFIG_WPA_CLI_EDIT
+OBJS_c += ../src/utils/edit.o
+else
+OBJS_c += ../src/utils/edit_simple.o
+endif
 endif
 
 ifdef CONFIG_NATIVE_WINDOWS
@@ -1140,12 +1255,6 @@ OBJS += sme.o
 CFLAGS += -DCONFIG_SME
 endif
 
-ifdef CONFIG_CLIENT_MLME
-OBJS += mlme.o
-CFLAGS += -DCONFIG_CLIENT_MLME
-NEED_80211_COMMON=y
-endif
-
 ifdef NEED_80211_COMMON
 OBJS += ../src/common/ieee802_11_common.o
 endif
@@ -1160,6 +1269,9 @@ endif
 
 ifdef CONFIG_DEBUG_SYSLOG
 CFLAGS += -DCONFIG_DEBUG_SYSLOG
+ifdef CONFIG_DEBUG_SYSLOG_FACILITY
+CFLAGS += -DLOG_HOSTAPD="$(CONFIG_DEBUG_SYSLOG_FACILITY)"
+endif
 endif
 
 ifdef CONFIG_DEBUG_FILE
@@ -1177,6 +1289,7 @@ endif
 OBJS += $(SHA1OBJS) $(DESOBJS)
 
 OBJS_p += $(SHA1OBJS)
+OBJS_p += $(SHA256OBJS)
 
 ifdef CONFIG_BGSCAN_SIMPLE
 CFLAGS += -DCONFIG_BGSCAN_SIMPLE
@@ -1184,12 +1297,32 @@ OBJS += bgscan_simple.o
 NEED_BGSCAN=y
 endif
 
+ifdef CONFIG_BGSCAN_LEARN
+CFLAGS += -DCONFIG_BGSCAN_LEARN
+OBJS += bgscan_learn.o
+NEED_BGSCAN=y
+endif
+
 ifdef NEED_BGSCAN
 CFLAGS += -DCONFIG_BGSCAN
 OBJS += bgscan.o
 endif
 
-OBJS_wpa_rm := ctrl_iface.o mlme.o ctrl_iface_unix.o
+ifdef NEED_GAS
+OBJS += ../src/common/gas.o
+OBJS += gas_query.o
+CFLAGS += -DCONFIG_GAS
+NEED_OFFCHANNEL=y
+endif
+
+ifdef NEED_OFFCHANNEL
+OBJS += offchannel.o
+CFLAGS += -DCONFIG_OFFCHANNEL
+endif
+
+OBJS += ../src/drivers/driver_common.o
+
+OBJS_wpa_rm := ctrl_iface.o ctrl_iface_unix.o
 OBJS_wpa := $(filter-out $(OBJS_wpa_rm),$(OBJS)) $(OBJS_h) tests/test_wpa.o
 ifdef CONFIG_AUTHENTICATOR
 OBJS_wpa += tests/link_test.o
@@ -1214,6 +1347,9 @@ OBJS_priv += ../src/utils/common.o
 OBJS_priv += ../src/utils/wpa_debug.o
 OBJS_priv += ../src/utils/wpabuf.o
 OBJS_priv += wpa_priv.o
+ifdef CONFIG_DRIVER_NL80211
+OBJS_priv += ../src/common/ieee802_11_common.o
+endif
 ifdef CONFIG_DRIVER_TEST
 OBJS_priv += $(SHA1OBJS)
 OBJS_priv += $(MD5OBJS)
@@ -1257,6 +1393,13 @@ ifndef LDO
 LDO=$(CC)
 endif
 
+Q=@
+E=echo
+ifeq ($(V), 1)
+Q=
+E=true
+endif
+
 dynamic_eap_methods: $(EAPDYN)
 
 ../src/drivers/build.wpa_supplicant:
@@ -1268,31 +1411,42 @@ dynamic_eap_methods: $(EAPDYN)
 BCHECK=../src/drivers/build.wpa_supplicant
 
 wpa_priv: $(BCHECK) $(OBJS_priv)
-       $(LDO) $(LDFLAGS) -o wpa_priv $(OBJS_priv) $(LIBS)
+       $(Q)$(LDO) $(LDFLAGS) -o wpa_priv $(OBJS_priv) $(LIBS)
+       @$(E) "  LD " $@
+
+$(OBJS_c) $(OBJS_t) $(OBJS_t2) $(OBJS) $(BCHECK) $(EXTRA_progs): .config
 
-wpa_supplicant: .config $(BCHECK) $(OBJS) $(EXTRA_progs)
-       $(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS)
+wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs)
+       $(Q)$(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS)
+       @$(E) "  LD " $@
 
-eapol_test: .config $(OBJS_t)
-       $(LDO) $(LDFLAGS) -o eapol_test $(OBJS_t) $(LIBS)
+eapol_test: $(OBJS_t)
+       $(Q)$(LDO) $(LDFLAGS) -o eapol_test $(OBJS_t) $(LIBS)
+       @$(E) "  LD " $@
 
-preauth_test: .config $(OBJS_t2) 
-       $(LDO) $(LDFLAGS) -o preauth_test $(OBJS_t2) $(LIBS)
+preauth_test: $(OBJS_t2)
+       $(Q)$(LDO) $(LDFLAGS) -o preauth_test $(OBJS_t2) $(LIBS)
+       @$(E) "  LD " $@
 
 wpa_passphrase: $(OBJS_p)
-       $(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p)
+       $(Q)$(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p)
+       @$(E) "  LD " $@
 
 wpa_cli: $(OBJS_c)
-       $(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c)
+       $(Q)$(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c)
+       @$(E) "  LD " $@
 
 link_test: $(OBJS) $(OBJS_h) tests/link_test.o
-       $(LDO) $(LDFLAGS) -o link_test $(OBJS) $(OBJS_h) tests/link_test.o $(LIBS)
+       $(Q)$(LDO) $(LDFLAGS) -o link_test $(OBJS) $(OBJS_h) tests/link_test.o $(LIBS)
+       @$(E) "  LD " $@
 
 test_wpa: $(OBJS_wpa) $(OBJS_h)
-       $(LDO) $(LDFLAGS) -o test_wpa $(OBJS_wpa) $(LIBS)
+       $(Q)$(LDO) $(LDFLAGS) -o test_wpa $(OBJS_wpa) $(LIBS)
+       @$(E) "  LD " $@
 
 win_if_list: win_if_list.c
-       $(LDO) $(LDFLAGS) -o $@ win_if_list.c $(CFLAGS) $(LIBS_w)
+       $(Q)$(LDO) $(LDFLAGS) -o $@ win_if_list.c $(CFLAGS) $(LIBS_w)
+       @$(E) "  LD " $@
 
 eap_psk.so: ../src/eap_peer/eap_psk.c ../src/eap_common/eap_psk_common.c
        $(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
@@ -1318,17 +1472,13 @@ eap_ikev2.so: ../src/eap_peer/eap_ikev2.c ../src/eap_peer/ikev2.c ../src/eap_com
        $(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \
                -D$(*F:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init
 
-Q=@
-E=echo
-ifeq ($(V), 1)
-Q=
-E=true
-endif
-
 %.o: %.c
        $(Q)$(CC) -c -o $@ $(CFLAGS) $<
        @$(E) "  CC " $<
 
+%.service: %.service.in
+       sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+
 wpa_supplicant.exe: wpa_supplicant
        mv -f $< $@
 wpa_cli.exe: wpa_cli
@@ -1345,11 +1495,8 @@ WINALL=wpa_supplicant.exe wpa_cli.exe wpa_passphrase.exe win_if_list.exe
 windows-bin: $(WINALL)
        $(STRIP) $(WINALL)
 
-wpa_gui/Makefile:
-       qmake -o wpa_gui/Makefile wpa_gui/wpa_gui.pro 
-
-wpa_gui: wpa_gui/Makefile
-       $(MAKE) -C wpa_gui
+wpa_gui:
+       @echo "wpa_gui has been removed - see wpa_gui-qt4 for replacement"
 
 wpa_gui-qt4/Makefile:
        qmake -o wpa_gui-qt4/Makefile wpa_gui-qt4/wpa_gui.pro 
index 45c8bae..4d02f8f 100644 (file)
@@ -1,7 +1,7 @@
 WPA Supplicant
 ==============
 
-Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 This program is dual-licensed under both the GPL version 2 and BSD
@@ -138,55 +138,6 @@ Current hardware/software requirements:
        default option to start with before falling back to driver specific
        interface.
 
-       Host AP driver for Prism2/2.5/3 (development snapshot/v0.2.x)
-       (http://hostap.epitest.fi/)
-       Driver need to be set in Managed mode ('iwconfig wlan0 mode managed').
-       Please note that station firmware version needs to be 1.7.0 or newer
-       to work in WPA mode.
-
-       Linuxant DriverLoader (http://www.linuxant.com/driverloader/)
-       with Windows NDIS driver for your wlan card supporting WPA.
-
-       Agere Systems Inc. Linux Driver
-       (http://www.agere.com/support/drivers/)
-       Please note that the driver interface file (driver_hermes.c) and
-       hardware specific include files are not included in the
-       wpa_supplicant distribution. You will need to copy these from the
-       source package of the Agere driver.
-
-       madwifi driver for cards based on Atheros chip set (ar521x)
-       (http://sourceforge.net/projects/madwifi/)
-       Please note that you will need to modify the wpa_supplicant .config
-       file to use the correct path for the madwifi driver root directory
-       (CFLAGS += -I../madwifi/wpa line in example defconfig).
-
-       ATMEL AT76C5XXx driver for USB and PCMCIA cards
-       (http://atmelwlandriver.sourceforge.net/).
-
-       Linux ndiswrapper (http://ndiswrapper.sourceforge.net/) with
-       Windows NDIS driver.
-
-       Broadcom wl.o driver (old version only)
-       This is a generic Linux driver for Broadcom IEEE 802.11a/g cards.
-       However, it is proprietary driver that is not publicly available
-       except for couple of exceptions, mainly Broadcom-based APs/wireless
-       routers that use Linux. The driver binary can be downloaded, e.g.,
-       from Linksys support site (http://www.linksys.com/support/gpl.asp)
-       for Linksys WRT54G. The GPL tarball includes cross-compiler and
-       the needed header file, wlioctl.h, for compiling wpa_supplicant.
-       This driver support in wpa_supplicant is expected to work also with
-       other devices based on Broadcom driver (assuming the driver includes
-       client mode support). Please note that the newer Broadcom driver
-       ("hybrid Linux driver") supports Linux wireless extensions and does
-       not need (or even work) with the specific driver wrapper. Use -Dwext
-       with that driver.
-
-       Intel ipw2100 driver
-       (http://sourceforge.net/projects/ipw2100/)
-
-       Intel ipw2200 driver
-       (http://sourceforge.net/projects/ipw2200/)
-
        In theory, any driver that supports Linux wireless extensions can be
        used with IEEE 802.1X (i.e., not WPA) when using ap_scan=0 option in
        configuration file.
@@ -363,7 +314,7 @@ and a list of available options and additional notes.
 The build time configuration can be used to select only the needed
 features and limit the binary size and requirements for external
 libraries. The main configuration parts are the selection of which
-driver interfaces (e.g., hostap, madwifi, ..) and which authentication
+driver interfaces (e.g., nl80211, wext, ..) and which authentication
 methods (e.g., EAP-TLS, EAP-PEAP, ..) are included.
 
 Following build time configuration options are used to control IEEE
@@ -396,32 +347,18 @@ authentication algorithm (for EAP-SIM/EAP-AKA). This requires pcsc-lite
 CONFIG_PCSC=y
 
 Following options can be added to .config to select which driver
-interfaces are included. Hermes driver interface needs to be downloaded
-from Agere (see above).
+interfaces are included.
 
-CONFIG_DRIVER_HOSTAP=y
-CONFIG_DRIVER_HERMES=y
-CONFIG_DRIVER_MADWIFI=y
-CONFIG_DRIVER_ATMEL=y
+CONFIG_DRIVER_NL80211=y
 CONFIG_DRIVER_WEXT=y
-CONFIG_DRIVER_RALINK=y
-CONFIG_DRIVER_NDISWRAPPER=y
-CONFIG_DRIVER_BROADCOM=y
-CONFIG_DRIVER_IPW=y
 CONFIG_DRIVER_BSD=y
 CONFIG_DRIVER_NDIS=y
 
-Following example includes all features and driver interfaces that are
-included in the wpa_supplicant package:
+Following example includes some more features and driver interfaces that
+are included in the wpa_supplicant package:
 
-CONFIG_DRIVER_HOSTAP=y
-CONFIG_DRIVER_HERMES=y
-CONFIG_DRIVER_MADWIFI=y
-CONFIG_DRIVER_ATMEL=y
+CONFIG_DRIVER_NL80211=y
 CONFIG_DRIVER_WEXT=y
-CONFIG_DRIVER_NDISWRAPPER=y
-CONFIG_DRIVER_BROADCOM=y
-CONFIG_DRIVER_IPW=y
 CONFIG_DRIVER_BSD=y
 CONFIG_DRIVER_NDIS=y
 CONFIG_IEEE8021X_EAPOL=y
@@ -514,16 +451,7 @@ options:
   -N = start describing new interface
 
 drivers:
-  hostap = Host AP driver (Intersil Prism2/2.5/3) [default]
-       (this can also be used with Linuxant DriverLoader)
-  hermes = Agere Systems Inc. driver (Hermes-I/Hermes-II)
-  madwifi = MADWIFI 802.11 support (Atheros, etc.) (deprecated; use wext)
-  atmel = ATMEL AT76C5XXx (USB, PCMCIA)
   wext = Linux wireless extensions (generic)
-  ralink = Ralink Client driver
-  ndiswrapper = Linux ndiswrapper (deprecated; use wext)
-  broadcom = Broadcom wl.o driver
-  ipw = Intel ipw2100/2200 driver (old; use wext with Linux 2.6.13 or newer)
   wired = wpa_supplicant wired Ethernet driver
   roboswitch = wpa_supplicant Broadcom switch driver
   bsd = BSD 802.11 support (Atheros, etc.)
@@ -556,15 +484,15 @@ separated with -N argument. As an example, following command would
 start wpa_supplicant for two interfaces:
 
 wpa_supplicant \
-       -c wpa1.conf -i wlan0 -D hostap -N \
-       -c wpa2.conf -i ath0 -D madwifi
+       -c wpa1.conf -i wlan0 -D nl80211 -N \
+       -c wpa2.conf -i wlan1 -D wext
 
 
 If the interface is added in a Linux bridge (e.g., br0), the bridge
 interface needs to be configured to wpa_supplicant in addition to the
 main interface:
 
-wpa_supplicant -cw.conf -Dmadwifi -iath0 -bbr0
+wpa_supplicant -cw.conf -Dwext -iwlan0 -bbr0
 
 
 Configuration file
@@ -894,13 +822,14 @@ script:
 IFNAME=$1
 CMD=$2
 
-if [ "$CMD" == "CONNECTED" ]; then
+if [ "$CMD" = "CONNECTED" ]; then
     SSID=`wpa_cli -i$IFNAME status | grep ^ssid= | cut -f2- -d=`
     # configure network, signal DHCP client, etc.
 fi
 
-if [ "$CMD" == "DISCONNECTED" ]; then
+if [ "$CMD" = "DISCONNECTED" ]; then
     # remove network configuration, if needed
+    SSID=
 fi
 
 
diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P
new file mode 100644 (file)
index 0000000..db6e4ae
--- /dev/null
@@ -0,0 +1,525 @@
+wpa_supplicant and Wi-Fi P2P
+============================
+
+This document describes how the Wi-Fi P2P implementation in
+wpa_supplicant can be configured and how an external component on the
+client (e.g., management GUI) is used to enable WPS enrollment and
+registrar registration.
+
+
+Introduction to Wi-Fi P2P
+-------------------------
+
+TODO
+
+More information about Wi-Fi P2P is available from Wi-Fi Alliance:
+http://www.wi-fi.org/Wi-Fi_Direct.php
+
+
+wpa_supplicant implementation
+-----------------------------
+
+TODO
+
+
+wpa_supplicant configuration
+----------------------------
+
+Wi-Fi P2P is an optional component that needs to be enabled in the
+wpa_supplicant build configuration (.config). Here is an example
+configuration that includes Wi-Fi P2P support and Linux nl80211
+-based driver interface:
+
+CONFIG_DRIVER_NL80211=y
+CONFIG_CTRL_IFACE=y
+CONFIG_P2P=y
+CONFIG_AP=y
+CONFIG_WPS=y
+
+
+In run-time configuration file (wpa_supplicant.conf), some parameters
+for P2P may be set. In order to make the devices easier to recognize,
+device_name and device_type should be specified. For example,
+something like this should be included:
+
+ctrl_interface=/var/run/wpa_supplicant
+device_name=My P2P Device
+device_type=1-0050F204-1
+
+
+wpa_cli
+-------
+
+Actual Wi-Fi P2P operations are requested during runtime. These can be
+done for example using wpa_cli (which is described below) or a GUI
+like wpa_gui-qt4.
+
+
+wpa_cli starts in interactive mode if no command string is included on
+the command line. By default, it will select the first network interface
+that it can find (and that wpa_supplicant controls). If more than one
+interface is in use, it may be necessary to select one of the explicitly
+by adding -i argument on the command line (e.g., 'wpa_cli -i wlan1').
+
+Most of the P2P operations are done on the main interface (e.g., the
+interface that is automatically added when the driver is loaded, e.g.,
+wlan0). When using a separate virtual interface for group operations
+(e.g., wlan1), the control interface for that group interface may need
+to be used for some operations (mainly WPS activation in GO). This may
+change in the future so that all the needed operations could be done
+over the main control interface.
+
+Device Discovery
+
+p2p_find [timeout in seconds] [type=<social|progressive>]
+
+The default behavior is to run a single full scan in the beginning and
+then scan only social channels. type=social will scan only social
+channels, i.e., it skips the initial full scan. type=progressive is
+like the default behavior, but it will scan through all the channels
+progressively one channel at the time in the Search state rounds. This
+will help in finding new groups or groups missed during the initial
+full scan.
+
+p2p_listen [timeout in seconds]
+
+Start Listen-only state (become discoverable without searching for
+other devices). Optional parameter can be used to specify the duration
+for the Listen operation in seconds. This command may not be of that
+much use during normal operations and is mainly designed for
+testing. It can also be used to keep the device discoverable without
+having to maintain a group.
+
+p2p_stop_find
+
+Stop ongoing P2P device discovery or other operation (connect, listen
+mode).
+
+p2p_flush
+
+Flush P2P peer table and state.
+
+Group Formation
+
+p2p_prov_disc <peer device address> <display|keypad|pbc> [join]
+
+Send P2P provision discovery request to the specified peer. The
+parameters for this command are the P2P device address of the peer and
+the desired configuration method. For example, "p2p_prov_disc
+02:01:02:03:04:05 display" would request the peer to display a PIN for
+us and "p2p_prov_disc 02:01:02:03:04:05 keypad" would request the peer
+to enter a PIN that we display.
+
+The optional "join" parameter can be used to indicate that this command
+is requesting an already running GO to prepare for a new client. This is
+mainly used with "display" to request it to display a PIN.
+
+p2p_connect <peer device address> <pbc|pin|PIN#> [display|keypad]
+       [persistent] [join|auth] [go_intent=<0..15>] [freq=<in MHz>]
+
+Start P2P group formation with a discovered P2P peer. This includes
+optional group owner negotiation, group interface setup, provisioning,
+and establishing data connection.
+
+The <pbc|pin|PIN#> parameter specifies the WPS provisioning
+method. "pbc" string starts pushbutton method, "pin" string start PIN
+method using an automatically generated PIN (which will be returned as
+the command return code), PIN# means that a pre-selected PIN can be
+used (e.g., 12345670). [display|keypad] is used with PIN method
+to specify which PIN is used (display=dynamically generated random PIN
+from local display, keypad=PIN entered from peer display). "persistent"
+parameter can be used to request a persistent group to be formed.
+
+"join" indicates that this is a command to join an existing group as a
+client. It skips the GO Negotiation part. This will send a Provision
+Discovery Request message to the target GO before associating for WPS
+provisioning.
+
+"auth" indicates that the WPS parameters are authorized for the peer
+device without actually starting GO Negotiation (i.e., the peer is
+expected to initiate GO Negotiation). This is mainly for testing
+purposes.
+
+"go_intent" can be used to override the default GO Intent for this GO
+Negotiation.
+
+"freq" can be used to set a forced operating channel (e.g., freq=2412
+to select 2.4 GHz channel 1).
+
+p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>]
+
+Set up a P2P group owner manually (i.e., without group owner
+negotiation with a specific peer). This is also known as autonomous
+GO. Optional persistent=<network id> can be used to specify restart of
+a persistent group. Optional freq=<freq in MHz> can be used to force
+the GO to be started on a specific frequency. Special freq=2 or freq=5
+options can be used to request the best 2.4 GHz or 5 GHz band channel
+to be selected automatically.
+
+p2p_reject <peer device address>
+
+Reject connection attempt from a peer (specified with a device
+address). This is a mechanism to reject a pending GO Negotiation with
+a peer and request to automatically block any further connection or
+discovery of the peer.
+
+p2p_group_remove <group interface>
+
+Terminate a P2P group. If a new virtual network interface was used for
+the group, it will also be removed. The network interface name of the
+group interface is used as a parameter for this command.
+
+p2p_cancel
+
+Cancel an ongoing P2P group formation related operation.
+
+Service Discovery
+
+p2p_serv_disc_req
+
+Schedule a P2P service discovery request. The parameters for this
+command are the device address of the peer device (or 00:00:00:00:00:00
+for wildcard query that is sent to every discovered P2P peer that
+supports service discovery) and P2P Service Query TLV(s) as hexdump. For
+example,
+
+p2p_serv_disc_req 00:00:00:00:00:00 02000001
+
+schedules a request for listing all available services of all service
+discovery protocols and requests this to be sent to all discovered
+peers (note: this can result in long response frames). The pending
+requests are sent during device discovery (see p2p_find).
+
+Only a single pending wildcard query is supported, but there can be
+multiple pending peer device specific queries (each will be sent in
+sequence whenever the peer is found).
+
+This command returns an identifier for the pending query (e.g.,
+"1f77628") that can be used to cancel the request. Directed requests
+will be automatically removed when the specified peer has replied to
+it.
+
+For UPnP, an alternative command format can be used to specify a
+single query TLV (i.e., a service discovery for a specific UPnP
+service):
+
+p2p_serv_disc_req 00:00:00:00:00:00 upnp <version hex> <ST: from M-SEARCH>
+
+For example:
+
+p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:device:InternetGatewayDevice:1
+
+Additional examples for queries:
+
+# list of all Bonjour services
+p2p_serv_disc_req 00:00:00:00:00:00 02000101
+
+# list of all UPnP services
+p2p_serv_disc_req 00:00:00:00:00:00 02000201
+
+# list of all WS-Discovery services
+p2p_serv_disc_req 00:00:00:00:00:00 02000301
+
+# list of all Bonjour and UPnP services
+p2p_serv_disc_req 00:00:00:00:00:00 0200010102000202
+
+# Apple File Sharing over TCP
+p2p_serv_disc_req 00:00:00:00:00:00 130001010b5f6166706f766572746370c00c000c01
+
+# Bonjour SSTH (supported service type hash)
+p2p_serv_disc_req 00:00:00:00:00:00 05000101000000
+
+# UPnP examples
+p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 ssdp:all
+p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 upnp:rootdevice
+p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:service:ContentDirectory:2
+p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 uuid:6859dede-8574-59ab-9332-123456789012
+p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:device:InternetGatewayDevice:1
+
+p2p_serv_disc_cancel_req <query identifier>
+
+Cancel a pending P2P service discovery request. This command takes a
+single parameter: identifier for the pending query (the value returned
+by p2p_serv_disc_req, e.g., "p2p_serv_disc_cancel_req 1f77628".
+
+p2p_serv_disc_resp
+
+Reply to a service discovery query. This command takes following
+parameters: frequency in MHz, destination address, dialog token,
+response TLV(s). The first three parameters are copied from the
+request event. For example, "p2p_serv_disc_resp 2437 02:40:61:c2:f3:b7
+1 0300000101". This command is used only if external program is used
+to process the request (see p2p_serv_disc_external).
+
+p2p_service_update
+
+Indicate that local services have changed. This is used to increment
+the P2P service indicator value so that peers know when previously
+cached information may have changed. This is only needed when external
+service discovery processing is enabled since the commands to
+pre-configure services for internal processing will increment the
+indicator automatically.
+
+p2p_serv_disc_external <0|1>
+
+Configure external processing of P2P service requests: 0 (default) =
+no external processing of requests (i.e., internal code will process
+each request based on pre-configured services), 1 = external
+processing of requests (external program is responsible for replying
+to service discovery requests with p2p_serv_disc_resp). Please note
+that there is quite strict limit on how quickly the response needs to
+be transmitted, so use of the internal processing is strongly
+recommended.
+
+p2p_service_add bonjour <query hexdump> <RDATA hexdump>
+
+Add a local Bonjour service for internal SD query processing.
+
+Examples:
+
+# AFP Over TCP (PTR)
+p2p_service_add bonjour 0b5f6166706f766572746370c00c000c01 074578616d706c65c027
+# AFP Over TCP (TXT) (RDATA=null)
+p2p_service_add bonjour 076578616d706c650b5f6166706f766572746370c00c001001 00
+
+# IP Printing over TCP (PTR) (RDATA=MyPrinter._ipp._tcp.local.)
+p2p_service_add bonjour 045f697070c00c000c01 094d795072696e746572c027
+# IP Printing over TCP (TXT) (RDATA=txtvers=1,pdl=application/postscript)
+p2p_service_add bonjour 096d797072696e746572045f697070c00c001001 09747874766572733d311a70646c3d6170706c69636174696f6e2f706f7374736372797074
+
+# Supported Service Type Hash (SSTH)
+p2p_service_add bonjour 000000 <32-byte bitfield as hexdump>
+(note: see P2P spec Annex E.4 for information on how to construct the bitfield)
+
+p2p_service_del bonjour <query hexdump>
+
+Remove a local Bonjour service from internal SD query processing.
+
+p2p_service_add upnp <version hex> <service>
+
+Add a local UPnP service for internal SD query processing.
+
+Examples:
+
+p2p_service_add upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice
+p2p_service_add upnp 10 uuid:5566d33e-9774-09ab-4822-333456785632::upnp:rootdevice
+p2p_service_add upnp 10 uuid:1122de4e-8574-59ab-9322-333456789044::urn:schemas-upnp-org:service:ContentDirectory:2
+p2p_service_add upnp 10 uuid:5566d33e-9774-09ab-4822-333456785632::urn:schemas-upnp-org:service:ContentDirectory:2
+p2p_service_add upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp-org:device:InternetGatewayDevice:1
+
+p2p_service_del upnp <version hex> <service>
+
+Remove a local UPnP service from internal SD query processing.
+
+p2p_service_flush
+
+Remove all local services from internal SD query processing.
+
+Invitation
+
+p2p_invite [persistent=<network id>|group=<group ifname>] [peer=address]
+       [go_dev_addr=address]
+
+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
+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).
+
+Group Operations
+
+(These are used on the group interface.)
+
+wps_pin <any|address> <PIN>
+
+Start WPS PIN method. This allows a single WPS Enrollee to connect to
+the AP/GO. This is used on the GO when a P2P client joins an existing
+group. The second parameter is the address of the Enrollee or a string
+"any" to allow any station to use the entered PIN (which will restrict
+the PIN for one-time-use). PIN is the Enrollee PIN read either from a
+label or display on the P2P Client/WPS Enrollee.
+
+wps_pbc
+
+Start WPS PBC method (i.e., push the button). This allows a single WPS
+Enrollee to connect to the AP/GO. This is used on the GO when a P2P
+client joins an existing group.
+
+p2p_get_passphrase
+
+Get the passphrase for a group (only available when acting as a GO).
+
+p2p_presence_req [<duration> <interval>] [<duration> <interval>]
+
+Send a P2P Presence Request to the GO (this is only available when
+acting as a P2P client). If no duration/interval pairs are given, the
+request indicates that this client has no special needs for GO
+presence. the first parameter pair gives the preferred duration and
+interval values in microseconds. If the second pair is included, that
+indicates which value would be acceptable.
+
+Parameters
+
+p2p_ext_listen [<period> <interval>]
+
+Configure Extended Listen Timing. If the parameters are omitted, this
+feature is disabled. If the parameters are included, Listen State will
+be entered every interval msec for at least period msec. Both values
+have acceptable range of 1-65535 (with interval obviously having to be
+larger than or equal to duration). If the P2P module is not idle at
+the time the Extended Listen Timing timeout occurs, the Listen State
+operation will be skipped.
+
+The configured values will also be advertised to other P2P Devices. The
+received values are available in the p2p_peer command output:
+
+ext_listen_period=100 ext_listen_interval=5000
+
+p2p_set <field> <value>
+
+Change dynamic P2P parameters
+
+p2p_set discoverability <0/1>
+
+Disable/enable advertisement of client discoverability. This is
+enabled by default and this parameter is mainly used to allow testing
+of device discoverability.
+
+p2p_set managed <0/1>
+
+Disable/enable managed P2P Device operations. This is disabled by
+default.
+
+p2p_set listen_channel <1/6/11>
+
+Set P2P Listen channel. This is mainly meant for testing purposes and
+changing the Listen channel during normal operations can result in
+protocol failures.
+
+p2p_set ssid_postfix <postfix>
+
+Set postfix string to be added to the automatically generated P2P SSID
+(DIRECT-<two random characters>). For example, postfix of "-testing"
+could result in the SSID becoming DIRECT-ab-testing.
+
+set <field> <value>
+
+Set global configuration parameters which may also affect P2P
+operations. The format on these parameters is same as is used in
+wpa_supplicant.conf. Only the parameters listen here should be
+changed. Modifying other parameters may result in incorrect behavior
+since not all existing users of the parameters are updated.
+
+set uuid <UUID>
+
+Set WPS UUID (by default, this is generated based on the MAC address).
+
+set device_name <device name>
+
+Set WPS Device Name (also included in some P2P messages).
+
+set manufacturer <manufacturer>
+
+Set WPS Manufacturer.
+
+set model_name <model name>
+
+Set WPS Model Name.
+
+set model_number <model number>
+
+Set WPS Model Number.
+
+set serial_number <serial number>
+
+Set WPS Serial Number.
+
+set device_type <device type>
+
+Set WPS Device Type.
+
+set os_version <OS version>
+
+Set WPS OS Version.
+
+set config_methods <config methods>
+
+Set WPS Configuration Methods.
+
+set sec_device_type <device type>
+
+Add a new Secondary Device Type.
+
+set p2p_go_intent <GO intent>
+
+Set the default P2P GO Intent. Note: This value can be overridden in
+p2p_connect command and as such, there should be no need to change the
+default value here during normal operations.
+
+set p2p_ssid_postfix <P2P SSID postfix>
+
+Set P2P SSID postfix.
+
+set persistent_reconnect <0/1>
+
+Disable/enabled persistent reconnect for reinvocation of persistent
+groups. If enabled, invitations to reinvoke a persistent group will be
+accepted without separate authorization (e.g., user interaction).
+
+set country <two character country code>
+
+Set country code (this is included in some P2P messages).
+
+Status
+
+p2p_peers [discovered]
+
+List P2P Device Addresses of all the P2P peers we know. The optional
+"discovered" parameter filters out the peers that we have not fully
+discovered, i.e., which we have only seen in a received Probe Request
+frame.
+
+p2p_peer <P2P Device Address>
+
+Fetch information about a known P2P peer.
+
+Group Status
+
+(These are used on the group interface.)
+
+status
+
+Show status information (connection state, role, use encryption
+parameters, IP address, etc.).
+
+sta
+
+Show information about an associated station (when acting in AP/GO role).
+
+all_sta
+
+Lists the currently associated stations.
+
+Configuration data
+
+list_networks
+
+Lists the configured networks, including stored information for
+persistent groups. The identifier in this list is used with
+p2p_group_add and p2p_invite to indicate which persistent group is to
+be reinvoked.
+
+remove_network <network id>
+
+Remove a network entry from configuration. 
+
+
+wpa_cli action script
+---------------------
+
+See examples/p2p-action.sh
+
+TODO: describe DHCP/DNS setup
+TODO: cross-connection
index 8f0d0d6..bf75cb4 100644 (file)
@@ -47,9 +47,7 @@ wpa_supplicant implementation
 
 wpa_supplicant includes an optional WPS component that can be used as
 an Enrollee to enroll new network credential or as a Registrar to
-configure an AP. The current version of wpa_supplicant does not
-support operation as an external WLAN Management Registrar for adding
-new client devices or configuring the AP over UPnP.
+configure an AP.
 
 
 wpa_supplicant configuration
@@ -57,11 +55,17 @@ wpa_supplicant configuration
 
 WPS is an optional component that needs to be enabled in
 wpa_supplicant build configuration (.config). Here is an example
-configuration that includes WPS support and Linux wireless extensions
--based driver interface:
+configuration that includes WPS support and Linux nl80211 -based
+driver interface:
 
-CONFIG_DRIVER_WEXT=y
+CONFIG_DRIVER_NL80211=y
 CONFIG_WPS=y
+CONFIG_WPS2=y
+
+If you want to enable WPS external registrar (ER) functionality, you
+will also need to add following line:
+
+CONFIG_WPS_ER=y
 
 
 WPS needs the Universally Unique IDentifier (UUID; see RFC 4122) for
@@ -93,6 +97,13 @@ pushbutton event (for PBC) to allow a new WPS Enrollee to join the
 network. wpa_supplicant uses the control interface as an input channel
 for these events.
 
+The PIN value used in the commands must be processed by an UI to
+remove non-digit characters and potentially, to verify the checksum
+digit. "wpa_cli wps_check_pin <PIN>" can be used to do such processing.
+It returns FAIL if the PIN is invalid, or FAIL-CHECKSUM if the checksum
+digit is incorrect, or the processed PIN (non-digit characters removed)
+if the PIN is valid.
+
 If the client device has a display, a random PIN has to be generated
 for each WPS registration session. wpa_supplicant can do this with a
 control interface request, e.g., by calling wpa_cli:
@@ -116,6 +127,11 @@ This starts the WPS negotiation in the same way as above with the
 generated PIN.
 
 
+If a random PIN is needed for a user interface, "wpa_cli wps_pin get"
+can be used to generate a new PIN without starting WPS negotiation.
+This random PIN can then be passed as an argument to another wps_pin
+call when the actual operation should be started.
+
 If the client design wants to support optional WPS PBC mode, this can
 be enabled by either a physical button in the client device or a
 virtual button in the user interface. The PBC operation requires that
@@ -198,3 +214,92 @@ Following control interface messages are sent out for external programs:
 WPS-CRED-RECEIVED  <hexdump of Credential attribute(s)>
 For example:
 <2>WPS-CRED-RECEIVED 100e006f10260001011045000c6a6b6d2d7770732d74657374100300020020100f000200081027004030653462303435366332363666653064333961643135353461316634626637313234333761636664623766333939653534663166316230323061643434386235102000060266a0ee1727
+
+
+wpa_supplicant as WPS External Registrar (ER)
+---------------------------------------------
+
+wpa_supplicant can be used as a WPS ER to configure an AP or enroll
+new Enrollee to join the network. This functionality uses UPnP and
+requires that a working IP connectivity is available with the AP (this
+can be either over a wired or wireless connection).
+
+Separate wpa_supplicant process can be started for WPS ER
+operations. A special "none" driver can be used in such a case to
+indicate that no local network interface is actually controlled. For
+example, following command could be used to start the ER:
+
+wpa_supplicant -Dnone -c er.conf -ieth0
+
+Sample er.conf:
+
+ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=admin
+device_name=WPS External Registrar
+
+
+wpa_cli commands for ER functionality:
+
+wps_er_start [IP address]
+- start WPS ER functionality
+- the optional IP address parameter can be used to filter operations only
+  to include a single AP
+- if run again while ER is active, the stored information (discovered APs
+  and Enrollees) are shown again
+
+wps_er_stop
+- stop WPS ER functionality
+
+wps_er_learn <UUID> <AP PIN>
+- learn AP configuration
+
+wps_er_set_config <UUID> <network id>
+- use AP configuration from a locally configured network (e.g., from
+  wps_reg command); this does not change the AP's configuration, but
+  only prepares a configuration to be used when enrolling a new device
+  to the AP
+
+wps_er_config <UUID> <AP PIN> <new SSID> <auth> <encr> <new key>
+- examples:
+  wps_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 testing WPA2PSK CCMP 12345678
+  wpa_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 clear OPEN NONE ""
+
+<auth> must be one of the following: OPEN WPAPSK WPA2PSK
+<encr> must be one of the following: NONE WEP TKIP CCMP
+
+
+wps_er_pbc <Enrollee UUID>
+- accept an Enrollee PBC using External Registrar
+
+wps_er_pin <Enrollee UUID> <PIN> [Enrollee MAC address]
+- add an Enrollee PIN to External Registrar
+- if Enrollee UUID is not known, "any" can be used to add a wildcard PIN
+- if the MAC address of the enrollee is known, it should be configured
+  to allow the AP to advertise list of authorized enrollees
+
+
+WPS ER events:
+
+WPS_EVENT_ER_AP_ADD
+- WPS ER discovered an AP
+
+WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002 02:11:22:33:44:55 pri_dev_type=6-0050F204-1 wps_state=1 |Very friendly name|Company|Long description of the model|WAP|http://w1.fi/|http://w1.fi/hostapd/
+
+WPS_EVENT_ER_AP_REMOVE
+- WPS ER removed an AP entry
+
+WPS-ER-AP-REMOVE 87654321-9abc-def0-1234-56789abc0002
+
+WPS_EVENT_ER_ENROLLEE_ADD
+- WPS ER discovered a new Enrollee
+
+WPS-ER-ENROLLEE-ADD 2b7093f1-d6fb-5108-adbb-bea66bb87333 02:66:a0:ee:17:27 M1=1 config_methods=0x14d dev_passwd_id=0 pri_dev_type=1-0050F204-1 |Wireless Client|Company|cmodel|123|12345|
+
+WPS_EVENT_ER_ENROLLEE_REMOVE
+- WPS ER removed an Enrollee entry
+
+WPS-ER-ENROLLEE-REMOVE 2b7093f1-d6fb-5108-adbb-bea66bb87333 02:66:a0:ee:17:27
+
+WPS-ER-AP-SETTINGS
+- WPS ER learned AP settings
+
+WPS-ER-AP-SETTINGS uuid=fd91b4ec-e3fa-5891-a57d-8c59efeed1d2 ssid=test-wps auth_type=0x0020 encr_type=0x0008 key=12345678
index 2b93984..a3b460e 100644 (file)
 #include "utils/includes.h"
 
 #include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/uuid.h"
 #include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
 #include "ap/hostapd.h"
 #include "ap/ap_config.h"
+#include "ap/ap_drv_ops.h"
 #ifdef NEED_AP_MLME
 #include "ap/ieee802_11.h"
 #endif /* NEED_AP_MLME */
+#include "ap/beacon.h"
 #include "ap/ieee802_1x.h"
 #include "ap/wps_hostapd.h"
 #include "ap/ctrl_iface_ap.h"
-#include "eap_common/eap_defs.h"
-#include "eap_server/eap_methods.h"
-#include "eap_common/eap_wsc_common.h"
 #include "wps/wps.h"
+#include "common/ieee802_11_defs.h"
 #include "config_ssid.h"
 #include "config.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
+#include "p2p_supplicant.h"
 #include "ap.h"
+#include "ap/sta_info.h"
+#include "notify.h"
+
+
+#ifdef CONFIG_WPS
+static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
+#endif /* CONFIG_WPS */
 
 
 static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
@@ -64,9 +75,73 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
-       /* TODO: enable HT if driver supports it;
+       /* TODO: enable HT40 if driver supports it;
         * drop to 11b if driver does not support 11g */
 
+#ifdef CONFIG_IEEE80211N
+       /*
+        * Enable HT20 if the driver supports it, by setting conf->ieee80211n
+        * and a mask of allowed capabilities within conf->ht_capab.
+        * Using default config settings for: conf->ht_op_mode_fixed,
+        * conf->secondary_channel, conf->require_ht
+        */
+       if (wpa_s->hw.modes) {
+               struct hostapd_hw_modes *mode = NULL;
+               int i;
+               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) {
+                       conf->ieee80211n = 1;
+
+                       /*
+                        * white-list capabilities that won't cause issues
+                        * to connecting stations, while leaving the current
+                        * capabilities intact (currently disabled SMPS).
+                        */
+                       conf->ht_capab |= mode->ht_capab &
+                               (HT_CAP_INFO_GREEN_FIELD |
+                                HT_CAP_INFO_SHORT_GI20MHZ |
+                                HT_CAP_INFO_SHORT_GI40MHZ |
+                                HT_CAP_INFO_RX_STBC_MASK |
+                                HT_CAP_INFO_MAX_AMSDU_SIZE);
+               }
+       }
+#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_P2P
+       if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
+               /* Remove 802.11b rates from supported and basic rate sets */
+               int *list = os_malloc(4 * sizeof(int));
+               if (list) {
+                       list[0] = 60;
+                       list[1] = 120;
+                       list[2] = 240;
+                       list[3] = -1;
+               }
+               conf->basic_rates = list;
+
+               list = os_malloc(9 * sizeof(int));
+               if (list) {
+                       list[0] = 60;
+                       list[1] = 90;
+                       list[2] = 120;
+                       list[3] = 180;
+                       list[4] = 240;
+                       list[5] = 360;
+                       list[6] = 480;
+                       list[7] = 540;
+                       list[8] = -1;
+               }
+               conf->supported_rates = list;
+       }
+
+       bss->isolate = !wpa_s->conf->p2p_intra_bss;
+#endif /* CONFIG_P2P */
+
        if (ssid->ssid_len == 0) {
                wpa_printf(MSG_ERROR, "No SSID configured for AP mode");
                return -1;
@@ -76,6 +151,9 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
        bss->ssid.ssid_len = ssid->ssid_len;
        bss->ssid.ssid_set = 1;
 
+       if (ssid->auth_alg)
+               bss->auth_algs = ssid->auth_alg;
+
        if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt))
                bss->wpa = ssid->proto;
        bss->wpa_key_mgmt = ssid->key_mgmt;
@@ -89,6 +167,22 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                        return -1;
                os_memcpy(bss->ssid.wpa_psk->psk, ssid->psk, PMK_LEN);
                bss->ssid.wpa_psk->group = 1;
+       } else if (ssid->wep_key_len[0] || ssid->wep_key_len[1] ||
+                  ssid->wep_key_len[2] || ssid->wep_key_len[3]) {
+               struct hostapd_wep_keys *wep = &bss->ssid.wep;
+               int i;
+               for (i = 0; i < NUM_WEP_KEYS; i++) {
+                       if (ssid->wep_key_len[i] == 0)
+                               continue;
+                       wep->key[i] = os_malloc(ssid->wep_key_len[i]);
+                       if (wep->key[i] == NULL)
+                               return -1;
+                       os_memcpy(wep->key[i], ssid->wep_key[i],
+                                 ssid->wep_key_len[i]);
+                       wep->len[i] = ssid->wep_key_len[i];
+               }
+               wep->idx = ssid->wep_tx_keyidx;
+               wep->keys_set = 1;
        }
 
        /* Select group cipher based on the enabled pairwise cipher suites */
@@ -110,46 +204,187 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
        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;
-       } else if (bss->ssid.wep.keys_set)
+               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;
-       else
+               bss->wpa_group = cipher;
+               bss->wpa_pairwise = cipher;
+               bss->rsn_pairwise = cipher;
+       } else {
                bss->ssid.security_policy = SECURITY_PLAINTEXT;
+               bss->wpa_group = WPA_CIPHER_NONE;
+               bss->wpa_pairwise = WPA_CIPHER_NONE;
+               bss->rsn_pairwise = WPA_CIPHER_NONE;
+       }
 
 #ifdef CONFIG_WPS
        /*
-        * Enable WPS by default, but require user interaction to actually use
-        * it. Only the internal Registrar is supported.
+        * Enable WPS by default for open and WPA/WPA2-Personal network, but
+        * require user interaction to actually use it. Only the internal
+        * Registrar is supported.
         */
+       if (bss->ssid.security_policy != SECURITY_WPA_PSK &&
+           bss->ssid.security_policy != SECURITY_PLAINTEXT)
+               goto no_wps;
+#ifdef CONFIG_WPS2
+       if (bss->ssid.security_policy == SECURITY_WPA_PSK &&
+           (!(pairwise & WPA_CIPHER_CCMP) || !(bss->wpa & 2)))
+               goto no_wps; /* WPS2 does not allow WPA/TKIP-only
+                             * configuration */
+#endif /* CONFIG_WPS2 */
        bss->eap_server = 1;
        bss->wps_state = 2;
-       bss->ap_setup_locked = 1;
+       bss->ap_setup_locked = 2;
        if (wpa_s->conf->config_methods)
                bss->config_methods = os_strdup(wpa_s->conf->config_methods);
-       if (wpa_s->conf->device_type)
-               bss->device_type = os_strdup(wpa_s->conf->device_type);
+       os_memcpy(bss->device_type, wpa_s->conf->device_type,
+                 WPS_DEV_TYPE_LEN);
+       if (wpa_s->conf->device_name) {
+               bss->device_name = os_strdup(wpa_s->conf->device_name);
+               bss->friendly_name = os_strdup(wpa_s->conf->device_name);
+       }
+       if (wpa_s->conf->manufacturer)
+               bss->manufacturer = os_strdup(wpa_s->conf->manufacturer);
+       if (wpa_s->conf->model_name)
+               bss->model_name = os_strdup(wpa_s->conf->model_name);
+       if (wpa_s->conf->model_number)
+               bss->model_number = os_strdup(wpa_s->conf->model_number);
+       if (wpa_s->conf->serial_number)
+               bss->serial_number = os_strdup(wpa_s->conf->serial_number);
+       if (is_nil_uuid(wpa_s->conf->uuid))
+               os_memcpy(bss->uuid, wpa_s->wps->uuid, WPS_UUID_LEN);
+       else
+               os_memcpy(bss->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
+       os_memcpy(bss->os_version, wpa_s->conf->os_version, 4);
+no_wps:
 #endif /* CONFIG_WPS */
 
+       if (wpa_s->max_stations &&
+           wpa_s->max_stations < wpa_s->conf->max_num_sta)
+               bss->max_num_sta = wpa_s->max_stations;
+       else
+               bss->max_num_sta = wpa_s->conf->max_num_sta;
+
+       bss->disassoc_low_ack = wpa_s->conf->disassoc_low_ack;
+
        return 0;
 }
 
 
 static void ap_public_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
 {
+#ifdef CONFIG_P2P
+       struct wpa_supplicant *wpa_s = ctx;
+       const struct ieee80211_mgmt *mgmt;
+       size_t hdr_len;
+
+       mgmt = (const struct ieee80211_mgmt *) buf;
+       hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
+       if (hdr_len > len)
+               return;
+       wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
+                          mgmt->u.action.category,
+                          &mgmt->u.action.u.vs_public_action.action,
+                          len - hdr_len, freq);
+#endif /* CONFIG_P2P */
+}
+
+
+static void ap_wps_event_cb(void *ctx, enum wps_event event,
+                           union wps_event_data *data)
+{
+#ifdef CONFIG_P2P
+       struct wpa_supplicant *wpa_s = ctx;
+
+       if (event == WPS_EV_FAIL) {
+               struct wps_event_fail *fail = &data->fail;
+
+               if (wpa_s->parent && wpa_s->parent != wpa_s &&
+                   wpa_s == wpa_s->global->p2p_group_formation) {
+                       /*
+                        * src/ap/wps_hostapd.c has already sent this on the
+                        * main interface, so only send on the parent interface
+                        * here if needed.
+                        */
+                       wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+                               "msg=%d config_error=%d",
+                               fail->msg, fail->config_error);
+               }
+               wpas_p2p_wps_failed(wpa_s, fail);
+       }
+#endif /* CONFIG_P2P */
+}
+
+
+static void ap_sta_authorized_cb(void *ctx, const u8 *mac_addr,
+                                int authorized)
+{
+       wpas_notify_sta_authorized(ctx, mac_addr, authorized);
+}
+
+
+static int ap_vendor_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
+{
+#ifdef CONFIG_P2P
+       struct wpa_supplicant *wpa_s = ctx;
+       const struct ieee80211_mgmt *mgmt;
+       size_t hdr_len;
+
+       mgmt = (const struct ieee80211_mgmt *) buf;
+       hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
+       if (hdr_len > len)
+               return -1;
+       wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
+                          mgmt->u.action.category,
+                          &mgmt->u.action.u.vs_public_action.action,
+                          len - hdr_len, freq);
+#endif /* CONFIG_P2P */
+       return 0;
 }
 
 
-static int ap_probe_req_rx(void *ctx, const u8 *addr, const u8 *ie,
-                          size_t ie_len)
+static int ap_probe_req_rx(void *ctx, const u8 *sa, const u8 *da,
+                          const u8 *bssid, const u8 *ie, size_t ie_len)
 {
+#ifdef CONFIG_P2P
+       struct wpa_supplicant *wpa_s = ctx;
+       return wpas_p2p_probe_req_rx(wpa_s, sa, da, bssid, ie, ie_len);
+#else /* CONFIG_P2P */
        return 0;
+#endif /* CONFIG_P2P */
 }
 
 
 static void ap_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
                                  const u8 *uuid_e)
 {
+#ifdef CONFIG_P2P
+       struct wpa_supplicant *wpa_s = ctx;
+       wpas_p2p_wps_success(wpa_s, mac_addr, 1);
+#endif /* CONFIG_P2P */
+}
+
+
+static void wpas_ap_configured_cb(void *ctx)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+
+       if (wpa_s->ap_configured_cb)
+               wpa_s->ap_configured_cb(wpa_s->ap_configured_cb_ctx,
+                                       wpa_s->ap_configured_cb_data);
 }
 
 
@@ -182,11 +417,14 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
                params.mode = IEEE80211_MODE_IBSS;
                break;
        case WPAS_MODE_AP:
+       case WPAS_MODE_P2P_GO:
+       case WPAS_MODE_P2P_GROUP_FORMATION:
                params.mode = IEEE80211_MODE_AP;
                break;
        }
        params.freq = ssid->frequency;
 
+       params.wpa_proto = ssid->proto;
        if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
                wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
        else
@@ -207,6 +445,17 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
        params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher);
        params.group_suite = params.pairwise_suite;
 
+#ifdef CONFIG_P2P
+       if (ssid->mode == WPAS_MODE_P2P_GO ||
+           ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
+               params.p2p = 1;
+#endif /* CONFIG_P2P */
+
+       if (wpa_s->parent->set_ap_uapsd)
+               params.uapsd = wpa_s->parent->ap_uapsd;
+       else
+               params.uapsd = -1;
+
        if (wpa_drv_associate(wpa_s, &params) < 0) {
                wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality");
                return -1;
@@ -216,6 +465,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
        if (hapd_iface == NULL)
                return -1;
        hapd_iface->owner = wpa_s;
+       hapd_iface->drv_flags = wpa_s->drv_flags;
+       hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads;
 
        wpa_s->ap_iface->conf = conf = hostapd_config_defaults();
        if (conf == NULL) {
@@ -223,12 +474,25 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
+       if (params.uapsd > 0) {
+               conf->bss->wmm_enabled = 1;
+               conf->bss->wmm_uapsd = 1;
+       }
+
        if (wpa_supplicant_conf_ap(wpa_s, ssid, conf)) {
                wpa_printf(MSG_ERROR, "Failed to create AP configuration");
                wpa_supplicant_ap_deinit(wpa_s);
                return -1;
        }
 
+#ifdef CONFIG_P2P
+       if (ssid->mode == WPAS_MODE_P2P_GO)
+               conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER;
+       else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
+               conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER |
+                       P2P_GROUP_FORMATION;
+#endif /* CONFIG_P2P */
+
        hapd_iface->num_bss = conf->num_bss;
        hapd_iface->bss = os_zalloc(conf->num_bss *
                                    sizeof(struct hostapd_data *));
@@ -247,42 +511,64 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
                }
 
                hapd_iface->bss[i]->msg_ctx = wpa_s;
+               hapd_iface->bss[i]->msg_ctx_parent = wpa_s->parent;
                hapd_iface->bss[i]->public_action_cb = ap_public_action_rx;
                hapd_iface->bss[i]->public_action_cb_ctx = wpa_s;
+               hapd_iface->bss[i]->vendor_action_cb = ap_vendor_action_rx;
+               hapd_iface->bss[i]->vendor_action_cb_ctx = wpa_s;
                hostapd_register_probereq_cb(hapd_iface->bss[i],
                                             ap_probe_req_rx, wpa_s);
                hapd_iface->bss[i]->wps_reg_success_cb = ap_wps_reg_success_cb;
                hapd_iface->bss[i]->wps_reg_success_cb_ctx = wpa_s;
+               hapd_iface->bss[i]->wps_event_cb = ap_wps_event_cb;
+               hapd_iface->bss[i]->wps_event_cb_ctx = wpa_s;
+               hapd_iface->bss[i]->sta_authorized_cb = ap_sta_authorized_cb;
+               hapd_iface->bss[i]->sta_authorized_cb_ctx = wpa_s;
+#ifdef CONFIG_P2P
+               hapd_iface->bss[i]->p2p = wpa_s->global->p2p;
+               hapd_iface->bss[i]->p2p_group = wpas_p2p_group_init(
+                       wpa_s, ssid->p2p_persistent_group,
+                       ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION);
+#endif /* CONFIG_P2P */
+               hapd_iface->bss[i]->setup_complete_cb = wpas_ap_configured_cb;
+               hapd_iface->bss[i]->setup_complete_cb_ctx = wpa_s;
        }
 
        os_memcpy(hapd_iface->bss[0]->own_addr, wpa_s->own_addr, ETH_ALEN);
        hapd_iface->bss[0]->driver = wpa_s->driver;
        hapd_iface->bss[0]->drv_priv = wpa_s->drv_priv;
 
+       wpa_s->current_ssid = ssid;
+       os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
+       wpa_s->assoc_freq = ssid->frequency;
+
        if (hostapd_setup_interface(wpa_s->ap_iface)) {
                wpa_printf(MSG_ERROR, "Failed to initialize AP interface");
                wpa_supplicant_ap_deinit(wpa_s);
                return -1;
        }
 
-       wpa_s->current_ssid = ssid;
-       os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
-       wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
-
-       if (wpa_s->ap_configured_cb)
-               wpa_s->ap_configured_cb(wpa_s->ap_configured_cb_ctx,
-                                       wpa_s->ap_configured_cb_data);
-
        return 0;
 }
 
 
 void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s)
 {
+#ifdef CONFIG_WPS
+       eloop_cancel_timeout(wpas_wps_ap_pin_timeout, wpa_s, NULL);
+#endif /* CONFIG_WPS */
+
        if (wpa_s->ap_iface == NULL)
                return;
 
        wpa_s->current_ssid = NULL;
+       wpa_s->assoc_freq = 0;
+       wpa_s->reassociated_connection = 0;
+#ifdef CONFIG_P2P
+       if (wpa_s->ap_iface->bss)
+               wpa_s->ap_iface->bss[0]->p2p_group = NULL;
+       wpas_p2p_group_deinit(wpa_s);
+#endif /* CONFIG_P2P */
        hostapd_interface_deinit(wpa_s->ap_iface);
        hostapd_interface_free(wpa_s->ap_iface);
        wpa_s->ap_iface = NULL;
@@ -300,16 +586,31 @@ void ap_tx_status(void *ctx, const u8 *addr,
 }
 
 
-void ap_rx_from_unknown_sta(void *ctx, const u8 *frame, size_t len)
+void ap_eapol_tx_status(void *ctx, const u8 *dst,
+                       const u8 *data, size_t len, int ack)
+{
+#ifdef NEED_AP_MLME
+       struct wpa_supplicant *wpa_s = ctx;
+       hostapd_tx_status(wpa_s->ap_iface->bss[0], dst, data, len, ack);
+#endif /* NEED_AP_MLME */
+}
+
+
+void ap_client_poll_ok(void *ctx, const u8 *addr)
+{
+#ifdef NEED_AP_MLME
+       struct wpa_supplicant *wpa_s = ctx;
+       if (wpa_s->ap_iface)
+               hostapd_client_poll_ok(wpa_s->ap_iface->bss[0], addr);
+#endif /* NEED_AP_MLME */
+}
+
+
+void ap_rx_from_unknown_sta(void *ctx, const u8 *addr, int wds)
 {
 #ifdef NEED_AP_MLME
        struct wpa_supplicant *wpa_s = ctx;
-       const struct ieee80211_hdr *hdr =
-               (const struct ieee80211_hdr *) frame;
-       u16 fc = le_to_host16(hdr->frame_control);
-       ieee802_11_rx_from_unknown(wpa_s->ap_iface->bss[0], hdr->addr2,
-                                  (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
-                                  (WLAN_FC_TODS | WLAN_FC_FROMDS));
+       ieee802_11_rx_from_unknown(wpa_s->ap_iface->bss[0], addr, wds);
 #endif /* NEED_AP_MLME */
 }
 
@@ -346,11 +647,58 @@ void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s,
 
 #ifdef CONFIG_WPS
 
-int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid)
+int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
+                             const u8 *p2p_dev_addr)
 {
        if (!wpa_s->ap_iface)
                return -1;
-       return hostapd_wps_button_pushed(wpa_s->ap_iface->bss[0]);
+       return hostapd_wps_button_pushed(wpa_s->ap_iface->bss[0],
+                                        p2p_dev_addr);
+}
+
+
+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;
+       int reg_sel = 0, wps_sta = 0;
+
+       if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0]->wps)
+               return -1;
+
+       reg = wpa_s->ap_iface->bss[0]->wps->registrar;
+       reg_sel = wps_registrar_wps_cancel(reg);
+       wps_sta = ap_for_each_sta(wpa_s->ap_iface->bss[0],
+                                 wpa_supplicant_ap_wps_sta_cancel, NULL);
+
+       if (!reg_sel && !wps_sta) {
+               wpa_printf(MSG_DEBUG, "No WPS operation in progress at this "
+                          "time");
+               return -1;
+       }
+
+       /*
+        * There are 2 cases to return wps cancel as success:
+        * 1. When wps cancel was initiated but no connection has been
+        *    established with client yet.
+        * 2. Client is in the middle of exchanging WPS messages.
+        */
+
+       return 0;
 }
 
 
@@ -364,16 +712,135 @@ int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
 
        if (pin == NULL) {
                unsigned int rpin = wps_generate_pin();
-               ret_len = os_snprintf(buf, buflen, "%d", rpin);
+               ret_len = os_snprintf(buf, buflen, "%08d", rpin);
                pin = buf;
-       }
+       } else
+               ret_len = os_snprintf(buf, buflen, "%s", pin);
 
-       ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], "any", pin, 0);
+       ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], bssid, "any", pin,
+                                 0);
        if (ret)
                return -1;
        return ret_len;
 }
 
+
+static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_data;
+       wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out");
+       wpas_wps_ap_pin_disable(wpa_s);
+}
+
+
+static void wpas_wps_ap_pin_enable(struct wpa_supplicant *wpa_s, int timeout)
+{
+       struct hostapd_data *hapd;
+
+       if (wpa_s->ap_iface == NULL)
+               return;
+       hapd = wpa_s->ap_iface->bss[0];
+       wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout);
+       hapd->ap_pin_failures = 0;
+       eloop_cancel_timeout(wpas_wps_ap_pin_timeout, wpa_s, NULL);
+       if (timeout > 0)
+               eloop_register_timeout(timeout, 0,
+                                      wpas_wps_ap_pin_timeout, wpa_s, NULL);
+}
+
+
+void wpas_wps_ap_pin_disable(struct wpa_supplicant *wpa_s)
+{
+       struct hostapd_data *hapd;
+
+       if (wpa_s->ap_iface == NULL)
+               return;
+       wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN");
+       hapd = wpa_s->ap_iface->bss[0];
+       os_free(hapd->conf->ap_pin);
+       hapd->conf->ap_pin = NULL;
+       eloop_cancel_timeout(wpas_wps_ap_pin_timeout, wpa_s, NULL);
+}
+
+
+const char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout)
+{
+       struct hostapd_data *hapd;
+       unsigned int pin;
+       char pin_txt[9];
+
+       if (wpa_s->ap_iface == NULL)
+               return NULL;
+       hapd = wpa_s->ap_iface->bss[0];
+       pin = wps_generate_pin();
+       os_snprintf(pin_txt, sizeof(pin_txt), "%08u", pin);
+       os_free(hapd->conf->ap_pin);
+       hapd->conf->ap_pin = os_strdup(pin_txt);
+       if (hapd->conf->ap_pin == NULL)
+               return NULL;
+       wpas_wps_ap_pin_enable(wpa_s, timeout);
+
+       return hapd->conf->ap_pin;
+}
+
+
+const char * wpas_wps_ap_pin_get(struct wpa_supplicant *wpa_s)
+{
+       struct hostapd_data *hapd;
+       if (wpa_s->ap_iface == NULL)
+               return NULL;
+       hapd = wpa_s->ap_iface->bss[0];
+       return hapd->conf->ap_pin;
+}
+
+
+int wpas_wps_ap_pin_set(struct wpa_supplicant *wpa_s, const char *pin,
+                       int timeout)
+{
+       struct hostapd_data *hapd;
+       char pin_txt[9];
+       int ret;
+
+       if (wpa_s->ap_iface == NULL)
+               return -1;
+       hapd = wpa_s->ap_iface->bss[0];
+       ret = os_snprintf(pin_txt, sizeof(pin_txt), "%s", pin);
+       if (ret < 0 || ret >= (int) sizeof(pin_txt))
+               return -1;
+       os_free(hapd->conf->ap_pin);
+       hapd->conf->ap_pin = os_strdup(pin_txt);
+       if (hapd->conf->ap_pin == NULL)
+               return -1;
+       wpas_wps_ap_pin_enable(wpa_s, timeout);
+
+       return 0;
+}
+
+
+void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s)
+{
+       struct hostapd_data *hapd;
+
+       if (wpa_s->ap_iface == NULL)
+               return;
+       hapd = wpa_s->ap_iface->bss[0];
+
+       /*
+        * Registrar failed to prove its knowledge of the AP PIN. Disable AP
+        * PIN if this happens multiple times to slow down brute force attacks.
+        */
+       hapd->ap_pin_failures++;
+       wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u",
+                  hapd->ap_pin_failures);
+       if (hapd->ap_pin_failures < 3)
+               return;
+
+       wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN");
+       hapd->ap_pin_failures = 0;
+       os_free(hapd->conf->ap_pin);
+       hapd->conf->ap_pin = NULL;
+}
+
 #endif /* CONFIG_WPS */
 
 
@@ -440,6 +907,31 @@ int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
 #endif /* CONFIG_CTRL_IFACE */
 
 
+int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s)
+{
+       struct hostapd_iface *iface = wpa_s->ap_iface;
+       struct wpa_ssid *ssid = wpa_s->current_ssid;
+       struct hostapd_data *hapd;
+
+       if (ssid == NULL || wpa_s->ap_iface == NULL)
+               return -1;
+
+#ifdef CONFIG_P2P
+       if (ssid->mode == WPAS_MODE_P2P_GO)
+               iface->conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER;
+       else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
+               iface->conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER |
+                       P2P_GROUP_FORMATION;
+#endif /* CONFIG_P2P */
+
+       ieee802_11_set_beacons(iface);
+       hapd = iface->bss[0];
+       hostapd_set_ap_wps_ie(hapd);
+
+       return 0;
+}
+
+
 int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
                                      const u8 *addr)
 {
index 381a432..aa4c362 100644 (file)
@@ -21,9 +21,16 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
 void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s,
                                const u8 *src_addr, const u8 *buf, size_t len);
-int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
+                             const u8 *p2p_dev_addr);
 int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
                              const char *pin, char *buf, size_t buflen);
+int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s);
+void wpas_wps_ap_pin_disable(struct wpa_supplicant *wpa_s);
+const char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout);
+const char * wpas_wps_ap_pin_get(struct wpa_supplicant *wpa_s);
+int wpas_wps_ap_pin_set(struct wpa_supplicant *wpa_s, const char *pin,
+                       int timeout);
 int ap_ctrl_iface_sta_first(struct wpa_supplicant *wpa_s,
                            char *buf, size_t buflen);
 int ap_ctrl_iface_sta(struct wpa_supplicant *wpa_s, const char *txtaddr,
@@ -34,10 +41,15 @@ int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
                                 size_t buflen, int verbose);
 void ap_tx_status(void *ctx, const u8 *addr,
                  const u8 *buf, size_t len, int ack);
-void ap_rx_from_unknown_sta(void *ctx, const u8 *frame, size_t len);
+void ap_eapol_tx_status(void *ctx, const u8 *dst,
+                       const u8 *data, size_t len, int ack);
+void ap_client_poll_ok(void *ctx, const u8 *addr);
+void ap_rx_from_unknown_sta(void *ctx, const u8 *addr, int wds);
 void ap_mgmt_rx(void *ctx, struct rx_mgmt *rx_mgmt);
 void ap_mgmt_tx_cb(void *ctx, const u8 *buf, size_t len, u16 stype, int ok);
+int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s);
 int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
                                      const u8 *addr);
+void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s);
 
 #endif /* AP_H */
index 31b5d27..5661830 100644 (file)
 #ifdef CONFIG_BGSCAN_SIMPLE
 extern const struct bgscan_ops bgscan_simple_ops;
 #endif /* CONFIG_BGSCAN_SIMPLE */
+#ifdef CONFIG_BGSCAN_LEARN
+extern const struct bgscan_ops bgscan_learn_ops;
+#endif /* CONFIG_BGSCAN_LEARN */
 
 static const struct bgscan_ops * bgscan_modules[] = {
 #ifdef CONFIG_BGSCAN_SIMPLE
        &bgscan_simple_ops,
 #endif /* CONFIG_BGSCAN_SIMPLE */
+#ifdef CONFIG_BGSCAN_LEARN
+       &bgscan_learn_ops,
+#endif /* CONFIG_BGSCAN_LEARN */
        NULL
 };
 
@@ -88,10 +94,12 @@ void bgscan_deinit(struct wpa_supplicant *wpa_s)
 }
 
 
-int bgscan_notify_scan(struct wpa_supplicant *wpa_s)
+int bgscan_notify_scan(struct wpa_supplicant *wpa_s,
+                      struct wpa_scan_results *scan_res)
 {
        if (wpa_s->bgscan && wpa_s->bgscan_priv)
-               return wpa_s->bgscan->notify_scan(wpa_s->bgscan_priv);
+               return wpa_s->bgscan->notify_scan(wpa_s->bgscan_priv,
+                                                 scan_res);
        return 0;
 }
 
@@ -103,8 +111,13 @@ void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s)
 }
 
 
-void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above)
+void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above,
+                                int current_signal, int current_noise,
+                                int current_txrate)
 {
        if (wpa_s->bgscan && wpa_s->bgscan_priv)
-               wpa_s->bgscan->notify_signal_change(wpa_s->bgscan_priv, above);
+               wpa_s->bgscan->notify_signal_change(wpa_s->bgscan_priv, above,
+                                                   current_signal,
+                                                   current_noise,
+                                                   current_txrate);
 }
index 69e99b6..ae94a48 100644 (file)
@@ -25,18 +25,24 @@ struct bgscan_ops {
                       const struct wpa_ssid *ssid);
        void (*deinit)(void *priv);
 
-       int (*notify_scan)(void *priv);
+       int (*notify_scan)(void *priv, struct wpa_scan_results *scan_res);
        void (*notify_beacon_loss)(void *priv);
-       void (*notify_signal_change)(void *priv, int above);
+       void (*notify_signal_change)(void *priv, int above,
+                                    int current_signal,
+                                    int current_noise,
+                                    int current_txrate);
 };
 
 #ifdef CONFIG_BGSCAN
 
 int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
 void bgscan_deinit(struct wpa_supplicant *wpa_s);
-int bgscan_notify_scan(struct wpa_supplicant *wpa_s);
+int bgscan_notify_scan(struct wpa_supplicant *wpa_s,
+                      struct wpa_scan_results *scan_res);
 void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s);
-void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above);
+void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above,
+                                int current_signal, int current_noise,
+                                int current_txrate);
 
 #else /* CONFIG_BGSCAN */
 
@@ -50,7 +56,8 @@ static inline void bgscan_deinit(struct wpa_supplicant *wpa_s)
 {
 }
 
-static inline int bgscan_notify_scan(struct wpa_supplicant *wpa_s)
+static inline int bgscan_notify_scan(struct wpa_supplicant *wpa_s,
+                                    struct wpa_scan_results *scan_res)
 {
        return 0;
 }
@@ -60,7 +67,9 @@ static inline void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s)
 }
 
 static inline void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s,
-                                              int above)
+                                              int above, int current_signal,
+                                              int current_noise,
+                                              int current_txrate)
 {
 }
 
diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c
new file mode 100644 (file)
index 0000000..5385cce
--- /dev/null
@@ -0,0 +1,610 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "list.h"
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+#include "config_ssid.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "scan.h"
+#include "bgscan.h"
+
+struct bgscan_learn_bss {
+       struct dl_list list;
+       u8 bssid[ETH_ALEN];
+       int freq;
+       u8 *neigh; /* num_neigh * ETH_ALEN buffer */
+       size_t num_neigh;
+};
+
+struct bgscan_learn_data {
+       struct wpa_supplicant *wpa_s;
+       const struct wpa_ssid *ssid;
+       int scan_interval;
+       int signal_threshold;
+       int short_interval; /* use if signal < threshold */
+       int long_interval; /* use if signal > threshold */
+       struct os_time last_bgscan;
+       char *fname;
+       struct dl_list bss;
+       int *supp_freqs;
+       int probe_idx;
+};
+
+
+static void bss_free(struct bgscan_learn_bss *bss)
+{
+       os_free(bss->neigh);
+       os_free(bss);
+}
+
+
+static int bssid_in_array(u8 *array, size_t array_len, const u8 *bssid)
+{
+       size_t i;
+
+       if (array == NULL || array_len == 0)
+               return 0;
+
+       for (i = 0; i < array_len; i++) {
+               if (os_memcmp(array + i * ETH_ALEN, bssid, ETH_ALEN) == 0)
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+static void bgscan_learn_add_neighbor(struct bgscan_learn_bss *bss,
+                                     const u8 *bssid)
+{
+       u8 *n;
+
+       if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
+               return;
+       if (bssid_in_array(bss->neigh, bss->num_neigh, bssid))
+               return;
+
+       n = os_realloc(bss->neigh, (bss->num_neigh + 1) * ETH_ALEN);
+       if (n == NULL)
+               return;
+
+       os_memcpy(n + bss->num_neigh * ETH_ALEN, bssid, ETH_ALEN);
+       bss->neigh = n;
+       bss->num_neigh++;
+}
+
+
+static struct bgscan_learn_bss * bgscan_learn_get_bss(
+       struct bgscan_learn_data *data, const u8 *bssid)
+{
+       struct bgscan_learn_bss *bss;
+
+       dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
+               if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
+                       return bss;
+       }
+       return NULL;
+}
+
+
+static int bgscan_learn_load(struct bgscan_learn_data *data)
+{
+       FILE *f;
+       char buf[128];
+       struct bgscan_learn_bss *bss;
+
+       if (data->fname == NULL)
+               return 0;
+
+       f = fopen(data->fname, "r");
+       if (f == NULL)
+               return 0;
+
+       wpa_printf(MSG_DEBUG, "bgscan learn: Loading data from %s",
+                  data->fname);
+
+       if (fgets(buf, sizeof(buf), f) == NULL ||
+           os_strncmp(buf, "wpa_supplicant-bgscan-learn\n", 28) != 0) {
+               wpa_printf(MSG_INFO, "bgscan learn: Invalid data file %s",
+                          data->fname);
+               fclose(f);
+               return -1;
+       }
+
+       while (fgets(buf, sizeof(buf), f)) {
+               if (os_strncmp(buf, "BSS ", 4) == 0) {
+                       bss = os_zalloc(sizeof(*bss));
+                       if (!bss)
+                               continue;
+                       if (hwaddr_aton(buf + 4, bss->bssid) < 0) {
+                               bss_free(bss);
+                               continue;
+                       }
+                       bss->freq = atoi(buf + 4 + 18);
+                       dl_list_add(&data->bss, &bss->list);
+                       wpa_printf(MSG_DEBUG, "bgscan learn: Loaded BSS "
+                                  "entry: " MACSTR " freq=%d",
+                                  MAC2STR(bss->bssid), bss->freq);
+               }
+
+               if (os_strncmp(buf, "NEIGHBOR ", 9) == 0) {
+                       u8 addr[ETH_ALEN];
+
+                       if (hwaddr_aton(buf + 9, addr) < 0)
+                               continue;
+                       bss = bgscan_learn_get_bss(data, addr);
+                       if (bss == NULL)
+                               continue;
+                       if (hwaddr_aton(buf + 9 + 18, addr) < 0)
+                               continue;
+
+                       bgscan_learn_add_neighbor(bss, addr);
+               }
+       }
+
+       fclose(f);
+       return 0;
+}
+
+
+static void bgscan_learn_save(struct bgscan_learn_data *data)
+{
+       FILE *f;
+       struct bgscan_learn_bss *bss;
+
+       if (data->fname == NULL)
+               return;
+
+       wpa_printf(MSG_DEBUG, "bgscan learn: Saving data to %s",
+                  data->fname);
+
+       f = fopen(data->fname, "w");
+       if (f == NULL)
+               return;
+       fprintf(f, "wpa_supplicant-bgscan-learn\n");
+
+       dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
+               fprintf(f, "BSS " MACSTR " %d\n",
+                       MAC2STR(bss->bssid), bss->freq);
+       }
+
+       dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
+               size_t i;
+               for (i = 0; i < bss->num_neigh; i++) {
+                       fprintf(f, "NEIGHBOR " MACSTR " " MACSTR "\n",
+                               MAC2STR(bss->bssid),
+                               MAC2STR(bss->neigh + i * ETH_ALEN));
+               }
+       }
+
+       fclose(f);
+}
+
+
+static int in_array(int *array, int val)
+{
+       int i;
+
+       if (array == NULL)
+               return 0;
+
+       for (i = 0; array[i]; i++) {
+               if (array[i] == val)
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+static int * bgscan_learn_get_freqs(struct bgscan_learn_data *data,
+                                   size_t *count)
+{
+       struct bgscan_learn_bss *bss;
+       int *freqs = NULL, *n;
+
+       *count = 0;
+
+       dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
+               if (in_array(freqs, bss->freq))
+                       continue;
+               n = os_realloc(freqs, (*count + 2) * sizeof(int));
+               if (n == NULL)
+                       return freqs;
+               freqs = n;
+               freqs[*count] = bss->freq;
+               (*count)++;
+               freqs[*count] = 0;
+       }
+
+       return freqs;
+}
+
+
+static int * bgscan_learn_get_probe_freq(struct bgscan_learn_data *data,
+                                        int *freqs, size_t count)
+{
+       int idx, *n;
+
+       if (data->supp_freqs == NULL)
+               return freqs;
+
+       idx = data->probe_idx + 1;
+       while (idx != data->probe_idx) {
+               if (data->supp_freqs[idx] == 0)
+                       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));
+                       if (n == NULL)
+                               return freqs;
+                       freqs = n;
+                       freqs[count] = data->supp_freqs[idx];
+                       count++;
+                       freqs[count] = 0;
+                       break;
+               }
+
+               idx++;
+       }
+
+       return freqs;
+}
+
+
+static void bgscan_learn_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct bgscan_learn_data *data = eloop_ctx;
+       struct wpa_supplicant *wpa_s = data->wpa_s;
+       struct wpa_driver_scan_params params;
+       int *freqs = NULL;
+       size_t count, i;
+       char msg[100], *pos;
+
+       os_memset(&params, 0, sizeof(params));
+       params.num_ssids = 1;
+       params.ssids[0].ssid = data->ssid->ssid;
+       params.ssids[0].ssid_len = data->ssid->ssid_len;
+       if (data->ssid->scan_freq)
+               params.freqs = data->ssid->scan_freq;
+       else {
+               freqs = bgscan_learn_get_freqs(data, &count);
+               wpa_printf(MSG_DEBUG, "bgscan learn: BSSes in this ESS have "
+                          "been seen on %u channels", (unsigned int) count);
+               freqs = bgscan_learn_get_probe_freq(data, freqs, count);
+
+               msg[0] = '\0';
+               pos = msg;
+               for (i = 0; freqs && freqs[i]; i++) {
+                       int ret;
+                       ret = os_snprintf(pos, msg + sizeof(msg) - pos, " %d",
+                                         freqs[i]);
+                       if (ret < 0 || ret >= msg + sizeof(msg) - pos)
+                               break;
+                       pos += ret;
+               }
+               pos[0] = '\0';
+               wpa_printf(MSG_DEBUG, "bgscan learn: Scanning frequencies:%s",
+                          msg);
+               params.freqs = freqs;
+       }
+
+       wpa_printf(MSG_DEBUG, "bgscan learn: Request a background scan");
+       if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
+               wpa_printf(MSG_DEBUG, "bgscan learn: Failed to trigger scan");
+               eloop_register_timeout(data->scan_interval, 0,
+                                      bgscan_learn_timeout, data, NULL);
+       } else
+               os_get_time(&data->last_bgscan);
+       os_free(freqs);
+}
+
+
+static int bgscan_learn_get_params(struct bgscan_learn_data *data,
+                                  const char *params)
+{
+       const char *pos;
+
+       if (params == NULL)
+               return 0;
+
+       data->short_interval = atoi(params);
+
+       pos = os_strchr(params, ':');
+       if (pos == NULL)
+               return 0;
+       pos++;
+       data->signal_threshold = atoi(pos);
+       pos = os_strchr(pos, ':');
+       if (pos == NULL) {
+               wpa_printf(MSG_ERROR, "bgscan learn: Missing scan interval "
+                          "for high signal");
+               return -1;
+       }
+       pos++;
+       data->long_interval = atoi(pos);
+       pos = os_strchr(pos, ':');
+       if (pos) {
+               pos++;
+               data->fname = os_strdup(pos);
+       }
+
+       return 0;
+}
+
+
+static int * bgscan_learn_get_supp_freqs(struct wpa_supplicant *wpa_s)
+{
+       struct hostapd_hw_modes *modes;
+       int i, j, *freqs = NULL, *n;
+       size_t count = 0;
+
+       modes = wpa_s->hw.modes;
+       if (modes == NULL)
+               return NULL;
+
+       for (i = 0; i < wpa_s->hw.num_modes; i++) {
+               for (j = 0; j < modes[i].num_channels; j++) {
+                       if (modes[i].channels[j].flag & HOSTAPD_CHAN_DISABLED)
+                               continue;
+                       n = os_realloc(freqs, (count + 2) * sizeof(int));
+                       if (n == NULL)
+                               continue;
+
+                       freqs = n;
+                       freqs[count] = modes[i].channels[j].freq;
+                       count++;
+                       freqs[count] = 0;
+               }
+       }
+
+       return freqs;
+}
+
+
+static void * bgscan_learn_init(struct wpa_supplicant *wpa_s,
+                               const char *params,
+                               const struct wpa_ssid *ssid)
+{
+       struct bgscan_learn_data *data;
+
+       data = os_zalloc(sizeof(*data));
+       if (data == NULL)
+               return NULL;
+       dl_list_init(&data->bss);
+       data->wpa_s = wpa_s;
+       data->ssid = ssid;
+       if (bgscan_learn_get_params(data, params) < 0) {
+               os_free(data->fname);
+               os_free(data);
+               return NULL;
+       }
+       if (data->short_interval <= 0)
+               data->short_interval = 30;
+       if (data->long_interval <= 0)
+               data->long_interval = 30;
+
+       if (bgscan_learn_load(data) < 0) {
+               os_free(data->fname);
+               os_free(data);
+               return NULL;
+       }
+
+       wpa_printf(MSG_DEBUG, "bgscan learn: Signal strength threshold %d  "
+                  "Short bgscan interval %d  Long bgscan interval %d",
+                  data->signal_threshold, data->short_interval,
+                  data->long_interval);
+
+       if (data->signal_threshold &&
+           wpa_drv_signal_monitor(wpa_s, data->signal_threshold, 4) < 0) {
+               wpa_printf(MSG_ERROR, "bgscan learn: Failed to enable "
+                          "signal strength monitoring");
+       }
+
+       data->supp_freqs = bgscan_learn_get_supp_freqs(wpa_s);
+       data->scan_interval = data->short_interval;
+       eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout,
+                              data, NULL);
+
+       /*
+        * This function is called immediately after an association, so it is
+        * reasonable to assume that a scan was completed recently. This makes
+        * us skip an immediate new scan in cases where the current signal
+        * level is below the bgscan threshold.
+        */
+       os_get_time(&data->last_bgscan);
+
+       return data;
+}
+
+
+static void bgscan_learn_deinit(void *priv)
+{
+       struct bgscan_learn_data *data = priv;
+       struct bgscan_learn_bss *bss, *n;
+
+       bgscan_learn_save(data);
+       eloop_cancel_timeout(bgscan_learn_timeout, data, NULL);
+       if (data->signal_threshold)
+               wpa_drv_signal_monitor(data->wpa_s, 0, 0);
+       os_free(data->fname);
+       dl_list_for_each_safe(bss, n, &data->bss, struct bgscan_learn_bss,
+                             list) {
+               dl_list_del(&bss->list);
+               bss_free(bss);
+       }
+       os_free(data->supp_freqs);
+       os_free(data);
+}
+
+
+static int bgscan_learn_bss_match(struct bgscan_learn_data *data,
+                                 struct wpa_scan_res *bss)
+{
+       const u8 *ie;
+
+       ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
+       if (ie == NULL)
+               return 0;
+
+       if (data->ssid->ssid_len != ie[1] ||
+           os_memcmp(data->ssid->ssid, ie + 2, ie[1]) != 0)
+               return 0; /* SSID mismatch */
+
+       return 1;
+}
+
+
+static int bgscan_learn_notify_scan(void *priv,
+                                   struct wpa_scan_results *scan_res)
+{
+       struct bgscan_learn_data *data = priv;
+       size_t i, j;
+#define MAX_BSS 50
+       u8 bssid[MAX_BSS * ETH_ALEN];
+       size_t num_bssid = 0;
+
+       wpa_printf(MSG_DEBUG, "bgscan learn: scan result notification");
+
+       eloop_cancel_timeout(bgscan_learn_timeout, data, NULL);
+       eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout,
+                              data, NULL);
+
+       for (i = 0; i < scan_res->num; i++) {
+               struct wpa_scan_res *res = scan_res->res[i];
+               if (!bgscan_learn_bss_match(data, res))
+                       continue;
+
+               if (num_bssid < MAX_BSS) {
+                       os_memcpy(bssid + num_bssid * ETH_ALEN, res->bssid,
+                                 ETH_ALEN);
+                       num_bssid++;
+               }
+       }
+       wpa_printf(MSG_DEBUG, "bgscan learn: %u matching BSSes in scan "
+                  "results", (unsigned int) num_bssid);
+
+       for (i = 0; i < scan_res->num; i++) {
+               struct wpa_scan_res *res = scan_res->res[i];
+               struct bgscan_learn_bss *bss;
+
+               if (!bgscan_learn_bss_match(data, res))
+                       continue;
+
+               bss = bgscan_learn_get_bss(data, res->bssid);
+               if (bss && bss->freq != res->freq) {
+                       wpa_printf(MSG_DEBUG, "bgscan learn: Update BSS "
+                          MACSTR " freq %d -> %d",
+                                  MAC2STR(res->bssid), bss->freq, res->freq);
+                       bss->freq = res->freq;
+               } else if (!bss) {
+                       wpa_printf(MSG_DEBUG, "bgscan learn: Add BSS " MACSTR
+                                  " freq=%d", MAC2STR(res->bssid), res->freq);
+                       bss = os_zalloc(sizeof(*bss));
+                       if (!bss)
+                               continue;
+                       os_memcpy(bss->bssid, res->bssid, ETH_ALEN);
+                       bss->freq = res->freq;
+                       dl_list_add(&data->bss, &bss->list);
+               }
+
+               for (j = 0; j < num_bssid; j++) {
+                       u8 *addr = bssid + j * ETH_ALEN;
+                       bgscan_learn_add_neighbor(bss, addr);
+               }
+       }
+
+       /*
+        * A more advanced bgscan could process scan results internally, select
+        * the BSS and request roam if needed. This sample uses the existing
+        * BSS/ESS selection routine. Change this to return 1 if selection is
+        * done inside the bgscan module.
+        */
+
+       return 0;
+}
+
+
+static void bgscan_learn_notify_beacon_loss(void *priv)
+{
+       wpa_printf(MSG_DEBUG, "bgscan learn: beacon loss");
+       /* TODO: speed up background scanning */
+}
+
+
+static void bgscan_learn_notify_signal_change(void *priv, int above,
+                                             int current_signal,
+                                             int current_noise,
+                                             int current_txrate)
+{
+       struct bgscan_learn_data *data = priv;
+       int scan = 0;
+       struct os_time now;
+
+       if (data->short_interval == data->long_interval ||
+           data->signal_threshold == 0)
+               return;
+
+       wpa_printf(MSG_DEBUG, "bgscan learn: signal level changed "
+                  "(above=%d current_signal=%d current_noise=%d "
+                  "current_txrate=%d)", above, current_signal,
+                  current_noise, current_txrate);
+       if (data->scan_interval == data->long_interval && !above) {
+               wpa_printf(MSG_DEBUG, "bgscan learn: Start using short bgscan "
+                          "interval");
+               data->scan_interval = data->short_interval;
+               os_get_time(&now);
+               if (now.sec > data->last_bgscan.sec + 1)
+                       scan = 1;
+       } else if (data->scan_interval == data->short_interval && above) {
+               wpa_printf(MSG_DEBUG, "bgscan learn: Start using long bgscan "
+                          "interval");
+               data->scan_interval = data->long_interval;
+               eloop_cancel_timeout(bgscan_learn_timeout, data, NULL);
+               eloop_register_timeout(data->scan_interval, 0,
+                                      bgscan_learn_timeout, data, NULL);
+       } else if (!above) {
+               /*
+                * Signal dropped further 4 dB. Request a new scan if we have
+                * not yet scanned in a while.
+                */
+               os_get_time(&now);
+               if (now.sec > data->last_bgscan.sec + 10)
+                       scan = 1;
+       }
+
+       if (scan) {
+               wpa_printf(MSG_DEBUG, "bgscan learn: Trigger immediate scan");
+               eloop_cancel_timeout(bgscan_learn_timeout, data, NULL);
+               eloop_register_timeout(0, 0, bgscan_learn_timeout, data, NULL);
+       }
+}
+
+
+const struct bgscan_ops bgscan_learn_ops = {
+       .name = "learn",
+       .init = bgscan_learn_init,
+       .deinit = bgscan_learn_deinit,
+       .notify_scan = bgscan_learn_notify_scan,
+       .notify_beacon_loss = bgscan_learn_notify_beacon_loss,
+       .notify_signal_change = bgscan_learn_notify_signal_change,
+};
index 8e80b12..eedc961 100644 (file)
@@ -28,6 +28,7 @@ struct bgscan_simple_data {
        const struct wpa_ssid *ssid;
        int scan_interval;
        int signal_threshold;
+       int short_scan_count; /* counter for scans using short scan interval */
        int short_interval; /* use if signal < threshold */
        int long_interval; /* use if signal > threshold */
        struct os_time last_bgscan;
@@ -57,8 +58,23 @@ static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx)
                wpa_printf(MSG_DEBUG, "bgscan simple: Failed to trigger scan");
                eloop_register_timeout(data->scan_interval, 0,
                                       bgscan_simple_timeout, data, NULL);
-       } else
+       } else {
+               if (data->scan_interval == data->short_interval) {
+                       data->short_scan_count++;
+                       /*
+                        * Spend at most the duration of a long scan interval
+                        * scanning at the short scan interval. After that,
+                        * revert to the long scan interval.
+                        */
+                       if (data->short_scan_count >
+                           data->long_interval / data->short_interval + 1) {
+                               data->scan_interval = data->long_interval;
+                               wpa_printf(MSG_DEBUG, "bgscan simple: Backing "
+                                          "off to long scan interval");
+                       }
+               }
                os_get_time(&data->last_bgscan);
+       }
 }
 
 
@@ -122,6 +138,15 @@ static void * bgscan_simple_init(struct wpa_supplicant *wpa_s,
        }
 
        data->scan_interval = data->short_interval;
+       if (data->signal_threshold) {
+               /* Poll for signal info to set initial scan interval */
+               struct wpa_signal_info siginfo;
+               if (wpa_drv_signal_poll(wpa_s, &siginfo) == 0 &&
+                   siginfo.current_signal >= data->signal_threshold)
+                       data->scan_interval = data->long_interval;
+       }
+       wpa_printf(MSG_DEBUG, "bgscan simple: Init scan interval: %d",
+                  data->scan_interval);
        eloop_register_timeout(data->scan_interval, 0, bgscan_simple_timeout,
                               data, NULL);
 
@@ -147,7 +172,8 @@ static void bgscan_simple_deinit(void *priv)
 }
 
 
-static int bgscan_simple_notify_scan(void *priv)
+static int bgscan_simple_notify_scan(void *priv,
+                                    struct wpa_scan_results *scan_res)
 {
        struct bgscan_simple_data *data = priv;
 
@@ -175,7 +201,10 @@ static void bgscan_simple_notify_beacon_loss(void *priv)
 }
 
 
-static void bgscan_simple_notify_signal_change(void *priv, int above)
+static void bgscan_simple_notify_signal_change(void *priv, int above,
+                                              int current_signal,
+                                              int current_noise,
+                                              int current_txrate)
 {
        struct bgscan_simple_data *data = priv;
        int scan = 0;
@@ -186,14 +215,29 @@ static void bgscan_simple_notify_signal_change(void *priv, int above)
                return;
 
        wpa_printf(MSG_DEBUG, "bgscan simple: signal level changed "
-                  "(above=%d)", above);
+                  "(above=%d current_signal=%d current_noise=%d "
+                  "current_txrate=%d))", above, current_signal,
+                  current_noise, current_txrate);
        if (data->scan_interval == data->long_interval && !above) {
                wpa_printf(MSG_DEBUG, "bgscan simple: Start using short "
                           "bgscan interval");
                data->scan_interval = data->short_interval;
+               data->short_scan_count = 0;
                os_get_time(&now);
                if (now.sec > data->last_bgscan.sec + 1)
                        scan = 1;
+               else if (data->last_bgscan.sec + data->long_interval >
+                        now.sec + data->scan_interval) {
+                       /*
+                        * Restart scan interval timer if currently scheduled
+                        * scan is too far in the future.
+                        */
+                       eloop_cancel_timeout(bgscan_simple_timeout, data,
+                                            NULL);
+                       eloop_register_timeout(data->scan_interval, 0,
+                                              bgscan_simple_timeout, data,
+                                              NULL);
+               }
        } else if (data->scan_interval == data->short_interval && above) {
                wpa_printf(MSG_DEBUG, "bgscan simple: Start using long bgscan "
                           "interval");
index 4ffb220..8f12ac9 100644 (file)
@@ -44,7 +44,7 @@ struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
  * wpa_blacklist_add - Add an BSSID to the blacklist
  * @wpa_s: Pointer to wpa_supplicant data
  * @bssid: BSSID to be added to the blacklist
- * Returns: 0 on success, -1 on failure
+ * Returns: Current blacklist count on success, -1 on failure
  *
  * This function adds the specified BSSID to the blacklist or increases the
  * blacklist count if the BSSID was already listed. It should be called when
@@ -66,7 +66,7 @@ int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
                wpa_printf(MSG_DEBUG, "BSSID " MACSTR " blacklist count "
                           "incremented to %d",
                           MAC2STR(bssid), e->count);
-               return 0;
+               return e->count;
        }
 
        e = os_zalloc(sizeof(*e));
@@ -79,7 +79,7 @@ int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
        wpa_printf(MSG_DEBUG, "Added BSSID " MACSTR " into blacklist",
                   MAC2STR(bssid));
 
-       return 0;
+       return e->count;
 }
 
 
index 691d974..dec9323 100644 (file)
  */
 #define WPA_BSS_EXPIRATION_PERIOD 10
 
-/**
- * WPA_BSS_EXPIRATION_AGE - BSS entry age after which it can be expired
- *
- * This value control the time in seconds after which a BSS entry gets removed
- * if it has not been updated or is not in use.
- */
-#define WPA_BSS_EXPIRATION_AGE 180
-
-/**
- * WPA_BSS_EXPIRATION_SCAN_COUNT - Expire BSS after number of scans
- *
- * If the BSS entry has not been seen in this many scans, it will be removed.
- * Value 1 means that the entry is removed after the first scan without the
- * BSSID being seen. Larger values can be used to avoid BSS entries
- * disappearing if they are not visible in every scan (e.g., low signal quality
- * or interference).
- */
-#define WPA_BSS_EXPIRATION_SCAN_COUNT 2
-
 #define WPA_BSS_FREQ_CHANGED_FLAG      BIT(0)
 #define WPA_BSS_SIGNAL_CHANGED_FLAG    BIT(1)
 #define WPA_BSS_PRIVACY_CHANGED_FLAG   BIT(2)
@@ -65,10 +46,19 @@ static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
        dl_list_del(&bss->list);
        dl_list_del(&bss->list_id);
        wpa_s->num_bss--;
-       wpa_printf(MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR " SSID '%s'",
-                  bss->id, MAC2STR(bss->bssid),
-                  wpa_ssid_txt(bss->ssid, bss->ssid_len));
+       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));
        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 */
        os_free(bss);
 }
 
@@ -112,6 +102,55 @@ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
 }
 
 
+static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+       struct wpa_ssid *ssid;
+
+       for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+               if (ssid->ssid == NULL || ssid->ssid_len == 0)
+                       continue;
+               if (ssid->ssid_len == bss->ssid_len &&
+                   os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0)
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+static int wpa_bss_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);
+                       return 0;
+               }
+       }
+
+       return -1;
+}
+
+
+static void wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
+{
+       /*
+        * Remove the oldest entry that does not match with any configured
+        * network.
+        */
+       if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
+               return;
+
+       /*
+        * Remove the oldest entry since no better candidate for removal was
+        * found.
+        */
+       wpa_bss_remove(wpa_s, dl_list_first(&wpa_s->bss,
+                                           struct wpa_bss, list));
+}
+
+
 static void wpa_bss_add(struct wpa_supplicant *wpa_s,
                        const u8 *ssid, size_t ssid_len,
                        struct wpa_scan_res *res)
@@ -133,14 +172,12 @@ static void wpa_bss_add(struct wpa_supplicant *wpa_s,
        dl_list_add_tail(&wpa_s->bss, &bss->list);
        dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
        wpa_s->num_bss++;
-       wpa_printf(MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR " SSID '%s'",
-                  bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
+       wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
+               " SSID '%s'",
+               bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
        wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
-       if (wpa_s->num_bss > wpa_s->conf->bss_max_count) {
-               /* Remove the oldest entry */
-               wpa_bss_remove(wpa_s, dl_list_first(&wpa_s->bss,
-                                                   struct wpa_bss, list));
-       }
+       if (wpa_s->num_bss > wpa_s->conf->bss_max_count)
+               wpa_bss_remove_oldest(wpa_s);
 }
 
 
@@ -187,8 +224,11 @@ static int are_ies_equal(const struct wpa_bss *old,
                new_ie_len = new_ie ? new_ie[1] + 2 : 0;
        }
 
-       ret = (old_ie_len == new_ie_len &&
-              os_memcmp(old_ie, new_ie, old_ie_len) == 0);
+       if (!old_ie || !new_ie)
+               ret = !old_ie && !new_ie;
+       else
+               ret = (old_ie_len == new_ie_len &&
+                      os_memcmp(old_ie, new_ie, old_ie_len) == 0);
 
        wpabuf_free(old_ie_buff);
        wpabuf_free(new_ie_buff);
@@ -317,29 +357,34 @@ static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
 void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
 {
        wpa_s->bss_update_idx++;
-       wpa_printf(MSG_DEBUG, "BSS: Start scan result update %u",
-                  wpa_s->bss_update_idx);
+       wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
+               wpa_s->bss_update_idx);
 }
 
 
 void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
                             struct wpa_scan_res *res)
 {
-       const u8 *ssid;
+       const u8 *ssid, *p2p;
        struct wpa_bss *bss;
 
        ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
        if (ssid == NULL) {
-               wpa_printf(MSG_DEBUG, "BSS: No SSID IE included for " MACSTR,
-                          MAC2STR(res->bssid));
+               wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
+                       MACSTR, MAC2STR(res->bssid));
                return;
        }
        if (ssid[1] > 32) {
-               wpa_printf(MSG_DEBUG, "BSS: Too long SSID IE included for "
-                          MACSTR, MAC2STR(res->bssid));
+               wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
+                       MACSTR, MAC2STR(res->bssid));
                return;
        }
 
+       p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
+       if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
+           os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
+               return; /* Skip P2P listen discovery results here */
+
        /* TODO: add option for ignoring BSSes we are not interested in
         * (to save memory) */
        bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
@@ -349,12 +394,14 @@ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
                wpa_bss_update(wpa_s, bss, res);
 }
 
+
 /*
  * 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)
+               const u8 *ssid)
 {
        struct wpa_bss *bss = NULL;
        struct wpa_bss *compare = NULL;
@@ -362,13 +409,12 @@ struct wpa_bss * wpa_bss_check_scan_res(struct wpa_supplicant *wpa_s,
                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)
+               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);
+                       if (compare->level > bss->level) {
+                               wpa_printf(MSG_DEBUG, "current signal level %d finded signal level %d",
+                                               bss->level, compare->level);
                                bss = compare;
                        }
                }
@@ -376,8 +422,7 @@ struct wpa_bss * wpa_bss_check_scan_res(struct wpa_supplicant *wpa_s,
 
        return bss;
 }
-
-
+#endif
 
 static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
                                    const struct scan_info *info)
@@ -435,18 +480,18 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
                        continue; /* expire only BSSes that were scanned */
                if (bss->last_update_idx < wpa_s->bss_update_idx)
                        bss->scan_miss_count++;
-               if (bss->scan_miss_count >= WPA_BSS_EXPIRATION_SCAN_COUNT) {
-                       wpa_printf(MSG_DEBUG, "BSS: Expire BSS %u due to no "
-                                  "match in scan", bss->id);
+               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);
                }
        }
 }
 
 
-static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
+void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
 {
-       struct wpa_supplicant *wpa_s = eloop_ctx;
        struct wpa_bss *bss, *n;
        struct os_time t;
 
@@ -454,19 +499,27 @@ static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
                return;
 
        os_get_time(&t);
-       t.sec -= WPA_BSS_EXPIRATION_AGE;
+       t.sec -= age;
 
        dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
                if (wpa_bss_in_use(wpa_s, bss))
                        continue;
 
                if (os_time_before(&bss->last_update, &t)) {
-                       wpa_printf(MSG_DEBUG, "BSS: Expire BSS %u due to age",
-                                  bss->id);
+                       wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Expire BSS %u due to "
+                               "age", bss->id);
                        wpa_bss_remove(wpa_s, bss);
                } else
                        break;
        }
+}
+
+
+static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+
+       wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age);
        eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
                               wpa_bss_timeout, wpa_s, NULL);
 }
@@ -482,14 +535,25 @@ 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)
 {
        struct wpa_bss *bss, *n;
-       eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
+
        if (wpa_s->bss.next == NULL)
                return; /* BSS table not yet initialized */
-       dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list)
+
+       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);
+       }
+}
+
+
+void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
+{
+       eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
+       wpa_bss_flush(wpa_s);
 }
 
 
@@ -497,7 +561,7 @@ struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
                                   const u8 *bssid)
 {
        struct wpa_bss *bss;
-       dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+       dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
                if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
                        return bss;
        }
index ed155f1..5dd8972 100644 (file)
@@ -23,6 +23,7 @@ struct wpa_scan_res;
 #define WPA_BSS_LEVEL_DBM              BIT(3)
 #define WPA_BSS_AUTHENTICATED          BIT(4)
 #define WPA_BSS_ASSOCIATED             BIT(5)
+#define WPA_BSS_ANQP_FETCH_TRIED       BIT(6)
 
 /**
  * struct wpa_bss - BSS table
@@ -65,6 +66,15 @@ struct wpa_bss {
        int level;
        u64 tsf;
        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 */
        size_t ie_len;
        size_t beacon_ie_len;
        /* followed by ie_len octets of IEs */
@@ -74,17 +84,21 @@ 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);
+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.
  */
-struct wpa_bss * wpa_bss_check_scan_res(struct wpa_supplicant *wpa_s,const u8 *ssid);
+#if defined TIZEN_EXT
+struct wpa_bss * wpa_bss_check_scan_res(struct wpa_supplicant *wpa_s, const u8 *ssid);
+#endif
 
-void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
-                       int new_scan);
 int wpa_bss_init(struct wpa_supplicant *wpa_s);
 void wpa_bss_deinit(struct wpa_supplicant *wpa_s);
+void wpa_bss_flush(struct wpa_supplicant *wpa_s);
+void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age);
 struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
                             const u8 *ssid, size_t ssid_len);
 struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
index 7e2a5b4..b446a3f 100644 (file)
@@ -15,6 +15,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "utils/uuid.h"
 #include "crypto/sha1.h"
 #include "rsn_supp/wpa.h"
 #include "eap_peer/eap.h"
@@ -283,6 +284,12 @@ static int wpa_config_parse_bssid(const struct parse_data *data,
                                  struct wpa_ssid *ssid, int line,
                                  const char *value)
 {
+       if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 ||
+           os_strcmp(value, "any") == 0) {
+               ssid->bssid_set = 0;
+               wpa_printf(MSG_MSGDUMP, "BSSID any");
+               return 0;
+       }
        if (hwaddr_aton(value, ssid->bssid)) {
                wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.",
                           line, value);
@@ -1492,9 +1499,9 @@ static const struct parse_data ssid_fields[] = {
        { STRe(pac_file) },
        { INTe(fragment_size) },
 #endif /* IEEE8021X_EAPOL */
-       { INT_RANGE(mode, 0, 2) },
+       { INT_RANGE(mode, 0, 4) },
        { INT_RANGE(proactive_key_caching, 0, 1) },
-       { INT_RANGE(disabled, 0, 1) },
+       { INT_RANGE(disabled, 0, 2) },
        { STR(id_str) },
 #ifdef CONFIG_IEEE80211W
        { INT_RANGE(ieee80211w, 0, 2) },
@@ -1687,6 +1694,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;
+
        ssid = config->ssid;
        while (ssid) {
                prev = ssid;
@@ -1715,14 +1723,45 @@ void wpa_config_free(struct wpa_config *config)
        os_free(config->model_name);
        os_free(config->model_number);
        os_free(config->serial_number);
-       os_free(config->device_type);
        os_free(config->config_methods);
+       os_free(config->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);
 }
 
 
 /**
+ * wpa_config_foreach_network - Iterate over each configured network
+ * @config: Configuration data from wpa_config_read()
+ * @func: Callback function to process each network
+ * @arg: Opaque argument to pass to callback function
+ *
+ * Iterate over the set of configured networks calling the specified
+ * function for each item. We guard against callbacks removing the
+ * supplied network.
+ */
+void wpa_config_foreach_network(struct wpa_config *config,
+                               void (*func)(void *, struct wpa_ssid *),
+                               void *arg)
+{
+       struct wpa_ssid *ssid, *next;
+
+       ssid = config->ssid;
+       while (ssid) {
+               next = ssid->next;
+               func(arg, ssid);
+               ssid = next;
+       }
+}
+
+
+/**
  * wpa_config_get_network - Get configured network based on id
  * @config: Configuration data from wpa_config_read()
  * @id: Unique network id to search for
@@ -1876,10 +1915,32 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
 }
 
 
+int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var,
+                         const char *value)
+{
+       size_t len;
+       char *buf;
+       int ret;
+
+       len = os_strlen(value);
+       buf = os_malloc(len + 3);
+       if (buf == NULL)
+               return -1;
+       buf[0] = '"';
+       os_memcpy(buf + 1, value, len);
+       buf[len + 1] = '"';
+       buf[len + 2] = '\0';
+       ret = wpa_config_set(ssid, var, buf, 0);
+       os_free(buf);
+       return ret;
+}
+
+
 /**
  * wpa_config_get_all - Get all options from network configuration
  * @ssid: Pointer to network configuration data
  * @get_keys: Determines if keys/passwords will be included in returned list
+ *     (if they may be exported)
  * Returns: %NULL terminated list of all set keys and their values in the form
  * of [key1, val1, key2, val2, ... , NULL]
  *
@@ -1895,6 +1956,8 @@ char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
        char **props;
        int fields_num;
 
+       get_keys = get_keys && ssid->export_keys;
+
        props = os_zalloc(sizeof(char *) * ((2 * NUM_SSID_FIELDS) + 1));
        if (!props)
                return NULL;
@@ -2131,7 +2194,13 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
        config->eapol_version = DEFAULT_EAPOL_VERSION;
        config->ap_scan = DEFAULT_AP_SCAN;
        config->fast_reauth = DEFAULT_FAST_REAUTH;
+       config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
+       config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
        config->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;
 
        if (ctrl_interface)
                config->ctrl_interface = os_strdup(ctrl_interface);
@@ -2165,3 +2234,308 @@ void wpa_config_debug_dump_networks(struct wpa_config *config)
        }
 }
 #endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+struct global_parse_data {
+       char *name;
+       int (*parser)(const struct global_parse_data *data,
+                     struct wpa_config *config, int line, const char *value);
+       void *param1, *param2, *param3;
+       unsigned int changed_flag;
+};
+
+
+static int wpa_global_config_parse_int(const struct global_parse_data *data,
+                                      struct wpa_config *config, int line,
+                                      const char *pos)
+{
+       int *dst;
+       dst = (int *) (((u8 *) config) + (long) data->param1);
+       *dst = atoi(pos);
+       wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
+
+       if (data->param2 && *dst < (long) data->param2) {
+               wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
+                          "min_value=%ld)", line, data->name, *dst,
+                          (long) data->param2);
+               *dst = (long) data->param2;
+               return -1;
+       }
+
+       if (data->param3 && *dst > (long) data->param3) {
+               wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
+                          "max_value=%ld)", line, data->name, *dst,
+                          (long) data->param3);
+               *dst = (long) data->param3;
+               return -1;
+       }
+
+       return 0;
+}
+
+
+static int wpa_global_config_parse_str(const struct global_parse_data *data,
+                                      struct wpa_config *config, int line,
+                                      const char *pos)
+{
+       size_t len;
+       char **dst, *tmp;
+
+       len = os_strlen(pos);
+       if (data->param2 && len < (size_t) data->param2) {
+               wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
+                          "min_len=%ld)", line, data->name,
+                          (unsigned long) len, (long) data->param2);
+               return -1;
+       }
+
+       if (data->param3 && len > (size_t) data->param3) {
+               wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
+                          "max_len=%ld)", line, data->name,
+                          (unsigned long) len, (long) data->param3);
+               return -1;
+       }
+
+       tmp = os_strdup(pos);
+       if (tmp == NULL)
+               return -1;
+
+       dst = (char **) (((u8 *) config) + (long) data->param1);
+       os_free(*dst);
+       *dst = tmp;
+       wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst);
+
+       return 0;
+}
+
+
+static int wpa_config_process_country(const struct global_parse_data *data,
+                                     struct wpa_config *config, int line,
+                                     const char *pos)
+{
+       if (!pos[0] || !pos[1]) {
+               wpa_printf(MSG_DEBUG, "Invalid country set");
+               return -1;
+       }
+       config->country[0] = pos[0];
+       config->country[1] = pos[1];
+       wpa_printf(MSG_DEBUG, "country='%c%c'",
+                  config->country[0], config->country[1]);
+       return 0;
+}
+
+
+static int wpa_config_process_load_dynamic_eap(
+       const struct global_parse_data *data, struct wpa_config *config,
+       int line, const char *so)
+{
+       int ret;
+       wpa_printf(MSG_DEBUG, "load_dynamic_eap=%s", so);
+       ret = eap_peer_method_load(so);
+       if (ret == -2) {
+               wpa_printf(MSG_DEBUG, "This EAP type was already loaded - not "
+                          "reloading.");
+       } else if (ret) {
+               wpa_printf(MSG_ERROR, "Line %d: Failed to load dynamic EAP "
+                          "method '%s'.", line, so);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+#ifdef CONFIG_WPS
+
+static int wpa_config_process_uuid(const struct global_parse_data *data,
+                                  struct wpa_config *config, int line,
+                                  const char *pos)
+{
+       char buf[40];
+       if (uuid_str2bin(pos, config->uuid)) {
+               wpa_printf(MSG_ERROR, "Line %d: invalid UUID", line);
+               return -1;
+       }
+       uuid_bin2str(config->uuid, buf, sizeof(buf));
+       wpa_printf(MSG_DEBUG, "uuid=%s", buf);
+       return 0;
+}
+
+
+static int wpa_config_process_device_type(
+       const struct global_parse_data *data,
+       struct wpa_config *config, int line, const char *pos)
+{
+       return wps_dev_type_str2bin(pos, config->device_type);
+}
+
+
+static int wpa_config_process_os_version(const struct global_parse_data *data,
+                                        struct wpa_config *config, int line,
+                                        const char *pos)
+{
+       if (hexstr2bin(pos, config->os_version, 4)) {
+               wpa_printf(MSG_ERROR, "Line %d: invalid os_version", line);
+               return -1;
+       }
+       wpa_printf(MSG_DEBUG, "os_version=%08x",
+                  WPA_GET_BE32(config->os_version));
+       return 0;
+}
+
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+static int wpa_config_process_sec_device_type(
+       const struct global_parse_data *data,
+       struct wpa_config *config, int line, const char *pos)
+{
+       int idx;
+
+       if (config->num_sec_device_types >= MAX_SEC_DEVICE_TYPES) {
+               wpa_printf(MSG_ERROR, "Line %d: too many sec_device_type "
+                          "items", line);
+               return -1;
+       }
+
+       idx = config->num_sec_device_types;
+
+       if (wps_dev_type_str2bin(pos, config->sec_device_type[idx]))
+               return -1;
+
+       config->num_sec_device_types++;
+       return 0;
+}
+#endif /* CONFIG_P2P */
+
+
+static int wpa_config_process_hessid(
+       const struct global_parse_data *data,
+       struct wpa_config *config, int line, const char *pos)
+{
+       if (hwaddr_aton2(pos, config->hessid) < 0) {
+               wpa_printf(MSG_ERROR, "Line %d: Invalid hessid '%s'",
+                          line, pos);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+#ifdef OFFSET
+#undef OFFSET
+#endif /* OFFSET */
+/* OFFSET: Get offset of a variable within the wpa_config structure */
+#define OFFSET(v) ((void *) &((struct wpa_config *) 0)->v)
+
+#define FUNC(f) #f, wpa_config_process_ ## f, OFFSET(f), NULL, NULL
+#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL
+#define _INT(f) #f, wpa_global_config_parse_int, OFFSET(f)
+#define INT(f) _INT(f), NULL, NULL
+#define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max
+#define _STR(f) #f, wpa_global_config_parse_str, OFFSET(f)
+#define STR(f) _STR(f), NULL, NULL
+#define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
+
+static const struct global_parse_data global_fields[] = {
+#ifdef CONFIG_CTRL_IFACE
+       { STR(ctrl_interface), 0 },
+       { STR(ctrl_interface_group), 0 } /* deprecated */,
+#endif /* CONFIG_CTRL_IFACE */
+       { INT_RANGE(eapol_version, 1, 2), 0 },
+       { INT(ap_scan), 0 },
+       { INT(fast_reauth), 0 },
+       { STR(opensc_engine_path), 0 },
+       { STR(pkcs11_engine_path), 0 },
+       { STR(pkcs11_module_path), 0 },
+       { STR(driver_param), 0 },
+       { INT(dot11RSNAConfigPMKLifetime), 0 },
+       { INT(dot11RSNAConfigPMKReauthThreshold), 0 },
+       { INT(dot11RSNAConfigSATimeout), 0 },
+#ifndef CONFIG_NO_CONFIG_WRITE
+       { INT(update_config), 0 },
+#endif /* CONFIG_NO_CONFIG_WRITE */
+       { FUNC_NO_VAR(load_dynamic_eap), 0 },
+#ifdef CONFIG_WPS
+       { FUNC(uuid), CFG_CHANGED_UUID },
+       { STR_RANGE(device_name, 0, 32), CFG_CHANGED_DEVICE_NAME },
+       { STR_RANGE(manufacturer, 0, 64), CFG_CHANGED_WPS_STRING },
+       { STR_RANGE(model_name, 0, 32), CFG_CHANGED_WPS_STRING },
+       { STR_RANGE(model_number, 0, 32), CFG_CHANGED_WPS_STRING },
+       { STR_RANGE(serial_number, 0, 32), CFG_CHANGED_WPS_STRING },
+       { FUNC(device_type), CFG_CHANGED_DEVICE_TYPE },
+       { FUNC(os_version), CFG_CHANGED_OS_VERSION },
+       { STR(config_methods), CFG_CHANGED_CONFIG_METHODS },
+       { INT_RANGE(wps_cred_processing, 0, 2), 0 },
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+       { FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE },
+       { INT(p2p_listen_reg_class), 0 },
+       { INT(p2p_listen_channel), 0 },
+       { INT(p2p_oper_reg_class), 0 },
+       { INT(p2p_oper_channel), 0 },
+       { INT_RANGE(p2p_go_intent, 0, 15), 0 },
+       { STR(p2p_ssid_postfix), CFG_CHANGED_P2P_SSID_POSTFIX },
+       { INT_RANGE(persistent_reconnect, 0, 1), 0 },
+       { INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
+       { INT(p2p_group_idle), 0 },
+#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(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 },
+       { INT_RANGE(interworking, 0, 1), 0 },
+       { FUNC(hessid), 0 },
+       { INT_RANGE(access_network_type, 0, 15), 0 }
+};
+
+#undef FUNC
+#undef _INT
+#undef INT
+#undef INT_RANGE
+#undef _STR
+#undef STR
+#undef STR_RANGE
+#define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
+
+
+int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
+{
+       size_t i;
+       int ret = 0;
+
+       for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
+               const struct global_parse_data *field = &global_fields[i];
+               size_t flen = os_strlen(field->name);
+               if (os_strncmp(pos, field->name, flen) != 0 ||
+                   pos[flen] != '=')
+                       continue;
+
+               if (field->parser(field, config, line, pos + flen + 1)) {
+                       wpa_printf(MSG_ERROR, "Line %d: failed to "
+                                  "parse '%s'.", line, pos);
+                       ret = -1;
+               }
+               config->changed_parameters |= field->changed_flag;
+               break;
+       }
+       if (i == NUM_GLOBAL_FIELDS) {
+               if (line < 0)
+                       return -1;
+               wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.",
+                          line, pos);
+               ret = -1;
+       }
+
+       return ret;
+}
index 754e4be..f9e5043 100644 (file)
 #define DEFAULT_AP_SCAN 1
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 #define DEFAULT_FAST_REAUTH 1
+#define DEFAULT_P2P_GO_INTENT 7
+#define DEFAULT_P2P_INTRA_BSS 1
 #define DEFAULT_BSS_MAX_COUNT 200
+#define DEFAULT_BSS_EXPIRATION_AGE 180
+#define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2
+#define DEFAULT_MAX_NUM_STA 128
+#define DEFAULT_ACCESS_NETWORK_TYPE 15
 
 #include "config_ssid.h"
-
+#include "wps/wps.h"
+
+
+#define CFG_CHANGED_DEVICE_NAME BIT(0)
+#define CFG_CHANGED_CONFIG_METHODS BIT(1)
+#define CFG_CHANGED_DEVICE_TYPE BIT(2)
+#define CFG_CHANGED_OS_VERSION BIT(3)
+#define CFG_CHANGED_UUID BIT(4)
+#define CFG_CHANGED_COUNTRY BIT(5)
+#define CFG_CHANGED_SEC_DEVICE_TYPE BIT(6)
+#define CFG_CHANGED_P2P_SSID_POSTFIX BIT(7)
+#define CFG_CHANGED_WPS_STRING BIT(8)
+#define CFG_CHANGED_P2P_INTRA_BSS BIT(9)
+#define CFG_CHANGED_VENDOR_EXTENSION BIT(10)
+#define CFG_CHANGED_P2P_LISTEN_CHANNEL BIT(11)
+#define CFG_CHANGED_P2P_OPER_CHANNEL BIT(12)
 
 /**
  * struct wpa_config - wpa_supplicant configuration data
@@ -103,7 +124,7 @@ struct wpa_config {
         * If this is specified, %wpa_supplicant will open a control interface
         * that is available for external programs to manage %wpa_supplicant.
         * The meaning of this string depends on which control interface
-        * mechanism is used. For all cases, the existance of this parameter
+        * mechanism is used. For all cases, the existence of this parameter
         * in configuration is used to determine whether the control interface
         * is enabled.
         *
@@ -285,26 +306,19 @@ struct wpa_config {
 
        /**
         * device_type - Primary Device Type (WPS)
-        * Used format: categ-OUI-subcateg
-        * categ = Category as an integer value
-        * OUI = OUI and type octet as a 4-octet hex-encoded value;
-        *      0050F204 for default WPS OUI
-        * subcateg = OUI-specific Sub Category as an integer value
-        * Examples:
-        *   1-0050F204-1 (Computer / PC)
-        *   1-0050F204-2 (Computer / Server)
-        *   5-0050F204-1 (Storage / NAS)
-        *   6-0050F204-1 (Network Infrastructure / AP)
         */
-       char *device_type;
+       u8 device_type[WPS_DEV_TYPE_LEN];
 
        /**
         * config_methods - Config Methods
         *
         * This is a space-separated list of supported WPS configuration
-        * methods. For example, "label display push_button keypad".
+        * methods. For example, "label virtual_display virtual_push_button
+        * keypad".
         * Available methods: usba ethernet label display ext_nfc_token
-        * int_nfc_token nfc_interface push_button keypad.
+        * int_nfc_token nfc_interface push_button keypad
+        * virtual_display physical_display
+        * virtual_push_button physical_push_button.
         */
        char *config_methods;
 
@@ -333,18 +347,143 @@ struct wpa_config {
         */
        int wps_cred_processing;
 
+#define MAX_SEC_DEVICE_TYPES 5
+       /**
+        * sec_device_types - Secondary Device Types (P2P)
+        */
+       u8 sec_device_type[MAX_SEC_DEVICE_TYPES][WPS_DEV_TYPE_LEN];
+       int num_sec_device_types;
+
+       int p2p_listen_reg_class;
+       int p2p_listen_channel;
+       int p2p_oper_reg_class;
+       int p2p_oper_channel;
+       int p2p_go_intent;
+       char *p2p_ssid_postfix;
+       int persistent_reconnect;
+       int p2p_intra_bss;
+
+#define MAX_WPS_VENDOR_EXT 10
+       /**
+        * wps_vendor_ext - Vendor extension attributes in WPS
+        */
+       struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXT];
+
+       /**
+        * p2p_group_idle - Maximum idle time in seconds for P2P group
+        *
+        * This value controls how long a P2P group is maintained after there
+        * is no other members in the group. As a GO, this means no associated
+        * stations in the group. As a P2P client, this means no GO seen in
+        * scan results. The maximum idle time is specified in seconds with 0
+        * indicating no time limit, i.e., the P2P group remains in active
+        * state indefinitely until explicitly removed. As a P2P client, the
+        * maximum idle time of P2P_MAX_CLIENT_IDLE seconds is enforced, i.e.,
+        * this parameter is mainly meant for GO use and for P2P client, it can
+        * only be used to reduce the default timeout to smaller value.
+        */
+       unsigned int p2p_group_idle;
+
        /**
         * bss_max_count - Maximum number of BSS entries to keep in memory
         */
        unsigned int bss_max_count;
 
        /**
+        * bss_expiration_age - BSS entry age after which it can be expired
+        *
+        * This value controls the time in seconds after which a BSS entry
+        * gets removed if it has not been updated or is not in use.
+        */
+       unsigned int bss_expiration_age;
+
+       /**
+        * bss_expiration_scan_count - Expire BSS after number of scans
+        *
+        * If the BSS entry has not been seen in this many scans, it will be
+        * removed. A value of 1 means that entry is removed after the first
+        * scan in which the BSSID is not seen. Larger values can be used
+        * to avoid BSS entries disappearing if they are not visible in
+        * every scan (e.g., low signal quality or interference).
+        */
+       unsigned int bss_expiration_scan_count;
+
+       /**
         * filter_ssids - SSID-based scan result filtering
         *
         *   0 = do not filter scan results
         *   1 = only include configured SSIDs in scan results/BSS table
         */
        int filter_ssids;
+
+       /**
+        * max_num_sta - Maximum number of STAs in an AP/P2P GO
+        */
+       unsigned int max_num_sta;
+
+       /**
+        * changed_parameters - Bitmap of changed parameters since last update
+        */
+       unsigned int changed_parameters;
+
+       /**
+        * disassoc_low_ack - Disassocicate stations with massive packet loss
+        */
+       int disassoc_low_ack;
+
+       /**
+        * interworking - Whether Interworking (IEEE 802.11u) is enabled
+        */
+       int interworking;
+
+       /**
+        * access_network_type - Access Network Type
+        *
+        * When Interworking is enabled, scans will be limited to APs that
+        * advertise the specified Access Network Type (0..15; with 15
+        * indicating wildcard match).
+        */
+       int access_network_type;
+
+       /**
+        * hessid - Homogenous ESS identifier
+        *
+        * If this is set (any octet is non-zero), scans will be used to
+        * request response only from BSSes belonging to the specified
+        * Homogeneous ESS. This is used only if interworking is enabled.
+        */
+       u8 hessid[ETH_ALEN];
+
+       /**
+        * home_realm - Home Realm for Interworking
+        */
+       char *home_realm;
+
+       /**
+        * home_username - Username for Interworking network selection
+        */
+       char *home_username;
+
+       /**
+        * home_password - Password for Interworking network selection
+        */
+       char *home_password;
+
+       /**
+        * home_ca_cert - CA certificate for Interworking network selection
+        */
+       char *home_ca_cert;
+
+       /**
+        * home_imsi - IMSI in <MCC> | <MNC> | '-' | <MSIN> format
+        */
+       char *home_imsi;
+
+       /**
+        * home_milenage - Milenage parameters for SIM/USIM simulator in
+        *      <Ki>:<OPc>:<SQN> format
+        */
+       char *home_milenage;
 };
 
 
@@ -352,12 +491,17 @@ struct wpa_config {
 
 void wpa_config_free(struct wpa_config *ssid);
 void wpa_config_free_ssid(struct wpa_ssid *ssid);
+void wpa_config_foreach_network(struct wpa_config *config,
+                               void (*func)(void *, struct wpa_ssid *),
+                               void *arg);
 struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id);
 struct wpa_ssid * wpa_config_add_network(struct wpa_config *config);
 int wpa_config_remove_network(struct wpa_config *config, int id);
 void wpa_config_set_network_defaults(struct wpa_ssid *ssid);
 int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
                   int line);
+int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var,
+                         const char *value);
 char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys);
 char * wpa_config_get(struct wpa_ssid *ssid, const char *var);
 char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var);
@@ -381,6 +525,10 @@ void wpa_config_debug_dump_networks(struct wpa_config *config);
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
 
+/* Prototypes for common functions from config.c */
+int wpa_config_process_global(struct wpa_config *config, char *pos, int line);
+
+
 /* Prototypes for backend specific functions from the selected config_*.c */
 
 /**
index 5f07045..8ea03ab 100644 (file)
@@ -22,7 +22,6 @@
 #include "config.h"
 #include "base64.h"
 #include "uuid.h"
-#include "eap_peer/eap_methods.h"
 
 
 /**
@@ -105,9 +104,7 @@ static int wpa_config_validate_network(struct wpa_ssid *ssid, int line)
                wpa_config_update_psk(ssid);
        }
 
-       if ((ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
-                              WPA_KEY_MGMT_PSK_SHA256)) &&
-           !ssid->psk_set) {
+       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++;
@@ -270,238 +267,6 @@ static int wpa_config_process_blob(struct wpa_config *config, FILE *f,
 #endif /* CONFIG_NO_CONFIG_BLOBS */
 
 
-struct global_parse_data {
-       char *name;
-       int (*parser)(const struct global_parse_data *data,
-                     struct wpa_config *config, int line, const char *value);
-       void *param1, *param2, *param3;
-};
-
-
-static int wpa_config_parse_int(const struct global_parse_data *data,
-                               struct wpa_config *config, int line,
-                               const char *pos)
-{
-       int *dst;
-       dst = (int *) (((u8 *) config) + (long) data->param1);
-       *dst = atoi(pos);
-       wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
-
-       if (data->param2 && *dst < (long) data->param2) {
-               wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
-                          "min_value=%ld)", line, data->name, *dst,
-                          (long) data->param2);
-               *dst = (long) data->param2;
-               return -1;
-       }
-
-       if (data->param3 && *dst > (long) data->param3) {
-               wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
-                          "max_value=%ld)", line, data->name, *dst,
-                          (long) data->param3);
-               *dst = (long) data->param3;
-               return -1;
-       }
-
-       return 0;
-}
-
-
-static int wpa_config_parse_str(const struct global_parse_data *data,
-                               struct wpa_config *config, int line,
-                               const char *pos)
-{
-       size_t len;
-       char **dst, *tmp;
-
-       len = os_strlen(pos);
-       if (data->param2 && len < (size_t) data->param2) {
-               wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
-                          "min_len=%ld)", line, data->name,
-                          (unsigned long) len, (long) data->param2);
-               return -1;
-       }
-
-       if (data->param3 && len > (size_t) data->param3) {
-               wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
-                          "max_len=%ld)", line, data->name,
-                          (unsigned long) len, (long) data->param3);
-               return -1;
-       }
-
-       tmp = os_strdup(pos);
-       if (tmp == NULL)
-               return -1;
-
-       dst = (char **) (((u8 *) config) + (long) data->param1);
-       os_free(*dst);
-       *dst = tmp;
-       wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst);
-
-       return 0;
-}
-
-
-static int wpa_config_process_country(const struct global_parse_data *data,
-                                     struct wpa_config *config, int line,
-                                     const char *pos)
-{
-       if (!pos[0] || !pos[1]) {
-               wpa_printf(MSG_DEBUG, "Invalid country set");
-               return -1;
-       }
-       config->country[0] = pos[0];
-       config->country[1] = pos[1];
-       wpa_printf(MSG_DEBUG, "country='%c%c'",
-                  config->country[0], config->country[1]);
-       return 0;
-}
-
-
-static int wpa_config_process_load_dynamic_eap(
-       const struct global_parse_data *data, struct wpa_config *config,
-       int line, const char *so)
-{
-       int ret;
-       wpa_printf(MSG_DEBUG, "load_dynamic_eap=%s", so);
-       ret = eap_peer_method_load(so);
-       if (ret == -2) {
-               wpa_printf(MSG_DEBUG, "This EAP type was already loaded - not "
-                          "reloading.");
-       } else if (ret) {
-               wpa_printf(MSG_ERROR, "Line %d: Failed to load dynamic EAP "
-                          "method '%s'.", line, so);
-               return -1;
-       }
-
-       return 0;
-}
-
-
-#ifdef CONFIG_WPS
-
-static int wpa_config_process_uuid(const struct global_parse_data *data,
-                                  struct wpa_config *config, int line,
-                                  const char *pos)
-{
-       char buf[40];
-       if (uuid_str2bin(pos, config->uuid)) {
-               wpa_printf(MSG_ERROR, "Line %d: invalid UUID", line);
-               return -1;
-       }
-       uuid_bin2str(config->uuid, buf, sizeof(buf));
-       wpa_printf(MSG_DEBUG, "uuid=%s", buf);
-       return 0;
-}
-
-
-static int wpa_config_process_os_version(const struct global_parse_data *data,
-                                        struct wpa_config *config, int line,
-                                        const char *pos)
-{
-       if (hexstr2bin(pos, config->os_version, 4)) {
-               wpa_printf(MSG_ERROR, "Line %d: invalid os_version", line);
-               return -1;
-       }
-       wpa_printf(MSG_DEBUG, "os_version=%08x",
-                  WPA_GET_BE32(config->os_version));
-       return 0;
-}
-
-#endif /* CONFIG_WPS */
-
-
-#ifdef OFFSET
-#undef OFFSET
-#endif /* OFFSET */
-/* OFFSET: Get offset of a variable within the wpa_config structure */
-#define OFFSET(v) ((void *) &((struct wpa_config *) 0)->v)
-
-#define FUNC(f) #f, wpa_config_process_ ## f, OFFSET(f), NULL, NULL
-#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL
-#define _INT(f) #f, wpa_config_parse_int, OFFSET(f)
-#define INT(f) _INT(f), NULL, NULL
-#define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max
-#define _STR(f) #f, wpa_config_parse_str, OFFSET(f)
-#define STR(f) _STR(f), NULL, NULL
-#define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
-
-static const struct global_parse_data global_fields[] = {
-#ifdef CONFIG_CTRL_IFACE
-       { STR(ctrl_interface) },
-       { STR(ctrl_interface_group) } /* deprecated */,
-#endif /* CONFIG_CTRL_IFACE */
-       { INT_RANGE(eapol_version, 1, 2) },
-       { INT(ap_scan) },
-       { INT(fast_reauth) },
-       { STR(opensc_engine_path) },
-       { STR(pkcs11_engine_path) },
-       { STR(pkcs11_module_path) },
-       { STR(driver_param) },
-       { INT(dot11RSNAConfigPMKLifetime) },
-       { INT(dot11RSNAConfigPMKReauthThreshold) },
-       { INT(dot11RSNAConfigSATimeout) },
-#ifndef CONFIG_NO_CONFIG_WRITE
-       { INT(update_config) },
-#endif /* CONFIG_NO_CONFIG_WRITE */
-       { FUNC_NO_VAR(load_dynamic_eap) },
-#ifdef CONFIG_WPS
-       { FUNC(uuid) },
-       { STR_RANGE(device_name, 0, 32) },
-       { STR_RANGE(manufacturer, 0, 64) },
-       { STR_RANGE(model_name, 0, 32) },
-       { STR_RANGE(model_number, 0, 32) },
-       { STR_RANGE(serial_number, 0, 32) },
-       { STR(device_type) },
-       { FUNC(os_version) },
-       { STR(config_methods) },
-       { INT_RANGE(wps_cred_processing, 0, 2) },
-#endif /* CONFIG_WPS */
-       { FUNC(country) },
-       { INT(bss_max_count) },
-       { INT_RANGE(filter_ssids, 0, 1) }
-};
-
-#undef FUNC
-#undef _INT
-#undef INT
-#undef INT_RANGE
-#undef _STR
-#undef STR
-#undef STR_RANGE
-#define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
-
-
-static int wpa_config_process_global(struct wpa_config *config, char *pos,
-                                    int line)
-{
-       size_t i;
-       int ret = 0;
-
-       for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
-               const struct global_parse_data *field = &global_fields[i];
-               size_t flen = os_strlen(field->name);
-               if (os_strncmp(pos, field->name, flen) != 0 ||
-                   pos[flen] != '=')
-                       continue;
-
-               if (field->parser(field, config, line, pos + flen + 1)) {
-                       wpa_printf(MSG_ERROR, "Line %d: failed to "
-                                  "parse '%s'.", line, pos);
-                       ret = -1;
-               }
-               break;
-       }
-       if (i == NUM_GLOBAL_FIELDS) {
-               wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.",
-                          line, pos);
-               ret = -1;
-       }
-
-       return ret;
-}
-
-
 struct wpa_config * wpa_config_read(const char *name)
 {
        FILE *f;
@@ -564,11 +329,13 @@ struct wpa_config * wpa_config_read(const char *name)
        config->ssid = head;
        wpa_config_debug_dump_networks(config);
 
+#ifndef WPA_IGNORE_CONFIG_ERRORS
        if (errors) {
                wpa_config_free(config);
                config = NULL;
                head = NULL;
        }
+#endif /* WPA_IGNORE_CONFIG_ERRORS */
 
        return config;
 }
@@ -876,8 +643,13 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
                fprintf(f, "model_number=%s\n", config->model_number);
        if (config->serial_number)
                fprintf(f, "serial_number=%s\n", config->serial_number);
-       if (config->device_type)
-               fprintf(f, "device_type=%s\n", config->device_type);
+       {
+               char _buf[WPS_DEV_TYPE_BUFSIZE], *buf;
+               buf = wps_dev_type_bin2str(config->device_type,
+                                          _buf, sizeof(_buf));
+               if (os_strcmp(buf, "0-00000000-0") != 0)
+                       fprintf(f, "device_type=%s\n", buf);
+       }
        if (WPA_GET_BE32(config->os_version))
                fprintf(f, "os_version=%08x\n",
                        WPA_GET_BE32(config->os_version));
@@ -887,14 +659,70 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
                fprintf(f, "wps_cred_processing=%d\n",
                        config->wps_cred_processing);
 #endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+       if (config->p2p_listen_reg_class)
+               fprintf(f, "p2p_listen_reg_class=%u\n",
+                       config->p2p_listen_reg_class);
+       if (config->p2p_listen_channel)
+               fprintf(f, "p2p_listen_channel=%u\n",
+                       config->p2p_listen_channel);
+       if (config->p2p_oper_reg_class)
+               fprintf(f, "p2p_oper_reg_class=%u\n",
+                       config->p2p_oper_reg_class);
+       if (config->p2p_oper_channel)
+               fprintf(f, "p2p_oper_channel=%u\n", config->p2p_oper_channel);
+       if (config->p2p_go_intent != DEFAULT_P2P_GO_INTENT)
+               fprintf(f, "p2p_go_intent=%u\n", config->p2p_go_intent);
+       if (config->p2p_ssid_postfix)
+               fprintf(f, "p2p_ssid_postfix=%s\n", config->p2p_ssid_postfix);
+       if (config->persistent_reconnect)
+               fprintf(f, "persistent_reconnect=%u\n",
+                       config->persistent_reconnect);
+       if (config->p2p_intra_bss != DEFAULT_P2P_INTRA_BSS)
+               fprintf(f, "p2p_intra_bss=%u\n", config->p2p_intra_bss);
+       if (config->p2p_group_idle)
+               fprintf(f, "p2p_group_idle=%u\n", config->p2p_group_idle);
+#endif /* CONFIG_P2P */
        if (config->country[0] && config->country[1]) {
                fprintf(f, "country=%c%c\n",
                        config->country[0], config->country[1]);
        }
        if (config->bss_max_count != DEFAULT_BSS_MAX_COUNT)
                fprintf(f, "bss_max_count=%u\n", config->bss_max_count);
+       if (config->bss_expiration_age != DEFAULT_BSS_EXPIRATION_AGE)
+               fprintf(f, "bss_expiration_age=%u\n",
+                       config->bss_expiration_age);
+       if (config->bss_expiration_scan_count !=
+           DEFAULT_BSS_EXPIRATION_SCAN_COUNT)
+               fprintf(f, "bss_expiration_scan_count=%u\n",
+                       config->bss_expiration_scan_count);
        if (config->filter_ssids)
                fprintf(f, "filter_ssids=%d\n", config->filter_ssids);
+       if (config->max_num_sta != DEFAULT_MAX_NUM_STA)
+               fprintf(f, "max_num_sta=%u\n", config->max_num_sta);
+       if (config->disassoc_low_ack)
+               fprintf(f, "disassoc_low_ack=%u\n", config->disassoc_low_ack);
+#ifdef CONFIG_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))
+               fprintf(f, "hessid=" MACSTR "\n", MAC2STR(config->hessid));
+       if (config->access_network_type != DEFAULT_ACCESS_NETWORK_TYPE)
+               fprintf(f, "access_network_type=%d\n",
+                       config->access_network_type);
+#endif /* CONFIG_INTERWORKING */
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
@@ -921,8 +749,11 @@ int wpa_config_write(const char *name, struct wpa_config *config)
        wpa_config_write_global(f, config);
 
        for (ssid = config->ssid; ssid; ssid = ssid->next) {
-               if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
-                       continue; /* do not save temporary WPS networks */
+               if (ssid->key_mgmt == WPA_KEY_MGMT_WPS || ssid->temporary)
+                       continue; /* do not save temporary networks */
+               if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
+                   !ssid->passphrase)
+                       continue; /* do not save invalid network */
                fprintf(f, "\nnetwork={\n");
                wpa_config_write_network(f, ssid);
                fprintf(f, "}\n");
index 25e87aa..8419f43 100644 (file)
@@ -109,6 +109,9 @@ struct wpa_ssid {
         *
         * If set, this network block is used only when associating with the AP
         * using the configured BSSID
+        *
+        * If this is a persistent P2P group (disabled == 2), this is the GO
+        * Device Address.
         */
        u8 bssid[ETH_ALEN];
 
@@ -273,6 +276,11 @@ struct wpa_ssid {
         *
         * 2 = AP (access point)
         *
+        * 3 = P2P Group Owner (can be set in the configuration file)
+        *
+        * 4 = P2P Group Formation (used internally; not in configuration
+        * files)
+        *
         * Note: IBSS can only be used with key_mgmt NONE (plaintext and
         * static WEP) and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). In
         * addition, ap_scan has to be set to 2 for IBSS. WPA-None requires
@@ -284,6 +292,8 @@ struct wpa_ssid {
                WPAS_MODE_INFRA = 0,
                WPAS_MODE_IBSS = 1,
                WPAS_MODE_AP = 2,
+               WPAS_MODE_P2P_GO = 3,
+               WPAS_MODE_P2P_GROUP_FORMATION = 4,
        } mode;
 
        /**
@@ -292,6 +302,8 @@ struct wpa_ssid {
         * 0 = this network can be used (default).
         * 1 = this network block is disabled (can be enabled through
         * ctrl_iface, e.g., with wpa_cli or wpa_gui).
+        * 2 = this network block includes parameters for a persistent P2P
+        * group (can be used with P2P ctrl_iface commands)
         */
        int disabled;
 
@@ -373,6 +385,29 @@ struct wpa_ssid {
         * considered when selecting a BSS.
         */
        int *freq_list;
+
+       /**
+        * p2p_group - Network generated as a P2P group (used internally)
+        */
+       int p2p_group;
+
+       /**
+        * p2p_persistent_group - Whether this is a persistent group
+        */
+       int p2p_persistent_group;
+
+       /**
+        * temporary - Whether this network is temporary and not to be saved
+        */
+       int temporary;
+
+       /**
+        * export_keys - Whether keys may be exported
+        *
+        * This attribute will be set when keys are determined through
+        * WPS or similar so that they may be exported.
+        */
+       int export_keys;
 };
 
 #endif /* CONFIG_SSID_H */
index 9a7825a..5fb2580 100644 (file)
@@ -247,8 +247,13 @@ static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
                hk, TEXT("model_name"));
        config->serial_number = wpa_config_read_reg_string(
                hk, TEXT("serial_number"));
-       config->device_type = wpa_config_read_reg_string(
-               hk, TEXT("device_type"));
+       {
+               char *t = wpa_config_read_reg_string(
+                       hk, TEXT("device_type"));
+               if (t && wps_dev_type_str2bin(t, config->device_type))
+                       errors++;
+               os_free(t);
+       }
        config->config_methods = wpa_config_read_reg_string(
                hk, TEXT("config_methods"));
        if (wpa_config_read_global_os_version(config, hk))
@@ -256,11 +261,21 @@ static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
        wpa_config_read_reg_dword(hk, TEXT("wps_cred_processing"),
                                  &config->wps_cred_processing);
 #endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+       config->p2p_ssid_postfix = wpa_config_read_reg_string(
+               hk, TEXT("p2p_ssid_postfix"));
+       wpa_config_read_reg_dword(hk, TEXT("p2p_group_idle"),
+                                 (int *) &config->p2p_group_idle);
+#endif /* CONFIG_P2P */
 
        wpa_config_read_reg_dword(hk, TEXT("bss_max_count"),
                                  (int *) &config->bss_max_count);
        wpa_config_read_reg_dword(hk, TEXT("filter_ssids"),
                                  &config->filter_ssids);
+       wpa_config_read_reg_dword(hk, TEXT("max_num_sta"),
+                                 (int *) &config->max_num_sta);
+       wpa_config_read_reg_dword(hk, TEXT("disassoc_low_ack"),
+                                 (int *) &config->disassoc_low_ack);
 
        return errors ? -1 : 0;
 }
@@ -335,9 +350,7 @@ static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw,
                wpa_config_update_psk(ssid);
        }
 
-       if ((ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
-                              WPA_KEY_MGMT_PSK_SHA256)) &&
-           !ssid->psk_set) {
+       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);
@@ -575,7 +588,12 @@ static int wpa_config_write_global(struct wpa_config *config, HKEY hk)
        wpa_config_write_reg_string(hk, "model_number", config->model_number);
        wpa_config_write_reg_string(hk, "serial_number",
                                    config->serial_number);
-       wpa_config_write_reg_string(hk, "device_type", config->device_type);
+       {
+               char _buf[WPS_DEV_TYPE_BUFSIZE], *buf;
+               buf = wps_dev_type_bin2str(config->device_type,
+                                          _buf, sizeof(_buf));
+               wpa_config_write_reg_string(hk, "device_type", buf);
+       }
        wpa_config_write_reg_string(hk, "config_methods",
                                    config->config_methods);
        if (WPA_GET_BE32(config->os_version)) {
@@ -587,12 +605,22 @@ static int wpa_config_write_global(struct wpa_config *config, HKEY hk)
        wpa_config_write_reg_dword(hk, TEXT("wps_cred_processing"),
                                   config->wps_cred_processing, 0);
 #endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+       wpa_config_write_reg_string(hk, "p2p_ssid_postfix",
+                                   config->p2p_ssid_postfix);
+       wpa_config_write_reg_dword(hk, TEXT("p2p_group_idle"),
+                                  config->p2p_group_idle, 0);
+#endif /* CONFIG_P2P */
 
        wpa_config_write_reg_dword(hk, TEXT("bss_max_count"),
                                   config->bss_max_count,
                                   DEFAULT_BSS_MAX_COUNT);
        wpa_config_write_reg_dword(hk, TEXT("filter_ssids"),
                                   config->filter_ssids, 0);
+       wpa_config_write_reg_dword(hk, TEXT("max_num_sta"),
+                                  config->max_num_sta, DEFAULT_MAX_NUM_STA);
+       wpa_config_write_reg_dword(hk, TEXT("disassoc_low_ack"),
+                                  config->disassoc_low_ack, 0);
 
        return 0;
 }
index 19fea29..ebf9bbb 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "utils/common.h"
 #include "utils/eloop.h"
+#include "common/version.h"
 #include "common/ieee802_11_defs.h"
 #include "common/wpa_ctrl.h"
 #include "eap_peer/eap.h"
 #include "wps_supplicant.h"
 #include "ibss_rsn.h"
 #include "ap.h"
+#include "p2p_supplicant.h"
+#include "p2p/p2p.h"
 #include "notify.h"
 #include "bss.h"
 #include "scan.h"
 #include "ctrl_iface.h"
+#include "interworking.h"
+#include "blacklist.h"
+#include "wpas_glue.h"
 
 extern struct wpa_driver_ops *wpa_drivers[];
 
@@ -44,6 +50,76 @@ static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
                                                  char *buf, int len);
 
 
+static int pno_start(struct wpa_supplicant *wpa_s)
+{
+       int ret;
+       size_t i, num_ssid;
+       struct wpa_ssid *ssid;
+       struct wpa_driver_scan_params params;
+
+       if (wpa_s->pno)
+               return 0;
+
+       os_memset(&params, 0, sizeof(params));
+
+       num_ssid = 0;
+       ssid = wpa_s->conf->ssid;
+       while (ssid) {
+               if (!ssid->disabled)
+                       num_ssid++;
+               ssid = ssid->next;
+       }
+       if (num_ssid > WPAS_MAX_SCAN_SSIDS) {
+               wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from "
+                          "%u", WPAS_MAX_SCAN_SSIDS, (unsigned int) num_ssid);
+               num_ssid = WPAS_MAX_SCAN_SSIDS;
+       }
+
+       if (num_ssid == 0) {
+               wpa_printf(MSG_DEBUG, "PNO: No configured SSIDs");
+               return -1;
+       }
+
+       params.filter_ssids = os_malloc(sizeof(struct wpa_driver_scan_filter) *
+                                       num_ssid);
+       if (params.filter_ssids == NULL)
+               return -1;
+       i = 0;
+       ssid = wpa_s->conf->ssid;
+       while (ssid) {
+               if (!ssid->disabled) {
+                       params.ssids[i].ssid = ssid->ssid;
+                       params.ssids[i].ssid_len = ssid->ssid_len;
+                       params.num_ssids++;
+                       os_memcpy(params.filter_ssids[i].ssid, ssid->ssid,
+                                 ssid->ssid_len);
+                       params.filter_ssids[i].ssid_len = ssid->ssid_len;
+                       params.num_filter_ssids++;
+                       i++;
+                       if (i == num_ssid)
+                               break;
+               }
+               ssid = ssid->next;
+       }
+
+       ret = wpa_drv_sched_scan(wpa_s, &params, 10 * 1000);
+       os_free(params.filter_ssids);
+       if (ret == 0)
+               wpa_s->pno = 1;
+       return ret;
+}
+
+
+static int pno_stop(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->pno) {
+               wpa_s->pno = 0;
+               return wpa_drv_stop_sched_scan(wpa_s);
+       }
+       return 0;
+}
+
+
 static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                                         char *cmd)
 {
@@ -80,13 +156,86 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
        } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
                if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
                        ret = -1;
-       } else
-               ret = -1;
+       } else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) {
+               wpa_s->wps_fragment_size = atoi(value);
+#ifdef CONFIG_WPS_TESTING
+       } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
+               long int val;
+               val = strtol(value, NULL, 0);
+               if (val < 0 || val > 0xff) {
+                       ret = -1;
+                       wpa_printf(MSG_DEBUG, "WPS: Invalid "
+                                  "wps_version_number %ld", val);
+               } else {
+                       wps_version_number = val;
+                       wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
+                                  "version %u.%u",
+                                  (wps_version_number & 0xf0) >> 4,
+                                  wps_version_number & 0x0f);
+               }
+       } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
+               wps_testing_dummy_cred = atoi(value);
+               wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
+                          wps_testing_dummy_cred);
+#endif /* CONFIG_WPS_TESTING */
+       } else if (os_strcasecmp(cmd, "ampdu") == 0) {
+               if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
+                       ret = -1;
+#ifdef CONFIG_TDLS_TESTING
+       } else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
+               extern unsigned int tdls_testing;
+               tdls_testing = strtol(value, NULL, 0);
+               wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
+#endif /* CONFIG_TDLS_TESTING */
+#ifdef CONFIG_TDLS
+       } else if (os_strcasecmp(cmd, "tdls_disabled") == 0) {
+               int disabled = atoi(value);
+               wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled);
+               if (disabled) {
+                       if (wpa_drv_tdls_oper(wpa_s, TDLS_DISABLE, NULL) < 0)
+                               ret = -1;
+               } else if (wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL) < 0)
+                       ret = -1;
+               wpa_tdls_enable(wpa_s->wpa, !disabled);
+#endif /* CONFIG_TDLS */
+       } else if (os_strcasecmp(cmd, "pno") == 0) {
+               if (atoi(value))
+                       ret = pno_start(wpa_s);
+               else
+                       ret = pno_stop(wpa_s);
+       } else {
+               value[-1] = '=';
+               ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
+               if (ret == 0)
+                       wpa_supplicant_update_config(wpa_s);
+       }
 
        return ret;
 }
 
 
+static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
+                                        char *cmd, char *buf, size_t buflen)
+{
+       int res = -1;
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
+
+       if (os_strcmp(cmd, "version") == 0) {
+               res = os_snprintf(buf, buflen, "%s", VERSION_STR);
+       } else if (os_strcasecmp(cmd, "country") == 0) {
+               if (wpa_s->conf->country[0] && wpa_s->conf->country[1])
+                       res = os_snprintf(buf, buflen, "%c%c",
+                                         wpa_s->conf->country[0],
+                                         wpa_s->conf->country[1]);
+       }
+
+       if (res < 0 || (unsigned int) res >= buflen)
+               return -1;
+       return res;
+}
+
+
 #ifdef IEEE8021X_EAPOL
 static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
                                             char *addr)
@@ -131,6 +280,80 @@ static int wpa_supplicant_ctrl_iface_stkstart(
 #endif /* CONFIG_PEERKEY */
 
 
+#ifdef CONFIG_TDLS
+
+static int wpa_supplicant_ctrl_iface_tdls_discover(
+       struct wpa_supplicant *wpa_s, char *addr)
+{
+       u8 peer[ETH_ALEN];
+       int ret;
+
+       if (hwaddr_aton(addr, peer)) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER: invalid "
+                          "address '%s'", addr);
+               return -1;
+       }
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER " MACSTR,
+                  MAC2STR(peer));
+
+       if (wpa_tdls_is_external_setup(wpa_s->wpa))
+               ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
+       else
+               ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
+
+       return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_tdls_setup(
+       struct wpa_supplicant *wpa_s, char *addr)
+{
+       u8 peer[ETH_ALEN];
+       int ret;
+
+       if (hwaddr_aton(addr, peer)) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP: invalid "
+                          "address '%s'", addr);
+               return -1;
+       }
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
+                  MAC2STR(peer));
+
+       ret = wpa_tdls_reneg(wpa_s->wpa, peer);
+       if (ret) {
+               if (wpa_tdls_is_external_setup(wpa_s->wpa))
+                       ret = wpa_tdls_start(wpa_s->wpa, peer);
+               else
+                       ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
+       }
+
+       return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_tdls_teardown(
+       struct wpa_supplicant *wpa_s, char *addr)
+{
+       u8 peer[ETH_ALEN];
+
+       if (hwaddr_aton(addr, peer)) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
+                          "address '%s'", addr);
+               return -1;
+       }
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
+                  MAC2STR(peer));
+
+       return wpa_tdls_teardown_link(wpa_s->wpa, peer,
+                                     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+}
+
+#endif /* CONFIG_TDLS */
+
+
 #ifdef CONFIG_IEEE80211R
 static int wpa_supplicant_ctrl_iface_ft_ds(
        struct wpa_supplicant *wpa_s, char *addr)
@@ -163,10 +386,26 @@ static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
                                             char *cmd)
 {
        u8 bssid[ETH_ALEN], *_bssid = bssid;
+#ifdef CONFIG_P2P
+       u8 p2p_dev_addr[ETH_ALEN];
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_AP
+       u8 *_p2p_dev_addr = NULL;
+#endif /* CONFIG_AP */
 
-       if (cmd == NULL || os_strcmp(cmd, "any") == 0)
+       if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
                _bssid = NULL;
-       else if (hwaddr_aton(cmd, bssid)) {
+#ifdef CONFIG_P2P
+       } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
+               if (hwaddr_aton(cmd + 13, p2p_dev_addr)) {
+                       wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid "
+                                  "P2P Device Address '%s'",
+                                  cmd + 13);
+                       return -1;
+               }
+               _p2p_dev_addr = p2p_dev_addr;
+#endif /* CONFIG_P2P */
+       } else if (hwaddr_aton(cmd, bssid)) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
                           cmd);
                return -1;
@@ -174,10 +413,10 @@ static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
 
 #ifdef CONFIG_AP
        if (wpa_s->ap_iface)
-               return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid);
+               return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
 #endif /* CONFIG_AP */
 
-       return wpas_wps_start_pbc(wpa_s, _bssid);
+       return wpas_wps_start_pbc(wpa_s, _bssid, 0);
 }
 
 
@@ -195,7 +434,10 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
 
        if (os_strcmp(cmd, "any") == 0)
                _bssid = NULL;
-       else if (hwaddr_aton(cmd, bssid)) {
+       else if (os_strcmp(cmd, "get") == 0) {
+               ret = wps_generate_pin();
+               goto done;
+       } else if (hwaddr_aton(cmd, bssid)) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
                           cmd);
                return -1;
@@ -208,7 +450,8 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_AP */
 
        if (pin) {
-               ret = wpas_wps_start_pin(wpa_s, _bssid, pin);
+               ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0,
+                                        DEV_PW_DEFAULT);
                if (ret < 0)
                        return -1;
                ret = os_snprintf(buf, buflen, "%s", pin);
@@ -217,10 +460,11 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
                return ret;
        }
 
-       ret = wpas_wps_start_pin(wpa_s, _bssid, NULL);
+       ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT);
        if (ret < 0)
                return -1;
 
+done:
        /* Return the generated PIN */
        ret = os_snprintf(buf, buflen, "%08d", ret);
        if (ret < 0 || (size_t) ret >= buflen)
@@ -229,6 +473,51 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
 }
 
 
+static int wpa_supplicant_ctrl_iface_wps_check_pin(
+       struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
+{
+       char pin[9];
+       size_t len;
+       char *pos;
+       int ret;
+
+       wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
+                             (u8 *) cmd, os_strlen(cmd));
+       for (pos = cmd, len = 0; *pos != '\0'; pos++) {
+               if (*pos < '0' || *pos > '9')
+                       continue;
+               pin[len++] = *pos;
+               if (len == 9) {
+                       wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
+                       return -1;
+               }
+       }
+       if (len != 4 && len != 8) {
+               wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
+               return -1;
+       }
+       pin[len] = '\0';
+
+       if (len == 8) {
+               unsigned int pin_val;
+               pin_val = atoi(pin);
+               if (!wps_pin_valid(pin_val)) {
+                       wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
+                       ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
+                       if (ret < 0 || (size_t) ret >= buflen)
+                               return -1;
+                       return ret;
+               }
+       }
+
+       ret = os_snprintf(buf, buflen, "%s", pin);
+       if (ret < 0 || (size_t) ret >= buflen)
+               return -1;
+
+       return ret;
+}
+
+
 #ifdef CONFIG_WPS_OOB
 static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
                                             char *cmd)
@@ -257,7 +546,7 @@ static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
 static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
                                             char *cmd)
 {
-       u8 bssid[ETH_ALEN], *_bssid = bssid;
+       u8 bssid[ETH_ALEN];
        char *pin;
        char *new_ssid;
        char *new_auth;
@@ -270,9 +559,7 @@ static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
                return -1;
        *pin++ = '\0';
 
-       if (os_strcmp(cmd, "any") == 0)
-               _bssid = NULL;
-       else if (hwaddr_aton(cmd, bssid)) {
+       if (hwaddr_aton(cmd, bssid)) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
                           cmd);
                return -1;
@@ -280,7 +567,7 @@ static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
 
        new_ssid = os_strchr(pin, ' ');
        if (new_ssid == NULL)
-               return wpas_wps_start_reg(wpa_s, _bssid, pin, NULL);
+               return wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
        *new_ssid++ = '\0';
 
        new_auth = os_strchr(new_ssid, ' ');
@@ -303,20 +590,86 @@ static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
        ap.auth = new_auth;
        ap.encr = new_encr;
        ap.key_hex = new_key;
-       return wpas_wps_start_reg(wpa_s, _bssid, pin, &ap);
+       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;
+       char *uuid = cmd, *pin, *pos;
+       u8 addr_buf[ETH_ALEN], *addr = NULL;
        pin = os_strchr(uuid, ' ');
        if (pin == NULL)
                return -1;
        *pin++ = '\0';
-       return wpas_wps_er_add_pin(wpa_s, uuid, pin);
+       pos = os_strchr(pin, ' ');
+       if (pos) {
+               *pos++ = '\0';
+               if (hwaddr_aton(pos, addr_buf) == 0)
+                       addr = addr_buf;
+       }
+       return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin);
 }
 
 
@@ -330,6 +683,62 @@ static int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s,
        *pin++ = '\0';
        return wpas_wps_er_learn(wpa_s, uuid, pin);
 }
+
+
+static int wpa_supplicant_ctrl_iface_wps_er_set_config(
+       struct wpa_supplicant *wpa_s, char *cmd)
+{
+       char *uuid = cmd, *id;
+       id = os_strchr(uuid, ' ');
+       if (id == NULL)
+               return -1;
+       *id++ = '\0';
+       return wpas_wps_er_set_config(wpa_s, uuid, atoi(id));
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_er_config(
+       struct wpa_supplicant *wpa_s, char *cmd)
+{
+       char *pin;
+       char *new_ssid;
+       char *new_auth;
+       char *new_encr;
+       char *new_key;
+       struct wps_new_ap_settings ap;
+
+       pin = os_strchr(cmd, ' ');
+       if (pin == NULL)
+               return -1;
+       *pin++ = '\0';
+
+       new_ssid = os_strchr(pin, ' ');
+       if (new_ssid == NULL)
+               return -1;
+       *new_ssid++ = '\0';
+
+       new_auth = os_strchr(new_ssid, ' ');
+       if (new_auth == NULL)
+               return -1;
+       *new_auth++ = '\0';
+
+       new_encr = os_strchr(new_auth, ' ');
+       if (new_encr == NULL)
+               return -1;
+       *new_encr++ = '\0';
+
+       new_key = os_strchr(new_encr, ' ');
+       if (new_key == NULL)
+               return -1;
+       *new_key++ = '\0';
+
+       os_memset(&ap, 0, sizeof(ap));
+       ap.ssid_hex = new_ssid;
+       ap.auth = new_auth;
+       ap.encr = new_encr;
+       ap.key_hex = new_key;
+       return wpas_wps_er_config(wpa_s, cmd, pin, &ap);
+}
 #endif /* CONFIG_WPS_ER */
 
 #endif /* CONFIG_WPS */
@@ -355,99 +764,126 @@ static int wpa_supplicant_ctrl_iface_ibss_rsn(
 #endif /* CONFIG_IBSS_RSN */
 
 
-static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
-                                             char *rsp)
+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
-       char *pos, *id_pos;
-       int id;
-       struct wpa_ssid *ssid;
-       struct eap_peer_config *eap;
-
-       pos = os_strchr(rsp, '-');
-       if (pos == NULL)
-               return -1;
-       *pos++ = '\0';
-       id_pos = pos;
-       pos = os_strchr(pos, ':');
-       if (pos == NULL)
-               return -1;
-       *pos++ = '\0';
-       id = atoi(id_pos);
-       wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
-       wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
-                             (u8 *) pos, os_strlen(pos));
+       struct eap_peer_config *eap = &ssid->eap;
 
-       ssid = wpa_config_get_network(wpa_s->conf, id);
-       if (ssid == NULL) {
-               wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
-                          "to update", id);
-               return -1;
-       }
-       eap = &ssid->eap;
+       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));
 
-       if (os_strcmp(rsp, "IDENTITY") == 0) {
+       switch (wpa_supplicant_ctrl_req_from_string(field)) {
+       case WPA_CTRL_REQ_EAP_IDENTITY:
                os_free(eap->identity);
-               eap->identity = (u8 *) os_strdup(pos);
-               eap->identity_len = os_strlen(pos);
+               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;
-       } else if (os_strcmp(rsp, "PASSWORD") == 0) {
+               break;
+       case WPA_CTRL_REQ_EAP_PASSWORD:
                os_free(eap->password);
-               eap->password = (u8 *) os_strdup(pos);
-               eap->password_len = os_strlen(pos);
+               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;
-       } else if (os_strcmp(rsp, "NEW_PASSWORD") == 0) {
+               break;
+       case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
                os_free(eap->new_password);
-               eap->new_password = (u8 *) os_strdup(pos);
-               eap->new_password_len = os_strlen(pos);
+               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;
-       } else if (os_strcmp(rsp, "PIN") == 0) {
+               break;
+       case WPA_CTRL_REQ_EAP_PIN:
                os_free(eap->pin);
-               eap->pin = os_strdup(pos);
+               eap->pin = os_strdup(value);
                eap->pending_req_pin = 0;
                if (ssid == wpa_s->current_ssid)
                        wpa_s->reassociate = 1;
-       } else if (os_strcmp(rsp, "OTP") == 0) {
+               break;
+       case WPA_CTRL_REQ_EAP_OTP:
                os_free(eap->otp);
-               eap->otp = (u8 *) os_strdup(pos);
-               eap->otp_len = os_strlen(pos);
+               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;
-       } else if (os_strcmp(rsp, "PASSPHRASE") == 0) {
+               break;
+       case WPA_CTRL_REQ_EAP_PASSPHRASE:
                os_free(eap->private_key_passwd);
-               eap->private_key_passwd = (u8 *) os_strdup(pos);
+               eap->private_key_passwd = (u8 *) os_strdup(value);
                eap->pending_req_passphrase = 0;
                if (ssid == wpa_s->current_ssid)
                        wpa_s->reassociate = 1;
-       } else {
-               wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", rsp);
+               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: 802.1X not included");
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE: IEEE 802.1X not included");
        return -1;
 #endif /* IEEE8021X_EAPOL */
 }
 
 
-static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
-                                           const char *params,
-                                           char *buf, size_t buflen)
+static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
+                                             char *rsp)
 {
-       char *pos, *end, tmp[30];
-       int res, verbose, ret;
+#ifdef IEEE8021X_EAPOL
+       char *pos, *id_pos;
+       int id;
+       struct wpa_ssid *ssid;
 
-       verbose = os_strcmp(params, "-VERBOSE") == 0;
-       pos = buf;
+       pos = os_strchr(rsp, '-');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+       id_pos = pos;
+       pos = os_strchr(pos, ':');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+       id = atoi(id_pos);
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
+       wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
+                             (u8 *) pos, os_strlen(pos));
+
+       ssid = wpa_config_get_network(wpa_s->conf, id);
+       if (ssid == NULL) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
+                          "to update", id);
+               return -1;
+       }
+
+       return wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, rsp,
+                                                        pos);
+#else /* IEEE8021X_EAPOL */
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
+       return -1;
+#endif /* IEEE8021X_EAPOL */
+}
+
+
+static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
+                                           const char *params,
+                                           char *buf, size_t buflen)
+{
+       char *pos, *end, tmp[30];
+       int res, verbose, wps, ret;
+
+       verbose = os_strcmp(params, "-VERBOSE") == 0;
+       wps = os_strcmp(params, "-WPS") == 0;
+       pos = buf;
        end = buf + buflen;
        if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
                struct wpa_ssid *ssid = wpa_s->current_ssid;
@@ -475,6 +911,17 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
                                return pos - buf;
                        pos += ret;
 
+                       if (wps && ssid->passphrase &&
+                           wpa_key_mgmt_wpa_psk(ssid->key_mgmt) &&
+                           (ssid->mode == WPAS_MODE_AP ||
+                            ssid->mode == WPAS_MODE_P2P_GO)) {
+                               ret = os_snprintf(pos, end - pos,
+                                                 "passphrase=%s\n",
+                                                 ssid->passphrase);
+                               if (ret < 0 || ret >= end - pos)
+                                       return pos - buf;
+                               pos += ret;
+                       }
                        if (ssid->id_str) {
                                ret = os_snprintf(pos, end - pos,
                                                  "id_str=%s\n",
@@ -497,6 +944,15 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
                                ret = os_snprintf(pos, end - pos,
                                                  "mode=AP\n");
                                break;
+                       case WPAS_MODE_P2P_GO:
+                               ret = os_snprintf(pos, end - pos,
+                                                 "mode=P2P GO\n");
+                               break;
+                       case WPAS_MODE_P2P_GROUP_FORMATION:
+                               ret = os_snprintf(pos, end - pos,
+                                                 "mode=P2P GO - group "
+                                                 "formation\n");
+                               break;
                        default:
                                ret = 0;
                                break;
@@ -529,6 +985,22 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
                pos += ret;
        }
 
+#ifdef CONFIG_P2P
+       if (wpa_s->global->p2p) {
+               ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
+                                 "\n", MAC2STR(wpa_s->global->p2p_dev_addr));
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       }
+#endif /* CONFIG_P2P */
+
+       ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n",
+                         MAC2STR(wpa_s->own_addr));
+       if (ret < 0 || ret >= end - pos)
+               return pos - buf;
+       pos += ret;
+
        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,
@@ -579,6 +1051,152 @@ static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
 }
 
 
+static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
+                                              char *cmd, char *buf,
+                                              size_t buflen)
+{
+       u8 bssid[ETH_ALEN];
+       struct wpa_blacklist *e;
+       char *pos, *end;
+       int ret;
+
+       /* cmd: "BLACKLIST [<BSSID>]" */
+       if (*cmd == '\0') {
+               pos = buf;
+               end = buf + buflen;
+               e = wpa_s->blacklist;
+               while (e) {
+                       ret = os_snprintf(pos, end - pos, MACSTR "\n",
+                                         MAC2STR(e->bssid));
+                       if (ret < 0 || ret >= end - pos)
+                               return pos - buf;
+                       pos += ret;
+                       e = e->next;
+               }
+               return pos - buf;
+       }
+
+       cmd++;
+       if (os_strncmp(cmd, "clear", 5) == 0) {
+               wpa_blacklist_clear(wpa_s);
+               os_memcpy(buf, "OK\n", 3);
+               return 3;
+       }
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd);
+       if (hwaddr_aton(cmd, bssid)) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd);
+               return -1;
+       }
+
+       /*
+        * Add the BSSID twice, so its count will be 2, causing it to be
+        * skipped when processing scan results.
+        */
+       ret = wpa_blacklist_add(wpa_s, bssid);
+       if (ret != 0)
+               return -1;
+       ret = wpa_blacklist_add(wpa_s, bssid);
+       if (ret != 0)
+               return -1;
+       os_memcpy(buf, "OK\n", 3);
+       return 3;
+}
+
+
+extern int wpa_debug_level;
+extern int wpa_debug_timestamp;
+
+static const char * debug_level_str(int level)
+{
+       switch (level) {
+       case MSG_EXCESSIVE:
+               return "EXCESSIVE";
+       case MSG_MSGDUMP:
+               return "MSGDUMP";
+       case MSG_DEBUG:
+               return "DEBUG";
+       case MSG_INFO:
+               return "INFO";
+       case MSG_WARNING:
+               return "WARNING";
+       case MSG_ERROR:
+               return "ERROR";
+       default:
+               return "?";
+       }
+}
+
+
+static int str_to_debug_level(const char *s)
+{
+       if (os_strcasecmp(s, "EXCESSIVE") == 0)
+               return MSG_EXCESSIVE;
+       if (os_strcasecmp(s, "MSGDUMP") == 0)
+               return MSG_MSGDUMP;
+       if (os_strcasecmp(s, "DEBUG") == 0)
+               return MSG_DEBUG;
+       if (os_strcasecmp(s, "INFO") == 0)
+               return MSG_INFO;
+       if (os_strcasecmp(s, "WARNING") == 0)
+               return MSG_WARNING;
+       if (os_strcasecmp(s, "ERROR") == 0)
+               return MSG_ERROR;
+       return -1;
+}
+
+
+static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,
+                                              char *cmd, char *buf,
+                                              size_t buflen)
+{
+       char *pos, *end, *stamp;
+       int ret;
+
+       if (cmd == NULL) {
+               return -1;
+       }
+
+       /* cmd: "LOG_LEVEL [<level>]" */
+       if (*cmd == '\0') {
+               pos = buf;
+               end = buf + buflen;
+               ret = os_snprintf(pos, end - pos, "Current level: %s\n"
+                                 "Timestamp: %d\n",
+                                 debug_level_str(wpa_debug_level),
+                                 wpa_debug_timestamp);
+               if (ret < 0 || ret >= end - pos)
+                       ret = 0;
+
+               return ret;
+       }
+
+       while (*cmd == ' ')
+               cmd++;
+
+       stamp = os_strchr(cmd, ' ');
+       if (stamp) {
+               *stamp++ = '\0';
+               while (*stamp == ' ') {
+                       stamp++;
+               }
+       }
+
+       if (cmd && os_strlen(cmd)) {
+               int level = str_to_debug_level(cmd);
+               if (level < 0)
+                       return -1;
+               wpa_debug_level = level;
+       }
+
+       if (stamp && os_strlen(stamp))
+               wpa_debug_timestamp = atoi(stamp);
+
+       os_memcpy(buf, "OK\n", 3);
+       return 3;
+}
+
+
 static int wpa_supplicant_ctrl_iface_list_networks(
        struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
 {
@@ -611,10 +1229,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",
+               ret = os_snprintf(pos, end - pos, "\t%s%s%s",
                                  ssid == wpa_s->current_ssid ?
                                  "[CURRENT]" : "",
-                                 ssid->disabled ? "[DISABLED]" : "");
+                                 ssid->disabled ? "[DISABLED]" : "",
+                                 ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
+                                 "");
                if (ret < 0 || ret >= end - pos)
                        return pos - buf;
                pos += ret;
@@ -774,7 +1394,8 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
 
 
 #ifdef CONFIG_WPS
-static char * wpa_supplicant_wps_ie_txt_buf(char *pos, char *end,
+static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
+                                           char *pos, char *end,
                                            struct wpabuf *wps_ie)
 {
        int ret;
@@ -784,6 +1405,10 @@ static char * wpa_supplicant_wps_ie_txt_buf(char *pos, char *end,
                return pos;
        if (wps_is_selected_pbc_registrar(wps_ie))
                txt = "[WPS-PBC]";
+#ifdef CONFIG_WPS2
+       else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
+               txt = "[WPS-AUTH]";
+#endif /* CONFIG_WPS2 */
        else if (wps_is_selected_pin_registrar(wps_ie))
                txt = "[WPS-PIN]";
        else
@@ -798,13 +1423,14 @@ static char * wpa_supplicant_wps_ie_txt_buf(char *pos, char *end,
 #endif /* CONFIG_WPS */
 
 
-static char * wpa_supplicant_wps_ie_txt(char *pos, char *end,
+static char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s,
+                                       char *pos, char *end,
                                        const struct wpa_bss *bss)
 {
 #ifdef CONFIG_WPS
        struct wpabuf *wps_ie;
        wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
-       return wpa_supplicant_wps_ie_txt_buf(pos, end, wps_ie);
+       return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie);
 #else /* CONFIG_WPS */
        return pos;
 #endif /* CONFIG_WPS */
@@ -813,11 +1439,18 @@ static char * wpa_supplicant_wps_ie_txt(char *pos, char *end,
 
 /* Format one result on one text line into a buffer. */
 static int wpa_supplicant_ctrl_iface_scan_result(
+       struct wpa_supplicant *wpa_s,
        const struct wpa_bss *bss, char *buf, size_t buflen)
 {
        char *pos, *end;
        int ret;
-       const u8 *ie, *ie2;
+       const u8 *ie, *ie2, *p2p;
+
+       p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
+       if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN &&
+           os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) ==
+           0)
+               return 0; /* Do not show P2P listen discovery results here */
 
        pos = buf;
        end = buf + buflen;
@@ -825,7 +1458,7 @@ static int wpa_supplicant_ctrl_iface_scan_result(
        ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
                          MAC2STR(bss->bssid), bss->freq, bss->level);
        if (ret < 0 || ret >= end - pos)
-               return pos - buf;
+               return -1;
        pos += ret;
        ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
        if (ie)
@@ -833,35 +1466,41 @@ static int wpa_supplicant_ctrl_iface_scan_result(
        ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
        if (ie2)
                pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
-       pos = wpa_supplicant_wps_ie_txt(pos, end, bss);
+       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 pos - buf;
+                       return -1;
                pos += ret;
        }
        if (bss->caps & IEEE80211_CAP_IBSS) {
                ret = os_snprintf(pos, end - pos, "[IBSS]");
                if (ret < 0 || ret >= end - pos)
-                       return pos - buf;
+                       return -1;
                pos += ret;
        }
        if (bss->caps & IEEE80211_CAP_ESS) {
                ret = os_snprintf(pos, end - pos, "[ESS]");
                if (ret < 0 || ret >= end - pos)
-                       return pos - buf;
+                       return -1;
+               pos += ret;
+       }
+       if (p2p) {
+               ret = os_snprintf(pos, end - pos, "[P2P]");
+               if (ret < 0 || ret >= end - pos)
+                       return -1;
                pos += ret;
        }
 
        ret = os_snprintf(pos, end - pos, "\t%s",
                          wpa_ssid_txt(bss->ssid, bss->ssid_len));
        if (ret < 0 || ret >= end - pos)
-               return pos - buf;
+               return -1;
        pos += ret;
 
        ret = os_snprintf(pos, end - pos, "\n");
        if (ret < 0 || ret >= end - pos)
-               return pos - buf;
+               return -1;
        pos += ret;
 
        return pos - buf;
@@ -884,7 +1523,7 @@ static int wpa_supplicant_ctrl_iface_scan_results(
        pos += ret;
 
        dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
-               ret = wpa_supplicant_ctrl_iface_scan_result(bss, pos,
+               ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos,
                                                            end - pos);
                if (ret < 0 || ret >= end - pos)
                        return pos - buf;
@@ -915,6 +1554,11 @@ static int wpa_supplicant_ctrl_iface_select_network(
                                   "network id=%d", id);
                        return -1;
                }
+               if (ssid->disabled == 2) {
+                       wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
+                                  "SELECT_NETWORK with persistent P2P group");
+                       return -1;
+               }
        }
 
        wpa_supplicant_select_network(wpa_s, ssid);
@@ -943,6 +1587,11 @@ static int wpa_supplicant_ctrl_iface_enable_network(
                                   "network id=%d", id);
                        return -1;
                }
+               if (ssid->disabled == 2) {
+                       wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
+                                  "ENABLE_NETWORK with persistent P2P group");
+                       return -1;
+               }
        }
        wpa_supplicant_enable_network(wpa_s, ssid);
 
@@ -970,6 +1619,12 @@ static int wpa_supplicant_ctrl_iface_disable_network(
                                   "network id=%d", id);
                        return -1;
                }
+               if (ssid->disabled == 2) {
+                       wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
+                                  "DISABLE_NETWORK with persistent P2P "
+                                  "group");
+                       return -1;
+               }
        }
        wpa_supplicant_disable_network(wpa_s, ssid);
 
@@ -1018,8 +1673,10 @@ 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) {
-                       eapol_sm_invalidate_cached_session(wpa_s->eapol);
+                       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);
                }
@@ -1030,6 +1687,8 @@ static int wpa_supplicant_ctrl_iface_remove_network(
        wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
 
        ssid = wpa_config_get_network(wpa_s->conf, id);
+       if (ssid)
+               wpas_notify_network_removed(wpa_s, ssid);
        if (ssid == NULL ||
            wpa_config_remove_network(wpa_s->conf, id) < 0) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
@@ -1037,12 +1696,17 @@ static int wpa_supplicant_ctrl_iface_remove_network(
                return -1;
        }
 
-       if (ssid == wpa_s->current_ssid) {
+       if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
                /*
-                * Invalidate the EAP session cache if the current network is
-                * removed.
+                * Invalidate the EAP session cache if the current or
+                * previously used network is removed.
                 */
                eapol_sm_invalidate_cached_session(wpa_s->eapol);
+       }
+
+       if (ssid == wpa_s->current_ssid) {
+               wpa_sm_set_config(wpa_s->wpa, NULL);
+               eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 
                wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
        }
@@ -1088,10 +1752,12 @@ static int wpa_supplicant_ctrl_iface_set_network(
                return -1;
        }
 
-       if (wpa_s->current_ssid == ssid) {
+       wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+
+       if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
                /*
                 * Invalidate the EAP session cache if anything in the current
-                * configuration changes.
+                * or previously used configuration changes.
                 */
                eapol_sm_invalidate_cached_session(wpa_s->eapol);
        }
@@ -1482,6 +2148,41 @@ static int wpa_supplicant_ctrl_iface_get_capability(
 }
 
 
+#ifdef CONFIG_INTERWORKING
+static char * anqp_add_hex(char *pos, char *end, const char *title,
+                          struct wpabuf *data)
+{
+       char *start = pos;
+       size_t i;
+       int ret;
+       const u8 *d;
+
+       if (data == NULL)
+               return start;
+
+       ret = os_snprintf(pos, end - pos, "%s=", title);
+       if (ret < 0 || ret >= end - pos)
+               return start;
+       pos += ret;
+
+       d = wpabuf_head_u8(data);
+       for (i = 0; i < wpabuf_len(data); i++) {
+               ret = os_snprintf(pos, end - pos, "%02x", *d++);
+               if (ret < 0 || ret >= end - pos)
+                       return start;
+               pos += ret;
+       }
+
+       ret = os_snprintf(pos, end - pos, "\n");
+       if (ret < 0 || ret >= end - pos)
+               return start;
+       pos += ret;
+
+       return pos;
+}
+#endif /* CONFIG_INTERWORKING */
+
+
 static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
                                         const char *cmd, char *buf,
                                         size_t buflen)
@@ -1572,7 +2273,7 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
        ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
        if (ie2)
                pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
-       pos = wpa_supplicant_wps_ie_txt(pos, end, bss);
+       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)
@@ -1591,6 +2292,12 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
                        return pos - buf;
                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 pos - buf;
+               pos += ret;
+       }
 
        ret = os_snprintf(pos, end - pos, "\n");
        if (ret < 0 || ret >= end - pos)
@@ -1611,6 +2318,28 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
        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;
+#endif /* CONFIG_P2P */
+
+#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);
+#endif /* CONFIG_INTERWORKING */
+
        return pos - buf;
 }
 
@@ -1623,19 +2352,44 @@ static int wpa_supplicant_ctrl_iface_ap_scan(
 }
 
 
-static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
+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;
+}
+
+
+static int wpa_supplicant_ctrl_iface_bss_expire_age(
+       struct wpa_supplicant *wpa_s, char *cmd)
+{
+       int expire_age = atoi(cmd);
+       return wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age);
+}
+
+
+static int wpa_supplicant_ctrl_iface_bss_expire_count(
+       struct wpa_supplicant *wpa_s, char *cmd)
 {
-       u8 *bcast = (u8 *) "\xff\xff\xff\xff\xff\xff";
+       int expire_count = atoi(cmd);
+       return wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count);
+}
+
 
+static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
+{
        wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
        /* MLME-DELETEKEYS.request */
-       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 0, 0, NULL, 0, NULL, 0);
-       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 1, 0, NULL, 0, NULL, 0);
-       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 2, 0, NULL, 0, NULL, 0);
-       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 3, 0, NULL, 0, NULL, 0);
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
 #ifdef CONFIG_IEEE80211W
-       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 4, 0, NULL, 0, NULL, 0);
-       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 5, 0, NULL, 0, NULL, 0);
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
 #endif /* CONFIG_IEEE80211W */
 
        wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
@@ -1651,6 +2405,9 @@ static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
 static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
                                          char *addr)
 {
+#ifdef CONFIG_NO_SCAN_PROCESSING
+       return -1;
+#else /* CONFIG_NO_SCAN_PROCESSING */
        u8 bssid[ETH_ALEN];
        struct wpa_bss *bss;
        struct wpa_ssid *ssid = wpa_s->current_ssid;
@@ -1685,68 +2442,936 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
        wpa_supplicant_connect(wpa_s, bss, ssid);
 
        return 0;
+#endif /* CONFIG_NO_SCAN_PROCESSING */
 }
 
 
-char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
-                                        char *buf, size_t *resp_len)
+#ifdef CONFIG_P2P
+static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
 {
-       char *reply;
-       const int reply_size = 2048;
-       int ctrl_rsp = 0;
-       int reply_len;
+       unsigned int timeout = atoi(cmd);
+       enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
 
-       if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
-           os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
-               wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
-                                     (const u8 *) buf, os_strlen(buf));
+       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);
+}
+
+
+static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
+                           char *buf, size_t buflen)
+{
+       u8 addr[ETH_ALEN];
+       char *pos, *pos2;
+       char *pin = NULL;
+       enum p2p_wps_method wps_method;
+       int new_pin;
+       int ret;
+       int persistent_group;
+       int join;
+       int auth;
+       int go_intent = -1;
+       int freq = 0;
+
+       /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad] [persistent]
+        * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] */
+
+       if (hwaddr_aton(cmd, addr))
+               return -1;
+
+       pos = cmd + 17;
+       if (*pos != ' ')
+               return -1;
+       pos++;
+
+       persistent_group = os_strstr(pos, " persistent") != NULL;
+       join = os_strstr(pos, " join") != NULL;
+       auth = os_strstr(pos, " auth") != NULL;
+
+       pos2 = os_strstr(pos, " go_intent=");
+       if (pos2) {
+               pos2 += 11;
+               go_intent = atoi(pos2);
+               if (go_intent < 0 || go_intent > 15)
+                       return -1;
+       }
+
+       pos2 = os_strstr(pos, " freq=");
+       if (pos2) {
+               pos2 += 6;
+               freq = atoi(pos2);
+               if (freq <= 0)
+                       return -1;
+       }
+
+       if (os_strncmp(pos, "pin", 3) == 0) {
+               /* Request random PIN (to be displayed) and enable the PIN */
+               wps_method = WPS_PIN_DISPLAY;
+       } else if (os_strncmp(pos, "pbc", 3) == 0) {
+               wps_method = WPS_PBC;
        } else {
-               wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface",
-                                 (const u8 *) buf, os_strlen(buf));
+               pin = pos;
+               pos = os_strchr(pin, ' ');
+               wps_method = WPS_PIN_KEYPAD;
+               if (pos) {
+                       *pos++ = '\0';
+                       if (os_strncmp(pos, "display", 7) == 0)
+                               wps_method = WPS_PIN_DISPLAY;
+               }
        }
 
-       reply = os_malloc(reply_size);
-       if (reply == NULL) {
-               *resp_len = 1;
-               return NULL;
+       new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
+                                  persistent_group, join, auth, go_intent,
+                                  freq);
+       if (new_pin == -2) {
+               os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
+               return 25;
+       }
+       if (new_pin == -3) {
+               os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25);
+               return 25;
+       }
+       if (new_pin < 0)
+               return -1;
+       if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
+               ret = os_snprintf(buf, buflen, "%08d", new_pin);
+               if (ret < 0 || (size_t) ret >= buflen)
+                       return -1;
+               return ret;
        }
 
-       os_memcpy(reply, "OK\n", 3);
-       reply_len = 3;
+       os_memcpy(buf, "OK\n", 3);
+       return 3;
+}
 
-       if (os_strcmp(buf, "PING") == 0) {
-               os_memcpy(reply, "PONG\n", 5);
-               reply_len = 5;
-       } else if (os_strcmp(buf, "MIB") == 0) {
-               reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
-               if (reply_len >= 0) {
-                       int res;
-                       res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
-                                              reply_size - reply_len);
-                       if (res < 0)
-                               reply_len = -1;
-                       else
-                               reply_len += res;
-               }
-       } else if (os_strncmp(buf, "STATUS", 6) == 0) {
-               reply_len = wpa_supplicant_ctrl_iface_status(
-                       wpa_s, buf + 6, reply, reply_size);
-       } else if (os_strcmp(buf, "PMKSA") == 0) {
-               reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
-                                                   reply_size);
-       } else if (os_strncmp(buf, "SET ", 4) == 0) {
-               if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
+
+static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       unsigned int timeout = atoi(cmd);
+       return wpas_p2p_listen(wpa_s, timeout);
+}
+
+
+static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       u8 addr[ETH_ALEN];
+       char *pos;
+
+       /* <addr> <config method> [join] */
+
+       if (hwaddr_aton(cmd, addr))
+               return -1;
+
+       pos = cmd + 17;
+       if (*pos != ' ')
+               return -1;
+       pos++;
+
+       return wpas_p2p_prov_disc(wpa_s, addr, pos,
+                                 os_strstr(pos, "join") != NULL);
+}
+
+
+static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf,
+                             size_t buflen)
+{
+       struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+       if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
+           ssid->passphrase == NULL)
+               return -1;
+
+       os_strlcpy(buf, ssid->passphrase, buflen);
+       return os_strlen(buf);
+}
+
+
+static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
+                                 char *buf, size_t buflen)
+{
+       u64 ref;
+       int res;
+       u8 dst_buf[ETH_ALEN], *dst;
+       struct wpabuf *tlvs;
+       char *pos;
+       size_t len;
+
+       if (hwaddr_aton(cmd, dst_buf))
+               return -1;
+       dst = dst_buf;
+       if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
+           dst[3] == 0 && dst[4] == 0 && dst[5] == 0)
+               dst = NULL;
+       pos = cmd + 17;
+       if (*pos != ' ')
+               return -1;
+       pos++;
+
+       if (os_strncmp(pos, "upnp ", 5) == 0) {
+               u8 version;
+               pos += 5;
+               if (hexstr2bin(pos, &version, 1) < 0)
+                       return -1;
+               pos += 2;
+               if (*pos != ' ')
+                       return -1;
+               pos++;
+               ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos);
+       } else {
+               len = os_strlen(pos);
+               if (len & 1)
+                       return -1;
+               len /= 2;
+               tlvs = wpabuf_alloc(len);
+               if (tlvs == NULL)
+                       return -1;
+               if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) {
+                       wpabuf_free(tlvs);
+                       return -1;
+               }
+
+               ref = wpas_p2p_sd_request(wpa_s, dst, tlvs);
+               wpabuf_free(tlvs);
+       }
+       if (ref == 0)
+               return -1;
+       res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
+       if (res < 0 || (unsigned) res >= buflen)
+               return -1;
+       return res;
+}
+
+
+static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s,
+                                        char *cmd)
+{
+       long long unsigned val;
+       u64 req;
+       if (sscanf(cmd, "%llx", &val) != 1)
+               return -1;
+       req = val;
+       return wpas_p2p_sd_cancel_request(wpa_s, req);
+}
+
+
+static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       int freq;
+       u8 dst[ETH_ALEN];
+       u8 dialog_token;
+       struct wpabuf *resp_tlvs;
+       char *pos, *pos2;
+       size_t len;
+
+       pos = os_strchr(cmd, ' ');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+       freq = atoi(cmd);
+       if (freq == 0)
+               return -1;
+
+       if (hwaddr_aton(pos, dst))
+               return -1;
+       pos += 17;
+       if (*pos != ' ')
+               return -1;
+       pos++;
+
+       pos2 = os_strchr(pos, ' ');
+       if (pos2 == NULL)
+               return -1;
+       *pos2++ = '\0';
+       dialog_token = atoi(pos);
+
+       len = os_strlen(pos2);
+       if (len & 1)
+               return -1;
+       len /= 2;
+       resp_tlvs = wpabuf_alloc(len);
+       if (resp_tlvs == NULL)
+               return -1;
+       if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) {
+               wpabuf_free(resp_tlvs);
+               return -1;
+       }
+
+       wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs);
+       wpabuf_free(resp_tlvs);
+       return 0;
+}
+
+
+static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s,
+                                      char *cmd)
+{
+       wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd);
+       return 0;
+}
+
+
+static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s,
+                                       char *cmd)
+{
+       char *pos;
+       size_t len;
+       struct wpabuf *query, *resp;
+
+       pos = os_strchr(cmd, ' ');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+
+       len = os_strlen(cmd);
+       if (len & 1)
+               return -1;
+       len /= 2;
+       query = wpabuf_alloc(len);
+       if (query == NULL)
+               return -1;
+       if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
+               wpabuf_free(query);
+               return -1;
+       }
+
+       len = os_strlen(pos);
+       if (len & 1) {
+               wpabuf_free(query);
+               return -1;
+       }
+       len /= 2;
+       resp = wpabuf_alloc(len);
+       if (resp == NULL) {
+               wpabuf_free(query);
+               return -1;
+       }
+       if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) {
+               wpabuf_free(query);
+               wpabuf_free(resp);
+               return -1;
+       }
+
+       if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
+               wpabuf_free(query);
+               wpabuf_free(resp);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       char *pos;
+       u8 version;
+
+       pos = os_strchr(cmd, ' ');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+
+       if (hexstr2bin(cmd, &version, 1) < 0)
+               return -1;
+
+       return wpas_p2p_service_add_upnp(wpa_s, version, pos);
+}
+
+
+static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       char *pos;
+
+       pos = os_strchr(cmd, ' ');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+
+       if (os_strcmp(cmd, "bonjour") == 0)
+               return p2p_ctrl_service_add_bonjour(wpa_s, pos);
+       if (os_strcmp(cmd, "upnp") == 0)
+               return p2p_ctrl_service_add_upnp(wpa_s, pos);
+       wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
+       return -1;
+}
+
+
+static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s,
+                                       char *cmd)
+{
+       size_t len;
+       struct wpabuf *query;
+       int ret;
+
+       len = os_strlen(cmd);
+       if (len & 1)
+               return -1;
+       len /= 2;
+       query = wpabuf_alloc(len);
+       if (query == NULL)
+               return -1;
+       if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
+               wpabuf_free(query);
+               return -1;
+       }
+
+       ret = wpas_p2p_service_del_bonjour(wpa_s, query);
+       wpabuf_free(query);
+       return ret;
+}
+
+
+static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       char *pos;
+       u8 version;
+
+       pos = os_strchr(cmd, ' ');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+
+       if (hexstr2bin(cmd, &version, 1) < 0)
+               return -1;
+
+       return wpas_p2p_service_del_upnp(wpa_s, version, pos);
+}
+
+
+static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       char *pos;
+
+       pos = os_strchr(cmd, ' ');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+
+       if (os_strcmp(cmd, "bonjour") == 0)
+               return p2p_ctrl_service_del_bonjour(wpa_s, pos);
+       if (os_strcmp(cmd, "upnp") == 0)
+               return p2p_ctrl_service_del_upnp(wpa_s, pos);
+       wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
+       return -1;
+}
+
+
+static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       u8 addr[ETH_ALEN];
+
+       /* <addr> */
+
+       if (hwaddr_aton(cmd, addr))
+               return -1;
+
+       return wpas_p2p_reject(wpa_s, addr);
+}
+
+
+static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       char *pos;
+       int id;
+       struct wpa_ssid *ssid;
+       u8 peer[ETH_ALEN];
+
+       id = atoi(cmd);
+       pos = os_strstr(cmd, " peer=");
+       if (pos) {
+               pos += 6;
+               if (hwaddr_aton(pos, peer))
+                       return -1;
+       }
+       ssid = wpa_config_get_network(wpa_s->conf, id);
+       if (ssid == NULL || ssid->disabled != 2) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
+                          "for persistent P2P group",
+                          id);
+               return -1;
+       }
+
+       return wpas_p2p_invite(wpa_s, pos ? peer : NULL, ssid, NULL);
+}
+
+
+static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       char *pos;
+       u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL;
+
+       pos = os_strstr(cmd, " peer=");
+       if (!pos)
+               return -1;
+
+       *pos = '\0';
+       pos += 6;
+       if (hwaddr_aton(pos, peer)) {
+               wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos);
+               return -1;
+       }
+
+       pos = os_strstr(pos, " go_dev_addr=");
+       if (pos) {
+               pos += 13;
+               if (hwaddr_aton(pos, go_dev_addr)) {
+                       wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'",
+                                  pos);
+                       return -1;
+               }
+               go_dev = go_dev_addr;
+       }
+
+       return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev);
+}
+
+
+static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       if (os_strncmp(cmd, "persistent=", 11) == 0)
+               return p2p_ctrl_invite_persistent(wpa_s, cmd + 11);
+       if (os_strncmp(cmd, "group=", 6) == 0)
+               return p2p_ctrl_invite_group(wpa_s, cmd + 6);
+
+       return -1;
+}
+
+
+static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
+                                        char *cmd, int freq)
+{
+       int id;
+       struct wpa_ssid *ssid;
+
+       id = atoi(cmd);
+       ssid = wpa_config_get_network(wpa_s->conf, id);
+       if (ssid == NULL || ssid->disabled != 2) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
+                          "for persistent P2P group",
+                          id);
+               return -1;
+       }
+
+       return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq);
+}
+
+
+static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       int freq = 0;
+       char *pos;
+
+       pos = os_strstr(cmd, "freq=");
+       if (pos)
+               freq = atoi(pos + 5);
+
+       if (os_strncmp(cmd, "persistent=", 11) == 0)
+               return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq);
+       if (os_strcmp(cmd, "persistent") == 0 ||
+           os_strncmp(cmd, "persistent ", 11) == 0)
+               return wpas_p2p_group_add(wpa_s, 1, freq);
+       if (os_strncmp(cmd, "freq=", 5) == 0)
+               return wpas_p2p_group_add(wpa_s, 0, freq);
+
+       wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
+                  cmd);
+       return -1;
+}
+
+
+static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
+                        char *buf, size_t buflen)
+{
+       u8 addr[ETH_ALEN], *addr_ptr;
+       int next;
+
+       if (!wpa_s->global->p2p)
+               return -1;
+
+       if (os_strcmp(cmd, "FIRST") == 0) {
+               addr_ptr = NULL;
+               next = 0;
+       } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
+               if (hwaddr_aton(cmd + 5, addr) < 0)
+                       return -1;
+               addr_ptr = addr;
+               next = 1;
+       } else {
+               if (hwaddr_aton(cmd, addr) < 0)
+                       return -1;
+               addr_ptr = addr;
+               next = 0;
+       }
+
+       return p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next,
+                                buf, buflen);
+}
+
+
+static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       char *param;
+
+       if (wpa_s->global->p2p == NULL)
+               return -1;
+
+       param = os_strchr(cmd, ' ');
+       if (param == NULL)
+               return -1;
+       *param++ = '\0';
+
+       if (os_strcmp(cmd, "discoverability") == 0) {
+               p2p_set_client_discoverability(wpa_s->global->p2p,
+                                              atoi(param));
+               return 0;
+       }
+
+       if (os_strcmp(cmd, "managed") == 0) {
+               p2p_set_managed_oper(wpa_s->global->p2p, atoi(param));
+               return 0;
+       }
+
+       if (os_strcmp(cmd, "listen_channel") == 0) {
+               return p2p_set_listen_channel(wpa_s->global->p2p, 81,
+                                             atoi(param));
+       }
+
+       if (os_strcmp(cmd, "ssid_postfix") == 0) {
+               return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param,
+                                           os_strlen(param));
+       }
+
+       if (os_strcmp(cmd, "noa") == 0) {
+               char *pos;
+               int count, start, duration;
+               /* GO NoA parameters: count,start_offset(ms),duration(ms) */
+               count = atoi(param);
+               pos = os_strchr(param, ',');
+               if (pos == NULL)
+                       return -1;
+               pos++;
+               start = atoi(pos);
+               pos = os_strchr(pos, ',');
+               if (pos == NULL)
+                       return -1;
+               pos++;
+               duration = atoi(pos);
+               if (count < 0 || count > 255 || start < 0 || duration < 0)
+                       return -1;
+               if (count == 0 && duration > 0)
+                       return -1;
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d "
+                          "start=%d duration=%d", count, start, duration);
+               return wpas_p2p_set_noa(wpa_s, count, start, duration);
+       }
+
+       if (os_strcmp(cmd, "ps") == 0)
+               return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1);
+
+       if (os_strcmp(cmd, "oppps") == 0)
+               return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1);
+
+       if (os_strcmp(cmd, "ctwindow") == 0)
+               return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param));
+
+       if (os_strcmp(cmd, "disabled") == 0) {
+               wpa_s->global->p2p_disabled = atoi(param);
+               wpa_printf(MSG_DEBUG, "P2P functionality %s",
+                          wpa_s->global->p2p_disabled ?
+                          "disabled" : "enabled");
+               if (wpa_s->global->p2p_disabled) {
+                       wpas_p2p_stop_find(wpa_s);
+                       os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+                       p2p_flush(wpa_s->global->p2p);
+               }
+               return 0;
+       }
+
+       if (os_strcmp(cmd, "force_long_sd") == 0) {
+               wpa_s->force_long_sd = atoi(param);
+               return 0;
+       }
+
+       if (os_strcmp(cmd, "peer_filter") == 0) {
+               u8 addr[ETH_ALEN];
+               if (hwaddr_aton(param, addr))
+                       return -1;
+               p2p_set_peer_filter(wpa_s->global->p2p, addr);
+               return 0;
+       }
+
+       if (os_strcmp(cmd, "cross_connect") == 0)
+               return wpas_p2p_set_cross_connect(wpa_s, atoi(param));
+
+       if (os_strcmp(cmd, "go_apsd") == 0) {
+               if (os_strcmp(param, "disable") == 0)
+                       wpa_s->set_ap_uapsd = 0;
+               else {
+                       wpa_s->set_ap_uapsd = 1;
+                       wpa_s->ap_uapsd = atoi(param);
+               }
+               return 0;
+       }
+
+       if (os_strcmp(cmd, "client_apsd") == 0) {
+               if (os_strcmp(param, "disable") == 0)
+                       wpa_s->set_sta_uapsd = 0;
+               else {
+                       int be, bk, vi, vo;
+                       char *pos;
+                       /* format: BE,BK,VI,VO;max SP Length */
+                       be = atoi(param);
+                       pos = os_strchr(param, ',');
+                       if (pos == NULL)
+                               return -1;
+                       pos++;
+                       bk = atoi(pos);
+                       pos = os_strchr(pos, ',');
+                       if (pos == NULL)
+                               return -1;
+                       pos++;
+                       vi = atoi(pos);
+                       pos = os_strchr(pos, ',');
+                       if (pos == NULL)
+                               return -1;
+                       pos++;
+                       vo = atoi(pos);
+                       /* ignore max SP Length for now */
+
+                       wpa_s->set_sta_uapsd = 1;
+                       wpa_s->sta_uapsd = 0;
+                       if (be)
+                               wpa_s->sta_uapsd |= BIT(0);
+                       if (bk)
+                               wpa_s->sta_uapsd |= BIT(1);
+                       if (vi)
+                               wpa_s->sta_uapsd |= BIT(2);
+                       if (vo)
+                               wpa_s->sta_uapsd |= BIT(3);
+               }
+               return 0;
+       }
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
+                  cmd);
+
+       return -1;
+}
+
+
+static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       char *pos, *pos2;
+       unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
+
+       if (cmd[0]) {
+               pos = os_strchr(cmd, ' ');
+               if (pos == NULL)
+                       return -1;
+               *pos++ = '\0';
+               dur1 = atoi(cmd);
+
+               pos2 = os_strchr(pos, ' ');
+               if (pos2)
+                       *pos2++ = '\0';
+               int1 = atoi(pos);
+       } else
+               pos2 = NULL;
+
+       if (pos2) {
+               pos = os_strchr(pos2, ' ');
+               if (pos == NULL)
+                       return -1;
+               *pos++ = '\0';
+               dur2 = atoi(pos2);
+               int2 = atoi(pos);
+       }
+
+       return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2);
+}
+
+
+static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       char *pos;
+       unsigned int period = 0, interval = 0;
+
+       if (cmd[0]) {
+               pos = os_strchr(cmd, ' ');
+               if (pos == NULL)
+                       return -1;
+               *pos++ = '\0';
+               period = atoi(cmd);
+               interval = atoi(pos);
+       }
+
+       return wpas_p2p_ext_listen(wpa_s, period, interval);
+}
+
+#endif /* CONFIG_P2P */
+
+
+#ifdef CONFIG_INTERWORKING
+static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
+{
+       u8 bssid[ETH_ALEN];
+       struct wpa_bss *bss;
+
+       if (hwaddr_aton(dst, bssid)) {
+               wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst);
+               return -1;
+       }
+
+       bss = wpa_bss_get_bssid(wpa_s, bssid);
+       if (bss == NULL) {
+               wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
+                          MAC2STR(bssid));
+               return -1;
+       }
+
+       return interworking_connect(wpa_s, bss);
+}
+
+
+static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
+{
+       u8 dst_addr[ETH_ALEN];
+       int used;
+       char *pos;
+#define MAX_ANQP_INFO_ID 100
+       u16 id[MAX_ANQP_INFO_ID];
+       size_t num_id = 0;
+
+       used = hwaddr_aton2(dst, dst_addr);
+       if (used < 0)
+               return -1;
+       pos = dst + used;
+       while (num_id < MAX_ANQP_INFO_ID) {
+               id[num_id] = atoi(pos);
+               if (id[num_id])
+                       num_id++;
+               pos = os_strchr(pos + 1, ',');
+               if (pos == NULL)
+                       break;
+               pos++;
+       }
+
+       if (num_id == 0)
+               return -1;
+
+       return anqp_send_req(wpa_s, dst_addr, id, num_id);
+}
+#endif /* CONFIG_INTERWORKING */
+
+
+static int wpa_supplicant_ctrl_iface_sta_autoconnect(
+       struct wpa_supplicant *wpa_s, char *cmd)
+{
+       wpa_s->auto_reconnect_disabled = atoi(cmd) == 0 ? 1 : 0;
+       return 0;
+}
+
+
+static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
+                                     size_t buflen)
+{
+       struct wpa_signal_info si;
+       int ret;
+
+       ret = wpa_drv_signal_poll(wpa_s, &si);
+       if (ret)
+               return -1;
+
+       ret = os_snprintf(buf, buflen, "RSSI=%d\nLINKSPEED=%d\n"
+                         "NOISE=%d\nFREQUENCY=%u\n",
+                         si.current_signal, si.current_txrate / 1000,
+                         si.current_noise, si.frequency);
+       if (ret < 0 || (unsigned int) ret > buflen)
+               return -1;
+       return ret;
+}
+
+
+char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
+                                        char *buf, size_t *resp_len)
+{
+       char *reply;
+       const int reply_size = 4096;
+       int ctrl_rsp = 0;
+       int reply_len;
+
+       if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
+           os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
+               wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
+                                     (const u8 *) buf, os_strlen(buf));
+       } else {
+               int level = MSG_DEBUG;
+               if (os_strcmp(buf, "PING") == 0)
+                       level = MSG_EXCESSIVE;
+               wpa_hexdump_ascii(level, "RX ctrl_iface",
+                                 (const u8 *) buf, os_strlen(buf));
+       }
+
+       reply = os_malloc(reply_size);
+       if (reply == NULL) {
+               *resp_len = 1;
+               return NULL;
+       }
+
+       os_memcpy(reply, "OK\n", 3);
+       reply_len = 3;
+
+       if (os_strcmp(buf, "PING") == 0) {
+               os_memcpy(reply, "PONG\n", 5);
+               reply_len = 5;
+       } else if (os_strncmp(buf, "RELOG", 5) == 0) {
+               if (wpa_debug_reopen_file() < 0)
                        reply_len = -1;
+       } else if (os_strncmp(buf, "NOTE ", 5) == 0) {
+               wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
+       } else if (os_strcmp(buf, "MIB") == 0) {
+               reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
+               if (reply_len >= 0) {
+                       int res;
+                       res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
+                                              reply_size - reply_len);
+                       if (res < 0)
+                               reply_len = -1;
+                       else
+                               reply_len += res;
+               }
+       } else if (os_strncmp(buf, "STATUS", 6) == 0) {
+               reply_len = wpa_supplicant_ctrl_iface_status(
+                       wpa_s, buf + 6, reply, reply_size);
+       } else if (os_strcmp(buf, "PMKSA") == 0) {
+               reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
+                                                   reply_size);
+       } else if (os_strncmp(buf, "SET ", 4) == 0) {
+               if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "GET ", 4) == 0) {
+               reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
+                                                         reply, reply_size);
        } else if (os_strcmp(buf, "LOGON") == 0) {
                eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
        } else if (os_strcmp(buf, "LOGOFF") == 0) {
                eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
        } else if (os_strcmp(buf, "REASSOCIATE") == 0) {
-               wpa_s->disconnected = 0;
-               wpa_s->reassociate = 1;
-               wpa_supplicant_req_scan(wpa_s, 0, 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 if (os_strcmp(buf, "RECONNECT") == 0) {
-               if (wpa_s->disconnected) {
+               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);
@@ -1768,15 +3393,29 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_IEEE80211R */
 #ifdef CONFIG_WPS
        } else if (os_strcmp(buf, "WPS_PBC") == 0) {
-               if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL))
+               int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL);
+               if (res == -2) {
+                       os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
+                       reply_len = 17;
+               } else if (res)
                        reply_len = -1;
        } else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
-               if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8))
+               int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8);
+               if (res == -2) {
+                       os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
+                       reply_len = 17;
+               } else if (res)
                        reply_len = -1;
        } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
                reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
                                                              reply,
                                                              reply_size);
+       } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
+               reply_len = wpa_supplicant_ctrl_iface_wps_check_pin(
+                       wpa_s, buf + 14, reply, reply_size);
+       } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
+               if (wpas_wps_cancel(wpa_s))
+                       reply_len = -1;
 #ifdef CONFIG_WPS_OOB
        } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
                if (wpa_supplicant_ctrl_iface_wps_oob(wpa_s, buf + 8))
@@ -1785,9 +3424,17 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
                if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
                        reply_len = -1;
+#ifdef CONFIG_AP
+       } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
+               reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin(
+                       wpa_s, buf + 11, reply, reply_size);
+#endif /* CONFIG_AP */
 #ifdef CONFIG_WPS_ER
        } else if (os_strcmp(buf, "WPS_ER_START") == 0) {
-               if (wpas_wps_er_start(wpa_s))
+               if (wpas_wps_er_start(wpa_s, NULL))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) {
+               if (wpas_wps_er_start(wpa_s, buf + 13))
                        reply_len = -1;
        } else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
                if (wpas_wps_er_stop(wpa_s))
@@ -1796,11 +3443,28 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
                        reply_len = -1;
        } else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) {
-               if (wpas_wps_er_pbc(wpa_s, buf + 11))
+               int ret = wpas_wps_er_pbc(wpa_s, buf + 11);
+               if (ret == -2) {
+                       os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
+                       reply_len = 17;
+               } else if (ret == -3) {
+                       os_memcpy(reply, "FAIL-UNKNOWN-UUID\n", 18);
+                       reply_len = 18;
+               } else if (ret == -4) {
+                       os_memcpy(reply, "FAIL-NO-AP-SETTINGS\n", 20);
+                       reply_len = 20;
+               } else if (ret)
                        reply_len = -1;
        } else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) {
                if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13))
                        reply_len = -1;
+       } else if (os_strncmp(buf, "WPS_ER_SET_CONFIG ", 18) == 0) {
+               if (wpa_supplicant_ctrl_iface_wps_er_set_config(wpa_s,
+                                                               buf + 18))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
+               if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
+                       reply_len = -1;
 #endif /* CONFIG_WPS_ER */
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_IBSS_RSN
@@ -1808,6 +3472,113 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
                        reply_len = -1;
 #endif /* CONFIG_IBSS_RSN */
+#ifdef CONFIG_P2P
+       } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
+               if (p2p_ctrl_find(wpa_s, buf + 9))
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "P2P_FIND") == 0) {
+               if (p2p_ctrl_find(wpa_s, ""))
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
+               wpas_p2p_stop_find(wpa_s);
+       } else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
+               reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
+                                            reply_size);
+       } else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) {
+               if (p2p_ctrl_listen(wpa_s, buf + 11))
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "P2P_LISTEN") == 0) {
+               if (p2p_ctrl_listen(wpa_s, ""))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) {
+               if (wpas_p2p_group_remove(wpa_s, buf + 17))
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
+               if (wpas_p2p_group_add(wpa_s, 0, 0))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
+               if (p2p_ctrl_group_add(wpa_s, buf + 14))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
+               if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) {
+               reply_len = p2p_get_passphrase(wpa_s, reply, reply_size);
+       } else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) {
+               reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply,
+                                                  reply_size);
+       } else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) {
+               if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) {
+               if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0)
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) {
+               wpas_p2p_sd_service_update(wpa_s);
+       } else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) {
+               if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0)
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) {
+               wpas_p2p_service_flush(wpa_s);
+       } else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) {
+               if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
+               if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
+               if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) {
+               if (p2p_ctrl_invite(wpa_s, buf + 11) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) {
+               reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply,
+                                             reply_size);
+       } else if (os_strncmp(buf, "P2P_SET ", 8) == 0) {
+               if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
+               os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+               wpa_s->force_long_sd = 0;
+               if (wpa_s->global->p2p)
+                       p2p_flush(wpa_s->global->p2p);
+       } else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
+               if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "P2P_CANCEL") == 0) {
+               if (wpas_p2p_cancel(wpa_s))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) {
+               if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0)
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) {
+               if (p2p_ctrl_presence_req(wpa_s, "") < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) {
+               if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0)
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
+               if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
+                       reply_len = -1;
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+       } else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
+               if (interworking_fetch_anqp(wpa_s) < 0)
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
+               interworking_stop_fetch_anqp(wpa_s);
+       } else if (os_strncmp(buf, "INTERWORKING_SELECT", 19) == 0) {
+               if (interworking_select(wpa_s, os_strstr(buf + 19, "auto") !=
+                                       NULL) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
+               if (ctrl_interworking_connect(wpa_s, buf + 21) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
+               if (get_anqp(wpa_s, buf + 9) < 0)
+                       reply_len = -1;
+#endif /* CONFIG_INTERWORKING */
        } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
        {
                if (wpa_supplicant_ctrl_iface_ctrl_rsp(
@@ -1823,17 +3594,38 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "BSSID ", 6) == 0) {
                if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
                        reply_len = -1;
+       } else if (os_strncmp(buf, "BLACKLIST", 9) == 0) {
+               reply_len = wpa_supplicant_ctrl_iface_blacklist(
+                       wpa_s, buf + 9, reply, reply_size);
+       } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
+               reply_len = wpa_supplicant_ctrl_iface_log_level(
+                       wpa_s, buf + 9, reply, reply_size);
        } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
                reply_len = wpa_supplicant_ctrl_iface_list_networks(
                        wpa_s, reply, reply_size);
        } else if (os_strcmp(buf, "DISCONNECT") == 0) {
                wpa_s->reassociate = 0;
                wpa_s->disconnected = 1;
+               wpa_supplicant_cancel_sched_scan(wpa_s);
                wpa_supplicant_deauthenticate(wpa_s,
                                              WLAN_REASON_DEAUTH_LEAVING);
        } else if (os_strcmp(buf, "SCAN") == 0) {
-               wpa_s->scan_req = 2;
-               wpa_supplicant_req_scan(wpa_s, 0, 0);
+               wpa_s->normal_scans = 0;
+               if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+                       reply_len = -1;
+               else {
+                       if (!wpa_s->scanning &&
+                           ((wpa_s->wpa_state <= WPA_SCANNING) ||
+                            (wpa_s->wpa_state == WPA_COMPLETED))) {
+                               wpa_s->scan_req = 2;
+                               wpa_supplicant_req_scan(wpa_s, 0, 0);
+                       } else {
+                               wpa_printf(MSG_DEBUG, "Ongoing scan action - "
+                                          "reject new request");
+                               reply_len = os_snprintf(reply, reply_size,
+                                                       "FAIL-BUSY\n");
+                       }
+               }
        } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
                reply_len = wpa_supplicant_ctrl_iface_scan_results(
                        wpa_s, reply, reply_size);
@@ -1869,6 +3661,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
                if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
                        reply_len = -1;
+       } else if (os_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) {
+               if (wpa_supplicant_ctrl_iface_scan_interval(wpa_s, buf + 14))
+                       reply_len = -1;
        } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
                reply_len = wpa_supplicant_global_iface_list(
                        wpa_s->global, reply, reply_size);
@@ -1897,6 +3692,32 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "ROAM ", 5) == 0) {
                if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
                        reply_len = -1;
+       } else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
+               if (wpa_supplicant_ctrl_iface_sta_autoconnect(wpa_s, buf + 16))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) {
+               if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "BSS_EXPIRE_COUNT ", 17) == 0) {
+               if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s,
+                                                              buf + 17))
+                       reply_len = -1;
+#ifdef CONFIG_TDLS
+       } else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
+               if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "TDLS_SETUP ", 11) == 0) {
+               if (wpa_supplicant_ctrl_iface_tdls_setup(wpa_s, buf + 11))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
+               if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
+                       reply_len = -1;
+#endif /* CONFIG_TDLS */
+       } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
+               reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
+                                                      reply_size);
+       } else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
+               eapol_sm_request_reauth(wpa_s->eapol);
        } else {
                os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
                reply_len = 16;
@@ -2093,8 +3914,11 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
        char *reply;
        const int reply_size = 2048;
        int reply_len;
+       int level = MSG_DEBUG;
 
-       wpa_hexdump_ascii(MSG_DEBUG, "RX global ctrl_iface",
+       if (os_strcmp(buf, "PING") == 0)
+               level = MSG_EXCESSIVE;
+       wpa_hexdump_ascii(level, "RX global ctrl_iface",
                          (const u8 *) buf, os_strlen(buf));
 
        reply = os_malloc(reply_size);
index 051d99a..88ae6b7 100644 (file)
@@ -95,6 +95,21 @@ 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 84ac760..306a222 100644 (file)
@@ -17,6 +17,9 @@
 #include <sys/stat.h>
 #include <grp.h>
 #include <stddef.h>
+#ifdef ANDROID
+#include <cutils/sockets.h>
+#endif /* ANDROID */
 
 #include "utils/common.h"
 #include "utils/eloop.h"
@@ -132,7 +135,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
 {
        struct wpa_supplicant *wpa_s = eloop_ctx;
        struct ctrl_iface_priv *priv = sock_ctx;
-       char buf[256];
+       char buf[4096];
        int res;
        struct sockaddr_un from;
        socklen_t fromlen = sizeof(from);
@@ -276,6 +279,13 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
        buf = os_strdup(wpa_s->conf->ctrl_interface);
        if (buf == NULL)
                goto fail;
+#ifdef ANDROID
+       os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s",
+                   wpa_s->conf->ctrl_interface);
+       priv->sock = android_get_control_socket(addr.sun_path);
+       if (priv->sock >= 0)
+               goto havesock;
+#endif /* ANDROID */
        if (os_strncmp(buf, "DIR=", 4) == 0) {
                dir = buf + 4;
                gid_str = os_strstr(dir, " GROUP=");
@@ -398,6 +408,9 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
        }
        os_free(fname);
 
+#ifdef ANDROID
+havesock:
+#endif /* ANDROID */
        eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
                                 wpa_s, priv);
        wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
@@ -637,6 +650,12 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
        if (global->params.ctrl_interface == NULL)
                return priv;
 
+#ifdef ANDROID
+       priv->sock = android_get_control_socket(global->params.ctrl_interface);
+       if (priv->sock >= 0)
+               goto havesock;
+#endif /* ANDROID */
+
        wpa_printf(MSG_DEBUG, "Global control interface '%s'",
                   global->params.ctrl_interface);
 
@@ -685,6 +704,9 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
                }
        }
 
+#ifdef ANDROID
+havesock:
+#endif /* ANDROID */
        eloop_register_read_sock(priv->sock,
                                 wpa_supplicant_global_ctrl_iface_receive,
                                 global, NULL);
diff --git a/wpa_supplicant/dbus/.gitignore b/wpa_supplicant/dbus/.gitignore
deleted file mode 100644 (file)
index 6db2468..0000000
+++ /dev/null
@@ -1 +0,0 @@
-libwpadbus.a
index cfaf58d..a088200 100644 (file)
@@ -15,6 +15,7 @@ ifndef CFLAGS
 CFLAGS = -MMD -O2 -Wall -g
 endif
 
+PKG_CONFIG ?= pkg-config
 CFLAGS += -I../../src -I../../src/utils
 
 
@@ -38,10 +39,10 @@ CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW
 CFLAGS += -DCONFIG_CTRL_IFACE_DBUS
 
 ifndef DBUS_LIBS
-DBUS_LIBS := $(shell pkg-config --libs dbus-1)
+DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1)
 endif
 ifndef DBUS_INCLUDE
-DBUS_INCLUDE := $(shell pkg-config --cflags dbus-1)
+DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1)
 endif
 ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
 CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
@@ -49,7 +50,7 @@ DBUS_INCLUDE += $(shell xml2-config --cflags)
 DBUS_LIBS += $(shell xml2-config --libs)
 endif
 
-dbus_version=$(subst ., ,$(shell pkg-config --modversion dbus-1))
+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),)
index f9da79a..728fe06 100644 (file)
                 <allow send_interface="fi.w1.wpa_supplicant1"/>
                 <allow receive_sender="fi.w1.wpa_supplicant1" receive_type="signal"/>
         </policy>
+        <policy user="5000">
+                <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 context="default">
                 <deny own="fi.epitest.hostap.WPASupplicant"/>
                 <deny send_destination="fi.epitest.hostap.WPASupplicant"/>
index b3aff40..5f9e64a 100644 (file)
@@ -16,6 +16,7 @@
 #include <dbus/dbus.h>
 
 #include "common.h"
+#include "wpabuf.h"
 #include "dbus_dict_helpers.h"
 
 
@@ -443,11 +444,12 @@ dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
 
 
 /**
- * Begin a string array entry in the dict
+ * Begin an array entry in the dict
  *
  * @param iter_dict A valid DBusMessageIter returned from
  *                  wpa_dbus_dict_open_write()
  * @param key The key of the dict item
+ * @param type The type of the contained data
  * @param iter_dict_entry A private DBusMessageIter provided by the caller to
  *                        be passed to wpa_dbus_dict_end_string_array()
  * @param iter_dict_val A private DBusMessageIter provided by the caller to
@@ -457,12 +459,21 @@ dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
  * @return TRUE on success, FALSE on failure
  *
  */
-dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
-                                            const char *key,
-                                            DBusMessageIter *iter_dict_entry,
-                                            DBusMessageIter *iter_dict_val,
-                                            DBusMessageIter *iter_array)
+dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict,
+                                     const char *key, const char *type,
+                                     DBusMessageIter *iter_dict_entry,
+                                     DBusMessageIter *iter_dict_val,
+                                     DBusMessageIter *iter_array)
 {
+       char array_type[10];
+       int err;
+
+       err = os_snprintf(array_type, sizeof(array_type),
+                         DBUS_TYPE_ARRAY_AS_STRING "%s",
+                         type);
+       if (err < 0 || err > (int) sizeof(array_type))
+               return FALSE;
+
        if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
                return FALSE;
 
@@ -472,20 +483,31 @@ dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
 
        if (!dbus_message_iter_open_container(iter_dict_entry,
                                              DBUS_TYPE_VARIANT,
-                                             DBUS_TYPE_ARRAY_AS_STRING
-                                             DBUS_TYPE_STRING_AS_STRING,
+                                             array_type,
                                              iter_dict_val))
                return FALSE;
 
        if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
-                                             DBUS_TYPE_BYTE_AS_STRING,
-                                             iter_array))
+                                             type, iter_array))
                return FALSE;
 
        return TRUE;
 }
 
 
+dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
+                                            const char *key,
+                                            DBusMessageIter *iter_dict_entry,
+                                            DBusMessageIter *iter_dict_val,
+                                            DBusMessageIter *iter_array)
+{
+       return wpa_dbus_dict_begin_array(
+               iter_dict, key,
+               DBUS_TYPE_STRING_AS_STRING,
+               iter_dict_entry, iter_dict_val, iter_array);
+}
+
+
 /**
  * Add a single string element to a string array dict entry
  *
@@ -508,23 +530,67 @@ dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
 
 
 /**
- * End a string array dict entry
+ * Add a single byte array element to a string array dict entry
+ *
+ * @param iter_array A valid DBusMessageIter returned from
+ *                   wpa_dbus_dict_begin_array()'s iter_array
+ *                   parameter -- note that wpa_dbus_dict_begin_array()
+ *                   must have been called with "ay" as the type
+ * @param value The data to be added to the dict entry's array
+ * @param value_len The length of the data
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array,
+                                               const u8 *value,
+                                               size_t value_len)
+{
+       DBusMessageIter iter_bytes;
+       size_t i;
+
+       if (!iter_array || !value)
+               return FALSE;
+
+       if (!dbus_message_iter_open_container(iter_array, DBUS_TYPE_ARRAY,
+                                             DBUS_TYPE_BYTE_AS_STRING,
+                                             &iter_bytes))
+               return FALSE;
+
+       for (i = 0; i < value_len; i++) {
+               if (!dbus_message_iter_append_basic(&iter_bytes,
+                                                   DBUS_TYPE_BYTE,
+                                                   &(value[i])))
+                       return FALSE;
+       }
+
+       if (!dbus_message_iter_close_container(iter_array, &iter_bytes))
+               return FALSE;
+
+       return TRUE;
+}
+
+
+/**
+ * End an array dict entry
  *
  * @param iter_dict A valid DBusMessageIter returned from
  *                  wpa_dbus_dict_open_write()
  * @param iter_dict_entry A private DBusMessageIter returned from
- *                        wpa_dbus_dict_end_string_array()
+ *                        wpa_dbus_dict_begin_string_array() or
+ *                       wpa_dbus_dict_begin_array()
  * @param iter_dict_val A private DBusMessageIter returned from
- *                      wpa_dbus_dict_end_string_array()
+ *                      wpa_dbus_dict_begin_string_array() or
+ *                     wpa_dbus_dict_begin_array()
  * @param iter_array A DBusMessageIter returned from
- *                   wpa_dbus_dict_end_string_array()
+ *                   wpa_dbus_dict_begin_string_array() or
+ *                  wpa_dbus_dict_begin_array()
  * @return TRUE on success, FALSE on failure
  *
  */
-dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
-                                          DBusMessageIter *iter_dict_entry,
-                                          DBusMessageIter *iter_dict_val,
-                                          DBusMessageIter *iter_array)
+dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict,
+                                   DBusMessageIter *iter_dict_entry,
+                                   DBusMessageIter *iter_dict_val,
+                                   DBusMessageIter *iter_array)
 {
        if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
                return FALSE;
@@ -583,6 +649,52 @@ dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
 }
 
 
+/**
+ * Convenience function to add an wpabuf binary array to the dict.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ *                  wpa_dbus_dict_open_write()
+ * @param key The key of the dict item
+ * @param items The array of wpabuf structures
+ * @param num_items The number of strings in the array
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict,
+                                             const char *key,
+                                             const struct wpabuf **items,
+                                             const dbus_uint32_t num_items)
+{
+       DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
+       dbus_uint32_t i;
+
+       if (!key)
+               return FALSE;
+       if (!items && (num_items != 0))
+               return FALSE;
+
+       if (!wpa_dbus_dict_begin_array(iter_dict, key,
+                                      DBUS_TYPE_ARRAY_AS_STRING
+                                      DBUS_TYPE_BYTE_AS_STRING,
+                                      &iter_dict_entry, &iter_dict_val,
+                                      &iter_array))
+               return FALSE;
+
+       for (i = 0; i < num_items; i++) {
+               if (!wpa_dbus_dict_bin_array_add_element(&iter_array,
+                                                        wpabuf_head(items[i]),
+                                                        wpabuf_len(items[i])))
+                       return FALSE;
+       }
+
+       if (!wpa_dbus_dict_end_array(iter_dict, &iter_dict_entry,
+                                    &iter_dict_val, &iter_array))
+               return FALSE;
+
+       return TRUE;
+}
+
+
 /*****************************************************/
 /* Stuff for reading dicts                           */
 /*****************************************************/
@@ -593,18 +705,26 @@ dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
  * @param iter A valid DBusMessageIter pointing to the start of the dict
  * @param iter_dict (out) A DBusMessageIter to be passed to
  *    wpa_dbus_dict_read_next_entry()
+ * @error on failure a descriptive error
  * @return TRUE on success, FALSE on failure
  *
  */
 dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
-                                   DBusMessageIter *iter_dict)
+                                   DBusMessageIter *iter_dict,
+                                   DBusError *error)
 {
-       if (!iter || !iter_dict)
+       if (!iter || !iter_dict) {
+               dbus_set_error_const(error, DBUS_ERROR_FAILED,
+                                    "[internal] missing message iterators");
                return FALSE;
+       }
 
        if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
-           dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY)
+           dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY) {
+               dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+                                    "unexpected message argument types");
                return FALSE;
+       }
 
        dbus_message_iter_recurse(iter, iter_dict);
        return TRUE;
@@ -615,8 +735,7 @@ dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
 #define BYTE_ARRAY_ITEM_SIZE (sizeof(char))
 
 static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
-       DBusMessageIter *iter, int array_type,
-       struct wpa_dbus_dict_entry *entry)
+       DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry)
 {
        dbus_uint32_t count = 0;
        dbus_bool_t success = FALSE;
@@ -733,6 +852,66 @@ done:
 }
 
 
+#define BIN_ARRAY_CHUNK_SIZE 10
+#define BIN_ARRAY_ITEM_SIZE (sizeof(struct wpabuf *))
+
+static dbus_bool_t _wpa_dbus_dict_entry_get_binarray(
+       DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry)
+{
+       struct wpa_dbus_dict_entry tmpentry;
+       size_t buflen = 0;
+       int i;
+
+       if (dbus_message_iter_get_element_type(iter) != DBUS_TYPE_BYTE)
+               return FALSE;
+
+       entry->array_type = WPAS_DBUS_TYPE_BINARRAY;
+       entry->array_len = 0;
+       entry->binarray_value = NULL;
+
+       while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY) {
+               DBusMessageIter iter_array;
+
+               if (entry->array_len == buflen) {
+                       struct wpabuf **newbuf;
+
+                       buflen += BIN_ARRAY_CHUNK_SIZE;
+
+                       newbuf = os_realloc(entry->binarray_value,
+                                           buflen * BIN_ARRAY_ITEM_SIZE);
+                       if (!newbuf)
+                               goto cleanup;
+                       entry->binarray_value = newbuf;
+               }
+
+               dbus_message_iter_recurse(iter, &iter_array);
+               if (_wpa_dbus_dict_entry_get_byte_array(&iter_array, &tmpentry)
+                                       == FALSE)
+                       goto cleanup;
+
+               entry->binarray_value[entry->array_len] =
+                       wpabuf_alloc_ext_data((u8 *) tmpentry.bytearray_value,
+                                             tmpentry.array_len);
+               if (entry->binarray_value[entry->array_len] == NULL) {
+                       wpa_dbus_dict_entry_clear(&tmpentry);
+                       goto cleanup;
+               }
+               entry->array_len++;
+               dbus_message_iter_next(iter);
+       }
+
+       return TRUE;
+
+ cleanup:
+       for (i = 0; i < (int) entry->array_len; i++)
+               wpabuf_free(entry->binarray_value[i]);
+       os_free(entry->binarray_value);
+       entry->array_len = 0;
+       entry->binarray_value = NULL;
+       return FALSE;
+}
+
+
 static dbus_bool_t _wpa_dbus_dict_entry_get_array(
        DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry)
 {
@@ -748,7 +927,6 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_array(
        switch (array_type) {
        case DBUS_TYPE_BYTE:
                success = _wpa_dbus_dict_entry_get_byte_array(&iter_array,
-                                                             array_type,
                                                              entry);
                break;
        case DBUS_TYPE_STRING:
@@ -756,6 +934,8 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_array(
                                                                array_type,
                                                                entry);
                break;
+       case DBUS_TYPE_ARRAY:
+               success = _wpa_dbus_dict_entry_get_binarray(&iter_array, entry);
        default:
                break;
        }
@@ -915,6 +1095,11 @@ void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry)
                                os_free(entry->strarray_value[i]);
                        os_free(entry->strarray_value);
                        break;
+               case WPAS_DBUS_TYPE_BINARRAY:
+                       for (i = 0; i < entry->array_len; i++)
+                               wpabuf_free(entry->binarray_value[i]);
+                       os_free(entry->binarray_value);
+                       break;
                }
                break;
        }
index eb31575..2f6eb45 100644 (file)
@@ -15,6 +15,8 @@
 #ifndef DBUS_DICT_HELPERS_H
 #define DBUS_DICT_HELPERS_H
 
+#include "wpabuf.h"
+
 /*
  * Adding a dict to a DBusMessage
  */
@@ -74,7 +76,13 @@ dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
                                            const char *value,
                                            const dbus_uint32_t value_len);
 
-/* Manual construction and addition of string array elements */
+/* Manual construction and addition of array elements */
+dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict,
+                                      const char *key, const char *type,
+                                      DBusMessageIter *iter_dict_entry,
+                                      DBusMessageIter *iter_dict_val,
+                                      DBusMessageIter *iter_array);
+
 dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
                                              const char *key,
                                              DBusMessageIter *iter_dict_entry,
@@ -84,10 +92,24 @@ dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
 dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
                                              const char *elem);
 
-dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
-                                           DBusMessageIter *iter_dict_entry,
-                                           DBusMessageIter *iter_dict_val,
-                                           DBusMessageIter *iter_array);
+dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array,
+                                               const u8 *value,
+                                               size_t value_len);
+
+dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict,
+                                    DBusMessageIter *iter_dict_entry,
+                                    DBusMessageIter *iter_dict_val,
+                                    DBusMessageIter *iter_array);
+
+static inline dbus_bool_t
+wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
+                              DBusMessageIter *iter_dict_entry,
+                              DBusMessageIter *iter_dict_val,
+                              DBusMessageIter *iter_array)
+{
+       return wpa_dbus_dict_end_array(iter_dict, iter_dict_entry,
+                                      iter_dict_val, iter_array);
+}
 
 /* Convenience function to add a whole string list */
 dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
@@ -95,14 +117,22 @@ dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
                                              const char **items,
                                              const dbus_uint32_t num_items);
 
+dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict,
+                                             const char *key,
+                                             const struct wpabuf **items,
+                                             const dbus_uint32_t num_items);
+
 /*
  * Reading a dict from a DBusMessage
  */
 
+#define WPAS_DBUS_TYPE_BINARRAY (DBUS_NUMBER_OF_TYPES + 100)
+
 struct wpa_dbus_dict_entry {
        int type;         /** the dbus type of the dict entry's value */
        int array_type;   /** the dbus type of the array elements if the dict
-                             entry value contains an array */
+                             entry value contains an array, or the special
+                             WPAS_DBUS_TYPE_BINARRAY */
        const char *key;  /** key of the dict entry */
 
        /** Possible values of the property */
@@ -119,13 +149,15 @@ struct wpa_dbus_dict_entry {
                double double_value;
                char *bytearray_value;
                char **strarray_value;
+               struct wpabuf **binarray_value;
        };
        dbus_uint32_t array_len; /** length of the array if the dict entry's
                                     value contains an array */
 };
 
 dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
-                                   DBusMessageIter *iter_dict);
+                                   DBusMessageIter *iter_dict,
+                                   DBusError *error);
 
 dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
                                    struct wpa_dbus_dict_entry *entry);
index bdfbbac..6cb43a5 100644 (file)
 #include "includes.h"
 
 #include "common.h"
+#include "common/ieee802_11_defs.h"
 #include "wps/wps.h"
 #include "../config.h"
 #include "../wpa_supplicant_i.h"
 #include "../bss.h"
+#include "../wpas_glue.h"
 #include "dbus_new_helpers.h"
 #include "dbus_dict_helpers.h"
 #include "dbus_new.h"
 #include "dbus_new_handlers.h"
-#include "dbus_common.h"
 #include "dbus_common_i.h"
+#include "dbus_new_handlers_p2p.h"
+#include "p2p/p2p.h"
 
 
 /**
@@ -42,7 +45,7 @@ static void wpas_dbus_signal_interface(struct wpa_supplicant *wpa_s,
 {
        struct wpas_dbus_priv *iface;
        DBusMessage *msg;
-       DBusMessageIter iter, iter_dict;
+       DBusMessageIter iter;
 
        iface = wpa_s->global->dbus;
 
@@ -61,14 +64,9 @@ static void wpas_dbus_signal_interface(struct wpa_supplicant *wpa_s,
                goto err;
 
        if (properties) {
-               if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
-                       goto err;
-
-               wpa_dbus_get_object_properties(iface, wpa_s->dbus_new_path,
-                                              WPAS_DBUS_NEW_IFACE_INTERFACE,
-                                              &iter_dict);
-
-               if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
+               if (!wpa_dbus_get_object_properties(
+                           iface, wpa_s->dbus_new_path,
+                           WPAS_DBUS_NEW_IFACE_INTERFACE, &iter))
                        goto err;
        }
 
@@ -157,7 +155,7 @@ static void wpas_dbus_signal_bss(struct wpa_supplicant *wpa_s,
 {
        struct wpas_dbus_priv *iface;
        DBusMessage *msg;
-       DBusMessageIter iter, iter_dict;
+       DBusMessageIter iter;
 
        iface = wpa_s->global->dbus;
 
@@ -177,14 +175,9 @@ static void wpas_dbus_signal_bss(struct wpa_supplicant *wpa_s,
                goto err;
 
        if (properties) {
-               if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
-                       goto err;
-
-               wpa_dbus_get_object_properties(iface, bss_obj_path,
-                                              WPAS_DBUS_NEW_IFACE_BSS,
-                                              &iter_dict);
-
-               if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
+               if (!wpa_dbus_get_object_properties(iface, bss_obj_path,
+                                                   WPAS_DBUS_NEW_IFACE_BSS,
+                                                   &iter))
                        goto err;
        }
 
@@ -304,7 +297,7 @@ static void wpas_dbus_signal_network(struct wpa_supplicant *wpa_s,
 {
        struct wpas_dbus_priv *iface;
        DBusMessage *msg;
-       DBusMessageIter iter, iter_dict;
+       DBusMessageIter iter;
        char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
 
        iface = wpa_s->global->dbus;
@@ -330,14 +323,9 @@ static void wpas_dbus_signal_network(struct wpa_supplicant *wpa_s,
                goto err;
 
        if (properties) {
-               if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
-                       goto err;
-
-               wpa_dbus_get_object_properties(iface, net_obj_path,
-                                              WPAS_DBUS_NEW_IFACE_NETWORK,
-                                              &iter_dict);
-
-               if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
+               if (!wpa_dbus_get_object_properties(
+                           iface, net_obj_path, WPAS_DBUS_NEW_IFACE_NETWORK,
+                           &iter))
                        goto err;
        }
 
@@ -394,6 +382,67 @@ void wpas_dbus_signal_network_selected(struct wpa_supplicant *wpa_s, int id)
 
 
 /**
+ * wpas_dbus_signal_network_request - Indicate that additional information
+ * (EAP password, etc.) is required to complete the association to this SSID
+ * @wpa_s: %wpa_supplicant network interface data
+ * @rtype: The specific additional information required
+ * @default_text: Optional description of required information
+ *
+ * Request additional information or passwords to complete an association
+ * request.
+ */
+void wpas_dbus_signal_network_request(struct wpa_supplicant *wpa_s,
+                                     struct wpa_ssid *ssid,
+                                     enum wpa_ctrl_req_type rtype,
+                                     const char *default_txt)
+{
+       struct wpas_dbus_priv *iface;
+       DBusMessage *msg;
+       DBusMessageIter iter;
+       char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+       const char *field, *txt = NULL, *net_ptr;
+
+       iface = wpa_s->global->dbus;
+
+       /* Do nothing if the control interface is not turned on */
+       if (iface == NULL)
+               return;
+
+       field = wpa_supplicant_ctrl_req_to_string(rtype, default_txt, &txt);
+       if (field == NULL)
+               return;
+
+       msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+                                     WPAS_DBUS_NEW_IFACE_INTERFACE,
+                                     "NetworkRequest");
+       if (msg == NULL)
+               return;
+
+       os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
+                   wpa_s->dbus_new_path, ssid->id);
+       net_ptr = &net_obj_path[0];
+
+       dbus_message_iter_init_append(msg, &iter);
+       if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+                                           &net_ptr))
+               goto err;
+       if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &field))
+               goto err;
+       if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &txt))
+               goto err;
+
+       dbus_connection_send(iface->con, msg, NULL);
+       dbus_message_unref(msg);
+       return;
+
+err:
+       wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+       dbus_message_unref(msg);
+}
+
+
+/**
  * wpas_dbus_signal_network_enabled_changed - Signals Enabled property changes
  * @wpa_s: %wpa_supplicant network interface data
  * @ssid: configured network which Enabled property has changed
@@ -650,861 +699,2578 @@ nomem:
 
 #endif /* CONFIG_WPS */
 
+void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
+                                   int depth, const char *subject,
+                                   const char *cert_hash,
+                                   const struct wpabuf *cert)
+{
+       struct wpas_dbus_priv *iface;
+       DBusMessage *msg;
+       DBusMessageIter iter, dict_iter;
+
+       iface = wpa_s->global->dbus;
+
+       /* Do nothing if the control interface is not turned on */
+       if (iface == NULL)
+               return;
+
+       msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+                                     WPAS_DBUS_NEW_IFACE_INTERFACE,
+                                     "Certification");
+       if (msg == NULL)
+               return;
+
+       dbus_message_iter_init_append(msg, &iter);
+       if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+               goto nomem;
+
+       if (!wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) ||
+           !wpa_dbus_dict_append_string(&dict_iter, "subject", subject))
+               goto nomem;
+
+       if (cert_hash &&
+           !wpa_dbus_dict_append_string(&dict_iter, "cert_hash", cert_hash))
+               goto nomem;
+
+       if (cert &&
+           !wpa_dbus_dict_append_byte_array(&dict_iter, "cert",
+                                            wpabuf_head(cert),
+                                            wpabuf_len(cert)))
+               goto nomem;
+
+       if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+               goto nomem;
+
+       dbus_connection_send(iface->con, msg, NULL);
+
+nomem:
+       dbus_message_unref(msg);
+}
+
+#ifdef CONFIG_P2P
 
 /**
- * wpas_dbus_signal_prop_changed - Signals change of property
+ * wpas_dbus_signal_p2p_group_removed - Signals P2P group was removed
  * @wpa_s: %wpa_supplicant network interface data
- * @property: indicates which property has changed
- *
- * Sends ProertyChanged signals with path, interface and arguments
- * depending on which property has changed.
+ * @role: role of this device (client or GO)
+ * Sends signal with i/f name and role as string arguments
  */
-void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
-                                  enum wpas_dbus_prop property)
+void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
+                                       const char *role)
 {
-       WPADBusPropertyAccessor getter;
-       char *prop;
 
-       if (wpa_s->dbus_new_path == NULL)
-               return; /* Skip signal since D-Bus setup is not yet ready */
+       DBusMessage *msg;
+       DBusMessageIter iter;
+       struct wpas_dbus_priv *iface = wpa_s->global->dbus;
+       char *ifname = wpa_s->ifname;
 
-       switch (property) {
-       case WPAS_DBUS_PROP_AP_SCAN:
-               getter = (WPADBusPropertyAccessor) wpas_dbus_getter_ap_scan;
-               prop = "ApScan";
-               break;
-       case WPAS_DBUS_PROP_SCANNING:
-               getter = (WPADBusPropertyAccessor) wpas_dbus_getter_scanning;
-               prop = "Scanning";
-               break;
-       case WPAS_DBUS_PROP_STATE:
-               getter = (WPADBusPropertyAccessor) wpas_dbus_getter_state;
-               prop = "State";
-               break;
-       case WPAS_DBUS_PROP_CURRENT_BSS:
-               getter = (WPADBusPropertyAccessor)
-                       wpas_dbus_getter_current_bss;
-               prop = "CurrentBSS";
-               break;
-       case WPAS_DBUS_PROP_CURRENT_NETWORK:
-               getter = (WPADBusPropertyAccessor)
-                       wpas_dbus_getter_current_network;
-               prop = "CurrentNetwork";
-               break;
-       default:
-               wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
-                          __func__, property);
+       /* Do nothing if the control interface is not turned on */
+       if (iface == NULL)
+               return;
+
+       msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+                                     WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+                                     "GroupFinished");
+       if (msg == NULL)
                return;
+
+       dbus_message_iter_init_append(msg, &iter);
+
+       if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &ifname)) {
+               wpa_printf(MSG_ERROR, "dbus: Failed to construct GroupFinished"
+                                     "signal -not enough memory for ifname ");
+               goto err;
        }
 
-       wpa_dbus_mark_property_changed(wpa_s->global->dbus,
-                                      wpa_s->dbus_new_path,
-                                      WPAS_DBUS_NEW_IFACE_INTERFACE, prop);
+       if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &role))
+               wpa_printf(MSG_ERROR, "dbus: Failed to construct GroupFinished"
+                                     "signal -not enough memory for role ");
+       else
+               dbus_connection_send(iface->con, msg, NULL);
+
+err:
+       dbus_message_unref(msg);
 }
 
 
 /**
- * wpas_dbus_bss_signal_prop_changed - Signals change of BSS property
- * @wpa_s: %wpa_supplicant network interface data
- * @property: indicates which property has changed
- * @id: unique BSS identifier
+ * wpas_dbus_signal_p2p_provision_discovery - Signals various PD events
  *
- * Sends PropertyChanged signals with path, interface, and arguments depending
- * on which property has changed.
+ * @dev_addr - who sent the request or responded to our request.
+ * @request - Will be 1 if request, 0 for response.
+ * @status - valid only in case of response
+ * @config_methods - wps config methods
+ * @generated_pin - pin to be displayed in case of WPS_CONFIG_DISPLAY method
+ *
+ * Sends following provision discovery related events:
+ *     ProvisionDiscoveryRequestDisplayPin
+ *     ProvisionDiscoveryResponseDisplayPin
+ *     ProvisionDiscoveryRequestEnterPin
+ *     ProvisionDiscoveryResponseEnterPin
+ *     ProvisionDiscoveryPBCRequest
+ *     ProvisionDiscoveryPBCResponse
+ *
+ *     TODO::
+ *     ProvisionDiscoveryFailure (timeout case)
  */
-void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s,
-                                      enum wpas_dbus_bss_prop property,
-                                      unsigned int id)
+void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+                                             const u8 *dev_addr, int request,
+                                             enum p2p_prov_disc_status status,
+                                             u16 config_methods,
+                                             unsigned int generated_pin)
 {
-       char path[WPAS_DBUS_OBJECT_PATH_MAX];
-       char *prop;
+       DBusMessage *msg;
+       DBusMessageIter iter;
+       struct wpas_dbus_priv *iface;
+       char *_signal;
+       int add_pin = 0;
+       char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+       int error_ret = 1;
+       char pin[9], *p_pin = NULL;
 
-       switch (property) {
-       case WPAS_DBUS_BSS_PROP_SIGNAL:
-               prop = "Signal";
-               break;
-       case WPAS_DBUS_BSS_PROP_FREQ:
-               prop = "Frequency";
-               break;
-       case WPAS_DBUS_BSS_PROP_MODE:
-               prop = "Mode";
-               break;
-       case WPAS_DBUS_BSS_PROP_PRIVACY:
-               prop = "Privacy";
-               break;
-       case WPAS_DBUS_BSS_PROP_RATES:
-               prop = "Rates";
-               break;
-       case WPAS_DBUS_BSS_PROP_WPA:
-               prop = "WPA";
-               break;
-       case WPAS_DBUS_BSS_PROP_RSN:
-               prop = "RSN";
-               break;
-       case WPAS_DBUS_BSS_PROP_IES:
-               prop = "IEs";
-               break;
-       default:
-               wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
-                          __func__, property);
+       iface = wpa_s->global->dbus;
+
+       /* Do nothing if the control interface is not turned on */
+       if (iface == NULL)
                return;
+
+       if (request || !status) {
+               if (config_methods & WPS_CONFIG_DISPLAY)
+                       _signal = request ?
+                                "ProvisionDiscoveryRequestDisplayPin" :
+                                "ProvisionDiscoveryResponseEnterPin";
+               else if (config_methods & WPS_CONFIG_KEYPAD)
+                       _signal = request ?
+                                "ProvisionDiscoveryRequestEnterPin" :
+                                "ProvisionDiscoveryResponseDisplayPin";
+               else if (config_methods & WPS_CONFIG_PUSHBUTTON)
+                       _signal = request ? "ProvisionDiscoveryPBCRequest" :
+                                  "ProvisionDiscoveryPBCResponse";
+               else
+                       return; /* Unknown or un-supported method */
+       } else if (!request && status)
+               /* Explicit check for failure response */
+               _signal = "ProvisionDiscoveryFailure";
+
+       add_pin = ((request && (config_methods & WPS_CONFIG_DISPLAY)) ||
+                  (!request && !status &&
+                       (config_methods & WPS_CONFIG_KEYPAD)));
+
+       if (add_pin) {
+               os_snprintf(pin, sizeof(pin), "%08d", generated_pin);
+               p_pin = pin;
        }
 
-       os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
-                   "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
-                   wpa_s->dbus_new_path, id);
+       msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+                                     WPAS_DBUS_NEW_IFACE_P2PDEVICE, _signal);
+       if (msg == NULL)
+               return;
 
-       wpa_dbus_mark_property_changed(wpa_s->global->dbus, path,
-                                      WPAS_DBUS_NEW_IFACE_BSS, prop);
+       /* Check if this is a known peer */
+       if (p2p_get_peer_info(wpa_s->global->p2p, dev_addr, 0, NULL, 0) < 0)
+               goto error;
+
+       os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                       "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
+                       COMPACT_MACSTR,
+                       wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+       path = peer_obj_path;
+
+       dbus_message_iter_init_append(msg, &iter);
+
+       if (!dbus_message_iter_append_basic(&iter,
+                                           DBUS_TYPE_OBJECT_PATH,
+                                           &path))
+                       goto error;
+
+       if (!request && status)
+               /* Attach status to ProvisionDiscoveryFailure */
+               error_ret = !dbus_message_iter_append_basic(&iter,
+                                                   DBUS_TYPE_INT32,
+                                                   &status);
+       else
+               error_ret = (add_pin &&
+                                !dbus_message_iter_append_basic(&iter,
+                                                       DBUS_TYPE_STRING,
+                                                       &p_pin));
+
+error:
+       if (!error_ret)
+               dbus_connection_send(iface->con, msg, NULL);
+       else
+               wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+
+       dbus_message_unref(msg);
 }
 
 
-/**
- * wpas_dbus_signal_debug_level_changed - Signals change of debug param
- * @global: wpa_global structure
- *
- * Sends ProertyChanged signals informing that debug level has changed.
- */
-void wpas_dbus_signal_debug_level_changed(struct wpa_global *global)
+void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
+                                    const u8 *src, u16 dev_passwd_id)
 {
-       wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
-                                      WPAS_DBUS_NEW_INTERFACE,
-                                      "DebugLevel");
+       DBusMessage *msg;
+       DBusMessageIter iter;
+       struct wpas_dbus_priv *iface;
+       char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+       iface = wpa_s->global->dbus;
+
+       /* Do nothing if the control interface is not turned on */
+       if (iface == NULL)
+               return;
+
+       os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+                   wpa_s->dbus_new_path, MAC2STR(src));
+       path = peer_obj_path;
+
+       msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+                                     WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+                                     "GONegotiationRequest");
+       if (msg == NULL)
+               return;
+
+       dbus_message_iter_init_append(msg, &iter);
+
+       if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+                                           &path) ||
+           !dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT16,
+                                           &dev_passwd_id))
+               wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+       else
+               dbus_connection_send(iface->con, msg, NULL);
+
+       dbus_message_unref(msg);
 }
 
 
-/**
- * wpas_dbus_signal_debug_timestamp_changed - Signals change of debug param
- * @global: wpa_global structure
- *
- * Sends ProertyChanged signals informing that debug timestamp has changed.
- */
-void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global)
+static int wpas_dbus_get_group_obj_path(struct wpa_supplicant *wpa_s,
+                                       const struct wpa_ssid *ssid,
+                                       char *group_obj_path)
 {
-       wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
-                                      WPAS_DBUS_NEW_INTERFACE,
-                                      "DebugTimestamp");
+       char group_name[3];
+
+       if (os_memcmp(ssid->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN))
+               return -1;
+
+       memcpy(group_name, ssid->ssid + P2P_WILDCARD_SSID_LEN, 2);
+       group_name[2] = '\0';
+
+       os_snprintf(group_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_P2P_GROUPS_PART "/%s",
+                   wpa_s->dbus_new_path, group_name);
+
+       return 0;
 }
 
 
 /**
- * wpas_dbus_signal_debug_show_keys_changed - Signals change of debug param
- * @global: wpa_global structure
+ * wpas_dbus_signal_p2p_group_started - Signals P2P group has
+ * started. Emitted when a group is successfully started
+ * irrespective of the role (client/GO) of the current device
  *
- * Sends ProertyChanged signals informing that debug show_keys has changed.
+ * @wpa_s: %wpa_supplicant network interface data
+ * @ssid: SSID object
+ * @client: this device is P2P client
+ * @network_id: network id of the group started, use instead of ssid->id
+ *     to account for persistent groups
  */
-void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global)
+void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
+                                       const struct wpa_ssid *ssid,
+                                       int client, int network_id)
 {
-       wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
-                                      WPAS_DBUS_NEW_INTERFACE,
-                                      "DebugShowKeys");
-}
+       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;
 
-static void wpas_dbus_register(struct wpa_dbus_object_desc *obj_desc,
-                              void *priv,
-                              WPADBusArgumentFreeFunction priv_free,
-                              const struct wpa_dbus_method_desc *methods,
-                              const struct wpa_dbus_property_desc *properties,
-                              const struct wpa_dbus_signal_desc *signals)
-{
-       int n;
+       /* Do nothing if the control interface is not turned on */
+       if (iface == NULL)
+               return;
 
-       obj_desc->user_data = priv;
-       obj_desc->user_data_free_func = priv_free;
-       obj_desc->methods = methods;
-       obj_desc->properties = properties;
-       obj_desc->signals = signals;
+       if (wpas_dbus_get_group_obj_path(wpa_s, ssid, group_obj_path) < 0)
+               return;
 
-       for (n = 0; properties && properties->dbus_property; properties++)
-               n++;
+       /* New interface has been created for this group */
+       msg = dbus_message_new_signal(wpa_s->parent->dbus_new_path,
+                                     WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+                                     "GroupStarted");
 
-       obj_desc->prop_changed_flags = os_zalloc(n);
-       if (!obj_desc->prop_changed_flags)
-               wpa_printf(MSG_DEBUG, "dbus: %s: can't register handlers",
-                          __func__);
-}
+       if (msg == NULL)
+               return;
 
+       dbus_message_iter_init_append(msg, &iter);
+       if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+               goto nomem;
 
-static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = {
-       { "CreateInterface", WPAS_DBUS_NEW_INTERFACE,
-         (WPADBusMethodHandler) &wpas_dbus_handler_create_interface,
-         {
-                 { "args", "a{sv}", ARG_IN },
-                 { "path", "o", ARG_OUT },
-                 END_ARGS
-         }
-       },
-       { "RemoveInterface", WPAS_DBUS_NEW_INTERFACE,
-         (WPADBusMethodHandler) &wpas_dbus_handler_remove_interface,
-         {
-                 { "path", "o", ARG_IN },
-                 END_ARGS
-         }
-       },
-       { "GetInterface", WPAS_DBUS_NEW_INTERFACE,
-         (WPADBusMethodHandler) &wpas_dbus_handler_get_interface,
-         {
-                 { "ifname", "s", ARG_IN },
-                 { "path", "o", ARG_OUT },
-                 END_ARGS
-         }
-       },
-       { NULL, NULL, NULL, { END_ARGS } }
-};
+       /*
+        * In case the device supports creating a separate interface the
+        * DBus client will need to know the object path for the interface
+        * object this group was created on, so include it here.
+        */
+       if (!wpa_dbus_dict_append_object_path(&dict_iter,
+                                       "interface_object",
+                                       wpa_s->dbus_new_path))
+               goto nomem;
 
-static const struct wpa_dbus_property_desc wpas_dbus_global_properties[] = {
-       { "DebugLevel", WPAS_DBUS_NEW_INTERFACE, "s",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_debug_level,
-         (WPADBusPropertyAccessor) wpas_dbus_setter_debug_level,
-         RW
-       },
-       { "DebugTimestamp", WPAS_DBUS_NEW_INTERFACE, "b",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_debug_timestamp,
-         (WPADBusPropertyAccessor) wpas_dbus_setter_debug_timestamp,
-         RW
-       },
-       { "DebugShowKeys", WPAS_DBUS_NEW_INTERFACE, "b",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_debug_show_keys,
-         (WPADBusPropertyAccessor) wpas_dbus_setter_debug_show_keys,
-         RW
-       },
-       { "Interfaces", WPAS_DBUS_NEW_INTERFACE, "ao",
-         (WPADBusPropertyAccessor) &wpas_dbus_getter_interfaces,
-         NULL,
-         R
-       },
-       { "EapMethods", WPAS_DBUS_NEW_INTERFACE, "as",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_eap_methods,
-         NULL,
-         R
-       },
-       { NULL, NULL, NULL, NULL, NULL, 0 }
-};
+       if (!wpa_dbus_dict_append_string(&dict_iter, "role",
+                                        client ? "client" : "GO"))
+               goto nomem;
 
-static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = {
-       { "InterfaceAdded", WPAS_DBUS_NEW_INTERFACE,
-         {
-                 { "path", "o", ARG_OUT },
-                 { "properties", "a{sv}", ARG_OUT },
-                 END_ARGS
-         }
-       },
-       { "InterfaceRemoved", WPAS_DBUS_NEW_INTERFACE,
-         {
-                 { "path", "o", ARG_OUT },
-                 END_ARGS
-         }
-       },
-       { "PropertiesChanged", WPAS_DBUS_NEW_INTERFACE,
-         {
-                 { "properties", "a{sv}", ARG_OUT },
-                 END_ARGS
-         }
-       },
-       { NULL, NULL, { END_ARGS } }
-};
+       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;
+
+       dbus_connection_send(iface->con, msg, NULL);
+
+nomem:
+       dbus_message_unref(msg);
+}
 
 
 /**
- * wpas_dbus_ctrl_iface_init - Initialize dbus control interface
- * @global: Pointer to global data from wpa_supplicant_init()
- * Returns: 0 on success or -1 on failure
  *
- * Initialize the dbus control interface for wpa_supplicantand and start
- * receiving commands from external programs over the bus.
+ * Method to emit GONeogtiation Success or Failure signals based
+ * on status.
+ * @status: Status of the GO neg request. 0 for success, other for errors.
  */
-int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv)
+void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
+                                     struct p2p_go_neg_results *res)
 {
-       struct wpa_dbus_object_desc *obj_desc;
-       int ret;
+       DBusMessage *msg;
+       DBusMessageIter iter, dict_iter;
+       DBusMessageIter iter_dict_entry, iter_dict_val, iter_dict_array;
+       struct wpas_dbus_priv *iface;
+       char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+       dbus_int32_t freqs[P2P_MAX_CHANNELS];
+       dbus_int32_t *f_array = freqs;
 
-       obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
-       if (!obj_desc) {
-               wpa_printf(MSG_ERROR, "Not enough memory "
-                          "to create object description");
-               return -1;
-       }
 
-       wpas_dbus_register(obj_desc, priv->global, NULL,
-                          wpas_dbus_global_methods,
-                          wpas_dbus_global_properties,
-                          wpas_dbus_global_signals);
+       iface = wpa_s->global->dbus;
 
-       wpa_printf(MSG_DEBUG, "dbus: Register D-Bus object '%s'",
-                  WPAS_DBUS_NEW_PATH);
-       ret = wpa_dbus_ctrl_iface_init(priv, WPAS_DBUS_NEW_PATH,
-                                      WPAS_DBUS_NEW_SERVICE,
-                                      obj_desc);
-       if (ret < 0)
-               free_dbus_object_desc(obj_desc);
-       else
-               priv->dbus_new_initialized = 1;
+       os_memset(freqs, 0, sizeof(freqs));
+       /* Do nothing if the control interface is not turned on */
+       if (iface == NULL)
+               return;
 
-       return ret;
+       os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+                   wpa_s->dbus_new_path, MAC2STR(res->peer_device_addr));
+       path = peer_obj_path;
+
+       msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+                                     WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+                                     res->status ? "GONegotiationFailure" :
+                                                   "GONegotiationSuccess");
+       if (msg == NULL)
+               return;
+
+       dbus_message_iter_init_append(msg, &iter);
+       if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+               goto err;
+       if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+                                             path) ||
+           !wpa_dbus_dict_append_int32(&dict_iter, "status", res->status))
+               goto err;
+
+       if (!res->status) {
+               int i = 0;
+               int freq_list_num = 0;
+
+               if (res->role_go) {
+                       if (!wpa_dbus_dict_append_byte_array(
+                                   &dict_iter, "passphrase",
+                                   (const char *) res->passphrase,
+                                   sizeof(res->passphrase)))
+                               goto err;
+               }
+
+               if (!wpa_dbus_dict_append_string(&dict_iter, "role_go",
+                                                res->role_go ? "GO" :
+                                                "client") ||
+                   !wpa_dbus_dict_append_int32(&dict_iter, "frequency",
+                                               res->freq) ||
+                   !wpa_dbus_dict_append_byte_array(&dict_iter, "ssid",
+                                                    (const char *) res->ssid,
+                                                    res->ssid_len) ||
+                   !wpa_dbus_dict_append_byte_array(&dict_iter,
+                                                    "peer_device_addr",
+                                                    (const char *)
+                                                    res->peer_device_addr,
+                                                    ETH_ALEN) ||
+                   !wpa_dbus_dict_append_byte_array(&dict_iter,
+                                                    "peer_interface_addr",
+                                                    (const char *)
+                                                    res->peer_interface_addr,
+                                                    ETH_ALEN) ||
+                   !wpa_dbus_dict_append_string(&dict_iter, "wps_method",
+                                                p2p_wps_method_text(
+                                                        res->wps_method)))
+                       goto err;
+
+               for (i = 0; i < P2P_MAX_CHANNELS; i++) {
+                       if (res->freq_list[i]) {
+                               freqs[i] = res->freq_list[i];
+                               freq_list_num++;
+                       }
+               }
+
+               if (!wpa_dbus_dict_begin_array(&dict_iter,
+                                              "frequency_list",
+                                              DBUS_TYPE_INT32_AS_STRING,
+                                              &iter_dict_entry,
+                                              &iter_dict_val,
+                                              &iter_dict_array))
+                       goto err;
+
+               if (!dbus_message_iter_append_fixed_array(&iter_dict_array,
+                                                         DBUS_TYPE_INT32,
+                                                         &f_array,
+                                                         freq_list_num))
+                       goto err;
+
+               if (!wpa_dbus_dict_end_array(&dict_iter,
+                                            &iter_dict_entry,
+                                            &iter_dict_val,
+                                            &iter_dict_array))
+                       goto err;
+
+               if (!wpa_dbus_dict_append_int32(&dict_iter, "persistent_group",
+                                               res->persistent_group) ||
+                   !wpa_dbus_dict_append_uint32(&dict_iter,
+                                                "peer_config_timeout",
+                                                res->peer_config_timeout))
+                       goto err;
+       }
+
+       if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+               goto err;
+
+       dbus_connection_send(iface->con, msg, NULL);
+err:
+       dbus_message_unref(msg);
 }
 
 
 /**
- * wpas_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface for
- * wpa_supplicant
- * @iface: Pointer to dbus private data from wpas_dbus_init()
  *
- * Deinitialize the dbus control interface that was initialized with
- * wpas_dbus_ctrl_iface_init().
+ * Method to emit Invitation Result signal based on status and
+ * bssid
+ * @status: Status of the Invite request. 0 for success, other
+ * for errors
+ * @bssid : Basic Service Set Identifier
  */
-void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *iface)
+void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s,
+                                           int status, const u8 *bssid)
 {
-       if (!iface->dbus_new_initialized)
+       DBusMessage *msg;
+       DBusMessageIter iter, dict_iter;
+       struct wpas_dbus_priv *iface;
+
+       wpa_printf(MSG_INFO, "%s\n", __func__);
+
+       iface = wpa_s->global->dbus;
+       /* Do nothing if the control interface is not turned on */
+       if (iface == NULL)
                return;
-       wpa_printf(MSG_DEBUG, "dbus: Unregister D-Bus object '%s'",
-                  WPAS_DBUS_NEW_PATH);
-       dbus_connection_unregister_object_path(iface->con,
-                                              WPAS_DBUS_NEW_PATH);
-}
 
+       msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+                                     WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+                                     "InvitationResult");
 
-static void wpa_dbus_free(void *ptr)
-{
-       os_free(ptr);
-}
+       if (msg == NULL)
+               return;
 
+       dbus_message_iter_init_append(msg, &iter);
+       if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+               goto nomem;
 
-static const struct wpa_dbus_property_desc wpas_dbus_network_properties[] = {
-       { "Properties", WPAS_DBUS_NEW_IFACE_NETWORK, "a{sv}",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_network_properties,
-         (WPADBusPropertyAccessor) wpas_dbus_setter_network_properties,
-         RW
-       },
-       { "Enabled", WPAS_DBUS_NEW_IFACE_NETWORK, "b",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_enabled,
-         (WPADBusPropertyAccessor) wpas_dbus_setter_enabled,
-         RW
-       },
-       { NULL, NULL, NULL, NULL, NULL, 0 }
-};
+       if (!wpa_dbus_dict_append_int32(&dict_iter, "status", status))
+               goto nomem;
+       if (bssid) {
+               if (!wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID",
+                                                    (const char *) bssid,
+                                                    ETH_ALEN))
+                       goto nomem;
+       }
+       if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+               goto nomem;
 
+       dbus_connection_send(iface->con, msg, NULL);
 
-static const struct wpa_dbus_signal_desc wpas_dbus_network_signals[] = {
-       { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_NETWORK,
-         {
-                 { "properties", "a{sv}", ARG_OUT },
-                 END_ARGS
-         }
-       },
-       { NULL, NULL, { END_ARGS } }
-};
+nomem:
+       dbus_message_unref(msg);
+}
 
 
 /**
- * wpas_dbus_register_network - Register a configured network with dbus
- * @wpa_s: wpa_supplicant interface structure
- * @ssid: network configuration data
- * Returns: 0 on success, -1 on failure
  *
- * Registers network representing object with dbus
+ * Method to emit a signal for a peer joining the group.
+ * The signal will carry path to the group member object
+ * constructed using p2p i/f addr used for connecting.
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @member_addr: addr (p2p i/f) of the peer joining the group
  */
-int wpas_dbus_register_network(struct wpa_supplicant *wpa_s,
-                              struct wpa_ssid *ssid)
+void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
+                                     const u8 *member)
 {
-       struct wpas_dbus_priv *ctrl_iface;
-       struct wpa_dbus_object_desc *obj_desc;
-       struct network_handler_args *arg;
-       char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+       struct wpas_dbus_priv *iface;
+       DBusMessage *msg;
+       DBusMessageIter iter;
+       char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+       iface = wpa_s->global->dbus;
 
        /* Do nothing if the control interface is not turned on */
-       if (wpa_s == NULL || wpa_s->global == NULL)
-               return 0;
-       ctrl_iface = wpa_s->global->dbus;
-       if (ctrl_iface == NULL)
-               return 0;
+       if (iface == NULL)
+               return;
 
-       os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
-                   "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
-                   wpa_s->dbus_new_path, ssid->id);
+       if (!wpa_s->dbus_groupobj_path)
+               return;
 
-       wpa_printf(MSG_DEBUG, "dbus: Register network object '%s'",
-                  net_obj_path);
-       obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
-       if (!obj_desc) {
-               wpa_printf(MSG_ERROR, "Not enough memory "
-                          "to create object description");
-               goto err;
-       }
+       os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                       "%s/"  WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/"
+                       COMPACT_MACSTR,
+                       wpa_s->dbus_groupobj_path, MAC2STR(member));
 
-       /* allocate memory for handlers arguments */
-       arg = os_zalloc(sizeof(struct network_handler_args));
-       if (!arg) {
-               wpa_printf(MSG_ERROR, "Not enough memory "
-                          "to create arguments for method");
-               goto err;
-       }
-
-       arg->wpa_s = wpa_s;
-       arg->ssid = ssid;
-
-       wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
-                          wpas_dbus_network_properties,
-                          wpas_dbus_network_signals);
+       msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
+                                     WPAS_DBUS_NEW_IFACE_P2P_GROUP,
+                                     "PeerJoined");
+       if (msg == NULL)
+               return;
 
-       if (wpa_dbus_register_object_per_iface(ctrl_iface, net_obj_path,
-                                              wpa_s->ifname, obj_desc))
+       dbus_message_iter_init_append(msg, &iter);
+       path = groupmember_obj_path;
+       if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+                                           &path))
                goto err;
 
-       wpas_dbus_signal_network_added(wpa_s, ssid->id);
+       dbus_connection_send(iface->con, msg, NULL);
 
-       return 0;
+       dbus_message_unref(msg);
+       return;
 
 err:
-       free_dbus_object_desc(obj_desc);
-       return -1;
+       wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+       dbus_message_unref(msg);
 }
 
 
 /**
- * wpas_dbus_unregister_network - Unregister a configured network from dbus
- * @wpa_s: wpa_supplicant interface structure
- * @nid: network id
- * Returns: 0 on success, -1 on failure
  *
- * Unregisters network representing object from dbus
+ * Method to emit a signal for a peer disconnecting the group.
+ * The signal will carry path to the group member object
+ * constructed using p2p i/f addr used for connecting.
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @member_addr: addr (p2p i/f) of the peer joining the group
  */
-int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid)
+void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
+                                     const u8 *member)
 {
-       struct wpas_dbus_priv *ctrl_iface;
-       char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
-       int ret;
+       struct wpas_dbus_priv *iface;
+       DBusMessage *msg;
+       DBusMessageIter iter;
+       char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+       iface = wpa_s->global->dbus;
 
        /* Do nothing if the control interface is not turned on */
-       if (wpa_s == NULL || wpa_s->global == NULL ||
-           wpa_s->dbus_new_path == NULL)
-               return 0;
-       ctrl_iface = wpa_s->global->dbus;
-       if (ctrl_iface == NULL)
-               return 0;
+       if (iface == NULL)
+               return;
 
-       os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
-                   "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
-                   wpa_s->dbus_new_path, nid);
+       if (!wpa_s->dbus_groupobj_path)
+               return;
 
-       wpa_printf(MSG_DEBUG, "dbus: Unregister network object '%s'",
-                  net_obj_path);
-       ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, net_obj_path);
+       os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                       "%s/"  WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/"
+                       COMPACT_MACSTR,
+                       wpa_s->dbus_groupobj_path, MAC2STR(member));
 
-       if (!ret)
-               wpas_dbus_signal_network_removed(wpa_s, nid);
+       msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
+                                     WPAS_DBUS_NEW_IFACE_P2P_GROUP,
+                                     "PeerDisconnected");
+       if (msg == NULL)
+               return;
 
-       return ret;
+       dbus_message_iter_init_append(msg, &iter);
+       path = groupmember_obj_path;
+       if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+                                           &path))
+               goto err;
+
+       dbus_connection_send(iface->con, msg, NULL);
+
+       dbus_message_unref(msg);
+       return;
+
+err:
+       wpa_printf(MSG_ERROR, "dbus: Failed to construct PeerDisconnected "
+                             "signal");
+       dbus_message_unref(msg);
 }
 
 
-static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = {
-       { "SSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_bss_ssid,
-         NULL,
-         R
-       },
-       { "BSSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_bss_bssid,
-         NULL,
-         R
-       },
-       { "Privacy", WPAS_DBUS_NEW_IFACE_BSS, "b",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_bss_privacy,
-         NULL,
-         R
-       },
-       { "Mode", WPAS_DBUS_NEW_IFACE_BSS, "s",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_bss_mode,
-         NULL,
-         R
-       },
-       { "Signal", WPAS_DBUS_NEW_IFACE_BSS, "n",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_bss_signal,
-         NULL,
-         R
-       },
-       { "Frequency", WPAS_DBUS_NEW_IFACE_BSS, "q",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_bss_frequency,
-         NULL,
-         R
-       },
-       { "Rates", WPAS_DBUS_NEW_IFACE_BSS, "au",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_bss_rates,
-         NULL,
-         R
-       },
-       { "WPA", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_bss_wpa,
-         NULL,
-         R
-       },
-       { "RSN", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_bss_rsn,
-         NULL,
-         R
-       },
-       { "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_bss_ies,
-         NULL,
-         R
-       },
-       { NULL, NULL, NULL, NULL, NULL, 0 }
-};
+/**
+ *
+ * Method to emit a signal for a service discovery request.
+ * The signal will carry station address, frequency, dialog token,
+ * update indicator and it tlvs
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sa: station addr (p2p i/f) of the peer
+ * @dialog_token: service discovery request dialog token
+ * @update_indic: service discovery request update indicator
+ * @tlvs: service discovery request genrated byte array of tlvs
+ * @tlvs_len: service discovery request tlvs length
+ */
+void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
+                                    int freq, const u8 *sa, u8 dialog_token,
+                                    u16 update_indic, const u8 *tlvs,
+                                    size_t tlvs_len)
+{
+       DBusMessage *msg;
+       DBusMessageIter iter, dict_iter;
+       struct wpas_dbus_priv *iface;
+       char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+       iface = wpa_s->global->dbus;
 
+       /* Do nothing if the control interface is not turned on */
+       if (iface == NULL)
+               return;
 
-static const struct wpa_dbus_signal_desc wpas_dbus_bss_signals[] = {
-       { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_BSS,
-         {
-                 { "properties", "a{sv}", ARG_OUT },
-                 END_ARGS
-         }
-       },
-       { NULL, NULL, { END_ARGS } }
-};
+       msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+                                     WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+                                     "ServiceDiscoveryRequest");
+       if (msg == NULL)
+               return;
+
+       /* Check if this is a known peer */
+       if (p2p_get_peer_info(wpa_s->global->p2p, sa, 0, NULL, 0) < 0)
+               goto error;
+
+       os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
+                   COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
+
+       path = peer_obj_path;
+
+       dbus_message_iter_init_append(msg, &iter);
+       if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+               goto error;
+
+
+       if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+                                             path) ||
+           !wpa_dbus_dict_append_int32(&dict_iter, "frequency", freq) ||
+           !wpa_dbus_dict_append_int32(&dict_iter, "dialog_token",
+                                       dialog_token) ||
+           !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator",
+                                        update_indic) ||
+           !wpa_dbus_dict_append_byte_array(&dict_iter, "tlvs",
+                                            (const char *) tlvs,
+                                            tlvs_len) ||
+           !wpa_dbus_dict_close_write(&iter, &dict_iter))
+               goto error;
+
+       dbus_connection_send(iface->con, msg, NULL);
+       dbus_message_unref(msg);
+       return;
+error:
+       wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+       dbus_message_unref(msg);
+}
 
 
 /**
- * wpas_dbus_unregister_bss - Unregister a scanned BSS from dbus
- * @wpa_s: wpa_supplicant interface structure
- * @bssid: scanned network bssid
- * @id: unique BSS identifier
- * Returns: 0 on success, -1 on failure
  *
- * Unregisters BSS representing object from dbus
+ * Method to emit a signal for a service discovery response.
+ * The signal will carry station address, update indicator and it
+ * tlvs
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sa: station addr (p2p i/f) of the peer
+ * @update_indic: service discovery request update indicator
+ * @tlvs: service discovery request genrated byte array of tlvs
+ * @tlvs_len: service discovery request tlvs length
  */
-int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s,
-                            u8 bssid[ETH_ALEN], unsigned int id)
+void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
+                                     const u8 *sa, u16 update_indic,
+                                     const u8 *tlvs, size_t tlvs_len)
 {
-       struct wpas_dbus_priv *ctrl_iface;
-       char bss_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+       DBusMessage *msg;
+       DBusMessageIter iter, dict_iter;
+       struct wpas_dbus_priv *iface;
+       char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+       iface = wpa_s->global->dbus;
 
        /* Do nothing if the control interface is not turned on */
-       if (wpa_s == NULL || wpa_s->global == NULL)
-               return 0;
-       ctrl_iface = wpa_s->global->dbus;
-       if (ctrl_iface == NULL)
-               return 0;
+       if (iface == NULL)
+               return;
 
-       os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
-                   "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
-                   wpa_s->dbus_new_path, id);
+       msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+                                     WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+                               "ServiceDiscoveryResponse");
+       if (msg == NULL)
+               return;
 
-       wpa_printf(MSG_DEBUG, "dbus: Unregister BSS object '%s'",
-                  bss_obj_path);
-       if (wpa_dbus_unregister_object_per_iface(ctrl_iface, bss_obj_path)) {
-               wpa_printf(MSG_ERROR, "dbus: Cannot unregister BSS object %s",
-                          bss_obj_path);
-               return -1;
-       }
+       /* Check if this is a known peer */
+       if (p2p_get_peer_info(wpa_s->global->p2p, sa, 0, NULL, 0) < 0)
+               goto error;
 
-       wpas_dbus_signal_bss_removed(wpa_s, bss_obj_path);
+       os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
+                   COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
 
-       return 0;
-}
+       path = peer_obj_path;
 
+       dbus_message_iter_init_append(msg, &iter);
+       if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+               goto error;
+
+       if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+                                             path) ||
+           !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator",
+                                        update_indic) ||
+           !wpa_dbus_dict_append_byte_array(&dict_iter, "tlvs",
+                                            (const char *) tlvs,
+                                            tlvs_len) ||
+           !wpa_dbus_dict_close_write(&iter, &dict_iter))
+               goto error;
+
+
+       dbus_connection_send(iface->con, msg, NULL);
+       dbus_message_unref(msg);
+       return;
+error:
+       wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+       dbus_message_unref(msg);
+}
 
 /**
- * wpas_dbus_register_bss - Register a scanned BSS with dbus
- * @wpa_s: wpa_supplicant interface structure
- * @bssid: scanned network bssid
- * @id: unique BSS identifier
- * Returns: 0 on success, -1 on failure
+ * wpas_dbus_signal_persistent_group - Send a persistent group related
+ *     event signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: new persistent group id
+ * @sig_name: signal name - PersistentGroupAdded, PersistentGroupRemoved
+ * @properties: determines if add second argument with object properties
  *
- * Registers BSS representing object with dbus
+ * Notify listeners about an event related to persistent groups.
  */
-int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
-                          u8 bssid[ETH_ALEN], unsigned int id)
+static void wpas_dbus_signal_persistent_group(struct wpa_supplicant *wpa_s,
+                                             int id, const char *sig_name,
+                                             int properties)
 {
-       struct wpas_dbus_priv *ctrl_iface;
-       struct wpa_dbus_object_desc *obj_desc;
-       char bss_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
-       struct bss_handler_args *arg;
+       struct wpas_dbus_priv *iface;
+       DBusMessage *msg;
+       DBusMessageIter iter;
+       char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+       iface = wpa_s->global->dbus;
 
        /* Do nothing if the control interface is not turned on */
-       if (wpa_s == NULL || wpa_s->global == NULL)
-               return 0;
-       ctrl_iface = wpa_s->global->dbus;
-       if (ctrl_iface == NULL)
-               return 0;
+       if (iface == NULL)
+               return;
 
-       os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
-                   "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
+       os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
                    wpa_s->dbus_new_path, id);
 
-       obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
-       if (!obj_desc) {
-               wpa_printf(MSG_ERROR, "Not enough memory "
-                          "to create object description");
-               goto err;
-       }
+       msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+                                     WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+                                     sig_name);
+       if (msg == NULL)
+               return;
 
-       arg = os_zalloc(sizeof(struct bss_handler_args));
-       if (!arg) {
-               wpa_printf(MSG_ERROR, "Not enough memory "
-                          "to create arguments for handler");
+       dbus_message_iter_init_append(msg, &iter);
+       path = pgrp_obj_path;
+       if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+                                           &path))
                goto err;
-       }
-       arg->wpa_s = wpa_s;
-       arg->id = id;
-
-       wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
-                          wpas_dbus_bss_properties,
-                          wpas_dbus_bss_signals);
 
-       wpa_printf(MSG_DEBUG, "dbus: Register BSS object '%s'",
-                  bss_obj_path);
-       if (wpa_dbus_register_object_per_iface(ctrl_iface, bss_obj_path,
-                                              wpa_s->ifname, obj_desc)) {
-               wpa_printf(MSG_ERROR,
-                          "Cannot register BSSID dbus object %s.",
-                          bss_obj_path);
-               goto err;
+       if (properties) {
+               if (!wpa_dbus_get_object_properties(
+                           iface, pgrp_obj_path,
+                           WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, &iter))
+                       goto err;
        }
 
-       wpas_dbus_signal_bss_added(wpa_s, bss_obj_path);
+       dbus_connection_send(iface->con, msg, NULL);
 
-       return 0;
+       dbus_message_unref(msg);
+       return;
 
 err:
-       free_dbus_object_desc(obj_desc);
-       return -1;
-}
+       wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+       dbus_message_unref(msg);
+}
 
 
-static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
-       { "Scan", WPAS_DBUS_NEW_IFACE_INTERFACE,
-         (WPADBusMethodHandler) &wpas_dbus_handler_scan,
+/**
+ * wpas_dbus_signal_persistent_group_added - Send a persistent_group
+ *     added signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: new persistent group id
+ *
+ * Notify listeners about addition of a new persistent group.
+ */
+static void wpas_dbus_signal_persistent_group_added(
+       struct wpa_supplicant *wpa_s, int id)
+{
+       wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupAdded",
+                                         TRUE);
+}
+
+
+/**
+ * wpas_dbus_signal_persistent_group_removed - Send a persistent_group
+ *     removed signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: persistent group id
+ *
+ * Notify listeners about removal of a persistent group.
+ */
+static void wpas_dbus_signal_persistent_group_removed(
+       struct wpa_supplicant *wpa_s, int id)
+{
+       wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupRemoved",
+                                         FALSE);
+}
+
+
+/**
+ * wpas_dbus_signal_p2p_wps_failed - Signals WpsFailed event
+ * @wpa_s: %wpa_supplicant network interface data
+ *
+ * Sends Event dbus signal with name "fail" and dictionary containing
+ * "msg" field with fail message number (int32) as arguments
+ */
+void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+                                    struct wps_event_fail *fail)
+{
+
+       DBusMessage *msg;
+       DBusMessageIter iter, dict_iter;
+       struct wpas_dbus_priv *iface;
+       char *key = "fail";
+
+       iface = wpa_s->global->dbus;
+
+       /* Do nothing if the control interface is not turned on */
+       if (iface == NULL)
+               return;
+
+       msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+                                     WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+                                     "WpsFailed");
+       if (msg == NULL)
+               return;
+
+       dbus_message_iter_init_append(msg, &iter);
+
+       if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
+           !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+           !wpa_dbus_dict_append_int32(&dict_iter, "msg", fail->msg) ||
+           !wpa_dbus_dict_append_int16(&dict_iter, "config_error",
+                                       fail->config_error) ||
+           !wpa_dbus_dict_close_write(&iter, &dict_iter))
+               wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+       else
+               dbus_connection_send(iface->con, msg, NULL);
+
+       dbus_message_unref(msg);
+}
+
+#endif /*CONFIG_P2P*/
+
+
+/**
+ * wpas_dbus_signal_prop_changed - Signals change of property
+ * @wpa_s: %wpa_supplicant network interface data
+ * @property: indicates which property has changed
+ *
+ * Sends PropertyChanged signals with path, interface and arguments
+ * depending on which property has changed.
+ */
+void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
+                                  enum wpas_dbus_prop property)
+{
+       char *prop;
+
+       if (wpa_s->dbus_new_path == NULL)
+               return; /* Skip signal since D-Bus setup is not yet ready */
+
+       switch (property) {
+       case WPAS_DBUS_PROP_AP_SCAN:
+               prop = "ApScan";
+               break;
+       case WPAS_DBUS_PROP_SCANNING:
+               prop = "Scanning";
+               break;
+       case WPAS_DBUS_PROP_STATE:
+               prop = "State";
+               break;
+       case WPAS_DBUS_PROP_CURRENT_BSS:
+               prop = "CurrentBSS";
+               break;
+       case WPAS_DBUS_PROP_CURRENT_NETWORK:
+               prop = "CurrentNetwork";
+               break;
+       case WPAS_DBUS_PROP_BSSS:
+               prop = "BSSs";
+               break;
+       case WPAS_DBUS_PROP_CURRENT_AUTH_MODE:
+               prop = "CurrentAuthMode";
+               break;
+       default:
+               wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
+                          __func__, property);
+               return;
+       }
+
+       wpa_dbus_mark_property_changed(wpa_s->global->dbus,
+                                      wpa_s->dbus_new_path,
+                                      WPAS_DBUS_NEW_IFACE_INTERFACE, prop);
+}
+
+
+/**
+ * wpas_dbus_bss_signal_prop_changed - Signals change of BSS property
+ * @wpa_s: %wpa_supplicant network interface data
+ * @property: indicates which property has changed
+ * @id: unique BSS identifier
+ *
+ * Sends PropertyChanged signals with path, interface, and arguments depending
+ * on which property has changed.
+ */
+void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s,
+                                      enum wpas_dbus_bss_prop property,
+                                      unsigned int id)
+{
+       char path[WPAS_DBUS_OBJECT_PATH_MAX];
+       char *prop;
+
+       switch (property) {
+       case WPAS_DBUS_BSS_PROP_SIGNAL:
+               prop = "Signal";
+               break;
+       case WPAS_DBUS_BSS_PROP_FREQ:
+               prop = "Frequency";
+               break;
+       case WPAS_DBUS_BSS_PROP_MODE:
+               prop = "Mode";
+               break;
+       case WPAS_DBUS_BSS_PROP_PRIVACY:
+               prop = "Privacy";
+               break;
+       case WPAS_DBUS_BSS_PROP_RATES:
+               prop = "Rates";
+               break;
+       case WPAS_DBUS_BSS_PROP_WPA:
+               prop = "WPA";
+               break;
+       case WPAS_DBUS_BSS_PROP_RSN:
+               prop = "RSN";
+               break;
+       case WPAS_DBUS_BSS_PROP_IES:
+               prop = "IEs";
+               break;
+       default:
+               wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
+                          __func__, property);
+               return;
+       }
+
+       os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
+                   wpa_s->dbus_new_path, id);
+
+       wpa_dbus_mark_property_changed(wpa_s->global->dbus, path,
+                                      WPAS_DBUS_NEW_IFACE_BSS, prop);
+}
+
+
+/**
+ * wpas_dbus_signal_debug_level_changed - Signals change of debug param
+ * @global: wpa_global structure
+ *
+ * Sends PropertyChanged signals informing that debug level has changed.
+ */
+void wpas_dbus_signal_debug_level_changed(struct wpa_global *global)
+{
+       wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
+                                      WPAS_DBUS_NEW_INTERFACE,
+                                      "DebugLevel");
+}
+
+
+/**
+ * wpas_dbus_signal_debug_timestamp_changed - Signals change of debug param
+ * @global: wpa_global structure
+ *
+ * Sends PropertyChanged signals informing that debug timestamp has changed.
+ */
+void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global)
+{
+       wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
+                                      WPAS_DBUS_NEW_INTERFACE,
+                                      "DebugTimestamp");
+}
+
+
+/**
+ * wpas_dbus_signal_debug_show_keys_changed - Signals change of debug param
+ * @global: wpa_global structure
+ *
+ * Sends PropertyChanged signals informing that debug show_keys has changed.
+ */
+void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global)
+{
+       wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
+                                      WPAS_DBUS_NEW_INTERFACE,
+                                      "DebugShowKeys");
+}
+
+
+static void wpas_dbus_register(struct wpa_dbus_object_desc *obj_desc,
+                              void *priv,
+                              WPADBusArgumentFreeFunction priv_free,
+                              const struct wpa_dbus_method_desc *methods,
+                              const struct wpa_dbus_property_desc *properties,
+                              const struct wpa_dbus_signal_desc *signals)
+{
+       int n;
+
+       obj_desc->user_data = priv;
+       obj_desc->user_data_free_func = priv_free;
+       obj_desc->methods = methods;
+       obj_desc->properties = properties;
+       obj_desc->signals = signals;
+
+       for (n = 0; properties && properties->dbus_property; properties++)
+               n++;
+
+       obj_desc->prop_changed_flags = os_zalloc(n);
+       if (!obj_desc->prop_changed_flags)
+               wpa_printf(MSG_DEBUG, "dbus: %s: can't register handlers",
+                          __func__);
+}
+
+
+static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = {
+       { "CreateInterface", WPAS_DBUS_NEW_INTERFACE,
+         (WPADBusMethodHandler) &wpas_dbus_handler_create_interface,
          {
                  { "args", "a{sv}", ARG_IN },
+                 { "path", "o", ARG_OUT },
                  END_ARGS
          }
        },
-       { "Disconnect", WPAS_DBUS_NEW_IFACE_INTERFACE,
-         (WPADBusMethodHandler) &wpas_dbus_handler_disconnect,
+       { "RemoveInterface", WPAS_DBUS_NEW_INTERFACE,
+         (WPADBusMethodHandler) &wpas_dbus_handler_remove_interface,
+         {
+                 { "path", "o", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "GetInterface", WPAS_DBUS_NEW_INTERFACE,
+         (WPADBusMethodHandler) &wpas_dbus_handler_get_interface,
+         {
+                 { "ifname", "s", ARG_IN },
+                 { "path", "o", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { NULL, NULL, NULL, { END_ARGS } }
+};
+
+static const struct wpa_dbus_property_desc wpas_dbus_global_properties[] = {
+       { "DebugLevel", WPAS_DBUS_NEW_INTERFACE, "s",
+         wpas_dbus_getter_debug_level,
+         wpas_dbus_setter_debug_level
+       },
+       { "DebugTimestamp", WPAS_DBUS_NEW_INTERFACE, "b",
+         wpas_dbus_getter_debug_timestamp,
+         wpas_dbus_setter_debug_timestamp
+       },
+       { "DebugShowKeys", WPAS_DBUS_NEW_INTERFACE, "b",
+         wpas_dbus_getter_debug_show_keys,
+         wpas_dbus_setter_debug_show_keys
+       },
+       { "Interfaces", WPAS_DBUS_NEW_INTERFACE, "ao",
+         wpas_dbus_getter_interfaces,
+         NULL
+       },
+       { "EapMethods", WPAS_DBUS_NEW_INTERFACE, "as",
+         wpas_dbus_getter_eap_methods,
+         NULL
+       },
+       { NULL, NULL, NULL, NULL, NULL }
+};
+
+static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = {
+       { "InterfaceAdded", WPAS_DBUS_NEW_INTERFACE,
+         {
+                 { "path", "o", ARG_OUT },
+                 { "properties", "a{sv}", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "InterfaceRemoved", WPAS_DBUS_NEW_INTERFACE,
+         {
+                 { "path", "o", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         {
+                 { "path", "o", ARG_OUT },
+                 { "field", "s", ARG_OUT },
+                 { "text", "s", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
+       { "PropertiesChanged", WPAS_DBUS_NEW_INTERFACE,
+         {
+                 { "properties", "a{sv}", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { NULL, NULL, { END_ARGS } }
+};
+
+
+/**
+ * wpas_dbus_ctrl_iface_init - Initialize dbus control interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * Returns: 0 on success or -1 on failure
+ *
+ * Initialize the dbus control interface for wpa_supplicantand and start
+ * receiving commands from external programs over the bus.
+ */
+int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv)
+{
+       struct wpa_dbus_object_desc *obj_desc;
+       int ret;
+
+       obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+       if (!obj_desc) {
+               wpa_printf(MSG_ERROR, "Not enough memory "
+                          "to create object description");
+               return -1;
+       }
+
+       wpas_dbus_register(obj_desc, priv->global, NULL,
+                          wpas_dbus_global_methods,
+                          wpas_dbus_global_properties,
+                          wpas_dbus_global_signals);
+
+       wpa_printf(MSG_DEBUG, "dbus: Register D-Bus object '%s'",
+                  WPAS_DBUS_NEW_PATH);
+       ret = wpa_dbus_ctrl_iface_init(priv, WPAS_DBUS_NEW_PATH,
+                                      WPAS_DBUS_NEW_SERVICE,
+                                      obj_desc);
+       if (ret < 0)
+               free_dbus_object_desc(obj_desc);
+       else
+               priv->dbus_new_initialized = 1;
+
+       return ret;
+}
+
+
+/**
+ * wpas_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface for
+ * wpa_supplicant
+ * @iface: Pointer to dbus private data from wpas_dbus_init()
+ *
+ * Deinitialize the dbus control interface that was initialized with
+ * wpas_dbus_ctrl_iface_init().
+ */
+void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *iface)
+{
+       if (!iface->dbus_new_initialized)
+               return;
+       wpa_printf(MSG_DEBUG, "dbus: Unregister D-Bus object '%s'",
+                  WPAS_DBUS_NEW_PATH);
+       dbus_connection_unregister_object_path(iface->con,
+                                              WPAS_DBUS_NEW_PATH);
+}
+
+
+static void wpa_dbus_free(void *ptr)
+{
+       os_free(ptr);
+}
+
+
+static const struct wpa_dbus_property_desc wpas_dbus_network_properties[] = {
+       { "Properties", WPAS_DBUS_NEW_IFACE_NETWORK, "a{sv}",
+         wpas_dbus_getter_network_properties,
+         wpas_dbus_setter_network_properties
+       },
+       { "Enabled", WPAS_DBUS_NEW_IFACE_NETWORK, "b",
+         wpas_dbus_getter_enabled,
+         wpas_dbus_setter_enabled
+       },
+       { NULL, NULL, NULL, NULL, NULL }
+};
+
+
+static const struct wpa_dbus_signal_desc wpas_dbus_network_signals[] = {
+       /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
+       { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_NETWORK,
+         {
+                 { "properties", "a{sv}", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { NULL, NULL, { END_ARGS } }
+};
+
+
+/**
+ * wpas_dbus_register_network - Register a configured network with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: network configuration data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers network representing object with dbus
+ */
+int wpas_dbus_register_network(struct wpa_supplicant *wpa_s,
+                              struct wpa_ssid *ssid)
+{
+       struct wpas_dbus_priv *ctrl_iface;
+       struct wpa_dbus_object_desc *obj_desc;
+       struct network_handler_args *arg;
+       char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+#ifdef CONFIG_P2P
+       /*
+        * If it is a persistent group register it as such.
+        * This is to handle cases where an interface is being initialized
+        * with a list of networks read from config.
+        */
+       if (network_is_persistent_group(ssid))
+               return wpas_dbus_register_persistent_group(wpa_s, ssid);
+#endif /* CONFIG_P2P */
+
+       /* Do nothing if the control interface is not turned on */
+       if (wpa_s == NULL || wpa_s->global == NULL)
+               return 0;
+       ctrl_iface = wpa_s->global->dbus;
+       if (ctrl_iface == NULL)
+               return 0;
+
+       os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
+                   wpa_s->dbus_new_path, ssid->id);
+
+       wpa_printf(MSG_DEBUG, "dbus: Register network object '%s'",
+                  net_obj_path);
+       obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+       if (!obj_desc) {
+               wpa_printf(MSG_ERROR, "Not enough memory "
+                          "to create object description");
+               goto err;
+       }
+
+       /* allocate memory for handlers arguments */
+       arg = os_zalloc(sizeof(struct network_handler_args));
+       if (!arg) {
+               wpa_printf(MSG_ERROR, "Not enough memory "
+                          "to create arguments for method");
+               goto err;
+       }
+
+       arg->wpa_s = wpa_s;
+       arg->ssid = ssid;
+
+       wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
+                          wpas_dbus_network_properties,
+                          wpas_dbus_network_signals);
+
+       if (wpa_dbus_register_object_per_iface(ctrl_iface, net_obj_path,
+                                              wpa_s->ifname, obj_desc))
+               goto err;
+
+       wpas_dbus_signal_network_added(wpa_s, ssid->id);
+
+       return 0;
+
+err:
+       free_dbus_object_desc(obj_desc);
+       return -1;
+}
+
+
+/**
+ * wpas_dbus_unregister_network - Unregister a configured network from dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @nid: network id
+ * Returns: 0 on success, -1 on failure
+ *
+ * Unregisters network representing object from dbus
+ */
+int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid)
+{
+       struct wpas_dbus_priv *ctrl_iface;
+       char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+       int ret;
+       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);
+#endif /* CONFIG_P2P */
+
+       /* Do nothing if the control interface is not turned on */
+       if (wpa_s->global == NULL || wpa_s->dbus_new_path == NULL)
+               return 0;
+       ctrl_iface = wpa_s->global->dbus;
+       if (ctrl_iface == NULL)
+               return 0;
+
+       os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
+                   wpa_s->dbus_new_path, nid);
+
+       wpa_printf(MSG_DEBUG, "dbus: Unregister network object '%s'",
+                  net_obj_path);
+       ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, net_obj_path);
+
+       if (!ret)
+               wpas_dbus_signal_network_removed(wpa_s, nid);
+
+       return ret;
+}
+
+
+static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = {
+       { "SSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
+         wpas_dbus_getter_bss_ssid,
+         NULL
+       },
+       { "BSSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
+         wpas_dbus_getter_bss_bssid,
+         NULL
+       },
+       { "Privacy", WPAS_DBUS_NEW_IFACE_BSS, "b",
+         wpas_dbus_getter_bss_privacy,
+         NULL
+       },
+       { "Mode", WPAS_DBUS_NEW_IFACE_BSS, "s",
+         wpas_dbus_getter_bss_mode,
+         NULL
+       },
+       { "Signal", WPAS_DBUS_NEW_IFACE_BSS, "n",
+         wpas_dbus_getter_bss_signal,
+         NULL
+       },
+       { "Frequency", WPAS_DBUS_NEW_IFACE_BSS, "q",
+         wpas_dbus_getter_bss_frequency,
+         NULL
+       },
+       { "Rates", WPAS_DBUS_NEW_IFACE_BSS, "au",
+         wpas_dbus_getter_bss_rates,
+         NULL
+       },
+       { "WPA", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
+         wpas_dbus_getter_bss_wpa,
+         NULL
+       },
+       { "RSN", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
+         wpas_dbus_getter_bss_rsn,
+         NULL
+       },
+       { "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay",
+         wpas_dbus_getter_bss_ies,
+         NULL
+       },
+       { NULL, NULL, NULL, NULL, NULL }
+};
+
+
+static const struct wpa_dbus_signal_desc wpas_dbus_bss_signals[] = {
+       /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
+       { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_BSS,
+         {
+                 { "properties", "a{sv}", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { NULL, NULL, { END_ARGS } }
+};
+
+
+/**
+ * wpas_dbus_unregister_bss - Unregister a scanned BSS from dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @bssid: scanned network bssid
+ * @id: unique BSS identifier
+ * Returns: 0 on success, -1 on failure
+ *
+ * Unregisters BSS representing object from dbus
+ */
+int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s,
+                            u8 bssid[ETH_ALEN], unsigned int id)
+{
+       struct wpas_dbus_priv *ctrl_iface;
+       char bss_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+       /* Do nothing if the control interface is not turned on */
+       if (wpa_s == NULL || wpa_s->global == NULL)
+               return 0;
+       ctrl_iface = wpa_s->global->dbus;
+       if (ctrl_iface == NULL)
+               return 0;
+
+       os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
+                   wpa_s->dbus_new_path, id);
+
+       wpa_printf(MSG_DEBUG, "dbus: Unregister BSS object '%s'",
+                  bss_obj_path);
+       if (wpa_dbus_unregister_object_per_iface(ctrl_iface, bss_obj_path)) {
+               wpa_printf(MSG_ERROR, "dbus: Cannot unregister BSS object %s",
+                          bss_obj_path);
+               return -1;
+       }
+
+       wpas_dbus_signal_bss_removed(wpa_s, bss_obj_path);
+       wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSSS);
+
+       return 0;
+}
+
+
+/**
+ * wpas_dbus_register_bss - Register a scanned BSS with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @bssid: scanned network bssid
+ * @id: unique BSS identifier
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers BSS representing object with dbus
+ */
+int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
+                          u8 bssid[ETH_ALEN], unsigned int id)
+{
+       struct wpas_dbus_priv *ctrl_iface;
+       struct wpa_dbus_object_desc *obj_desc;
+       char bss_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+       struct bss_handler_args *arg;
+
+       /* Do nothing if the control interface is not turned on */
+       if (wpa_s == NULL || wpa_s->global == NULL)
+               return 0;
+       ctrl_iface = wpa_s->global->dbus;
+       if (ctrl_iface == NULL)
+               return 0;
+
+       os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
+                   wpa_s->dbus_new_path, id);
+
+       obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+       if (!obj_desc) {
+               wpa_printf(MSG_ERROR, "Not enough memory "
+                          "to create object description");
+               goto err;
+       }
+
+       arg = os_zalloc(sizeof(struct bss_handler_args));
+       if (!arg) {
+               wpa_printf(MSG_ERROR, "Not enough memory "
+                          "to create arguments for handler");
+               goto err;
+       }
+       arg->wpa_s = wpa_s;
+       arg->id = id;
+
+       wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
+                          wpas_dbus_bss_properties,
+                          wpas_dbus_bss_signals);
+
+       wpa_printf(MSG_DEBUG, "dbus: Register BSS object '%s'",
+                  bss_obj_path);
+       if (wpa_dbus_register_object_per_iface(ctrl_iface, bss_obj_path,
+                                              wpa_s->ifname, obj_desc)) {
+               wpa_printf(MSG_ERROR,
+                          "Cannot register BSSID dbus object %s.",
+                          bss_obj_path);
+               goto err;
+       }
+
+       wpas_dbus_signal_bss_added(wpa_s, bss_obj_path);
+       wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSSS);
+
+       return 0;
+
+err:
+       free_dbus_object_desc(obj_desc);
+       return -1;
+}
+
+
+static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
+       { "Scan", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) &wpas_dbus_handler_scan,
+         {
+                 { "args", "a{sv}", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "Disconnect", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) &wpas_dbus_handler_disconnect,
+         {
+                 END_ARGS
+         }
+       },
+       { "AddNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) &wpas_dbus_handler_add_network,
+         {
+                 { "args", "a{sv}", ARG_IN },
+                 { "path", "o", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) &wpas_dbus_handler_remove_network,
+         {
+                 { "path", "o", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "RemoveAllNetworks", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) &wpas_dbus_handler_remove_all_networks,
+         {
+                 END_ARGS
+         }
+       },
+       { "SelectNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) &wpas_dbus_handler_select_network,
+         {
+                 { "path", "o", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "NetworkReply", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) &wpas_dbus_handler_network_reply,
+         {
+                 { "path", "o", ARG_IN },
+                 { "field", "s", ARG_IN },
+                 { "value", "s", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) &wpas_dbus_handler_add_blob,
+         {
+                 { "name", "s", ARG_IN },
+                 { "data", "ay", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "GetBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) &wpas_dbus_handler_get_blob,
+         {
+                 { "name", "s", ARG_IN },
+                 { "data", "ay", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "RemoveBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) &wpas_dbus_handler_remove_blob,
+         {
+                 { "name", "s", ARG_IN },
+                 END_ARGS
+         }
+       },
+
+       /*
+        * 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
+#ifdef CONFIG_WPS
+       { "Start", WPAS_DBUS_NEW_IFACE_WPS,
+         (WPADBusMethodHandler) &wpas_dbus_handler_wps_start,
+         {
+                 { "args", "a{sv}", ARG_IN },
+                 { "output", "a{sv}", ARG_OUT },
+                 END_ARGS
+         }
+       },
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+       { "Find", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_find,
+         {
+                 { "args", "a{sv}", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "StopFind", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_stop_find,
+         {
+                 END_ARGS
+         }
+       },
+       { "Listen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_listen,
+         {
+                 { "timeout", "i", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "ExtendedListen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_extendedlisten,
+         {
+                 { "args", "a{sv}", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "PresenceRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_presence_request,
+         {
+                 { "args", "a{sv}", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "ProvisionDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_prov_disc_req,
+         {
+                 { "peer", "o", ARG_IN },
+                 { "config_method", "s", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "Connect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_connect,
+         {
+                 { "args", "a{sv}", ARG_IN },
+                 { "generated_pin", "s", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "GroupAdd", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_group_add,
+         {
+                 { "args", "a{sv}", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "Invite", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_invite,
+         {
+                 { "args", "a{sv}", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "Disconnect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_disconnect,
+         {
+                 END_ARGS
+         }
+       },
+       { "RejectPeer", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_rejectpeer,
+         {
+                 { "peer", "o", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "Flush", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush,
+         {
+                 END_ARGS
+         }
+       },
+       { "AddService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_add_service,
+         {
+                 { "args", "a{sv}", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "DeleteService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_delete_service,
+         {
+                 { "args", "a{sv}", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "FlushService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush_service,
+         {
+                 END_ARGS
+         }
+       },
+       { "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_req,
+         {
+                 { "args", "a{sv}", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_res,
+         {
+                 { "args", "a{sv}", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "ServiceDiscoveryCancelRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_cancel_req,
+         {
+                 { "args", "t", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "ServiceUpdate", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_update,
+         {
+                 END_ARGS
+         }
+       },
+       { "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external,
+         {
+                 { "arg", "i", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external,
+         {
+                 { "arg", "i", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "AddPersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler) wpas_dbus_handler_add_persistent_group,
+         {
+                 { "args", "a{sv}", ARG_IN },
+                 { "path", "o", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "RemovePersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler) wpas_dbus_handler_remove_persistent_group,
+         {
+                 { "path", "o", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "RemoveAllPersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         (WPADBusMethodHandler)
+         wpas_dbus_handler_remove_all_persistent_groups,
+         {
+                 END_ARGS
+         }
+       },
+#endif /* CONFIG_P2P */
+       { "FlushBSS", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) &wpas_dbus_handler_flush_bss,
+         {
+                 { "age", "u", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { NULL, NULL, NULL, { END_ARGS } }
+};
+
+static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
+       { "Capabilities", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{sv}",
+         wpas_dbus_getter_capabilities,
+         NULL
+       },
+       { "State", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+         wpas_dbus_getter_state,
+         NULL
+       },
+       { "Scanning", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
+         wpas_dbus_getter_scanning,
+         NULL
+       },
+       { "ApScan", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+         wpas_dbus_getter_ap_scan,
+         wpas_dbus_setter_ap_scan
+       },
+       { "BSSExpireAge", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+         wpas_dbus_getter_bss_expire_age,
+         wpas_dbus_setter_bss_expire_age
+       },
+       { "BSSExpireCount", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+         wpas_dbus_getter_bss_expire_count,
+         wpas_dbus_setter_bss_expire_count
+       },
+       { "Country", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+         wpas_dbus_getter_country,
+         wpas_dbus_setter_country
+       },
+       { "Ifname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+         wpas_dbus_getter_ifname,
+         NULL
+       },
+       { "Driver", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+         wpas_dbus_getter_driver,
+         NULL
+       },
+       { "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+         wpas_dbus_getter_bridge_ifname,
+         NULL
+       },
+       { "CurrentBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
+         wpas_dbus_getter_current_bss,
+         NULL
+       },
+       { "CurrentNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
+         wpas_dbus_getter_current_network,
+         NULL
+       },
+       { "CurrentAuthMode", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+         wpas_dbus_getter_current_auth_mode,
+         NULL
+       },
+       { "Blobs", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{say}",
+         wpas_dbus_getter_blobs,
+         NULL
+       },
+       { "BSSs", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
+         wpas_dbus_getter_bsss,
+         NULL
+       },
+       { "Networks", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
+         wpas_dbus_getter_networks,
+         NULL
+       },
+#ifdef CONFIG_WPS
+       { "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b",
+         wpas_dbus_getter_process_credentials,
+         wpas_dbus_setter_process_credentials
+       },
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+       { "P2PDeviceProperties", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}",
+         wpas_dbus_getter_p2p_device_properties,
+         wpas_dbus_setter_p2p_device_properties
+       },
+       { "Peers", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
+         wpas_dbus_getter_p2p_peers,
+         NULL
+       },
+       { "Role", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "s",
+         wpas_dbus_getter_p2p_role,
+         NULL
+       },
+       { "Group", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
+         wpas_dbus_getter_p2p_group,
+         NULL
+       },
+       { "PeerGO", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
+         wpas_dbus_getter_p2p_peergo,
+         NULL
+       },
+       { "PersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
+         wpas_dbus_getter_persistent_groups,
+         NULL
+       },
+#endif /* CONFIG_P2P */
+       { NULL, NULL, NULL, NULL, NULL }
+};
+
+static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
+       { "ScanDone", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         {
+                 { "success", "b", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "BSSAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         {
+                 { "path", "o", ARG_OUT },
+                 { "properties", "a{sv}", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "BSSRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         {
+                 { "path", "o", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "BlobAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         {
+                 { "name", "s", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "BlobRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         {
+                 { "name", "s", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "NetworkAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         {
+                 { "path", "o", ARG_OUT },
+                 { "properties", "a{sv}", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "NetworkRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         {
+                 { "path", "o", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "NetworkSelected", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         {
+                 { "path", "o", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
+       { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         {
+                 { "properties", "a{sv}", ARG_OUT },
+                 END_ARGS
+         }
+       },
+#ifdef CONFIG_WPS
+       { "Event", WPAS_DBUS_NEW_IFACE_WPS,
+         {
+                 { "name", "s", ARG_OUT },
+                 { "args", "a{sv}", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "Credentials", WPAS_DBUS_NEW_IFACE_WPS,
+         {
+                 { "credentials", "a{sv}", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
+       { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_WPS,
+         {
+                 { "properties", "a{sv}", ARG_OUT },
+                 END_ARGS
+         }
+       },
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+       { "P2PStateChanged", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         {
+                 { "states", "a{ss}", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "DeviceFound", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         {
+                 { "path", "o", ARG_OUT },
+                 { "properties", "a{sv}", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "DeviceLost", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         {
+                 { "path", "o", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "ProvisionDiscoveryRequestDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         {
+                 { "peer_object", "o", ARG_OUT },
+                 { "pin", "s", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "ProvisionDiscoveryResponseDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         {
+                 { "peer_object", "o", ARG_OUT },
+                 { "pin", "s", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "ProvisionDiscoveryRequestEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
          {
+                 { "peer_object", "o", ARG_OUT },
                  END_ARGS
          }
        },
-       { "AddNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
-         (WPADBusMethodHandler) &wpas_dbus_handler_add_network,
+       { "ProvisionDiscoveryResponseEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
          {
-                 { "args", "a{sv}", ARG_IN },
-                 { "path", "o", ARG_OUT },
+                 { "peer_object", "o", ARG_OUT },
                  END_ARGS
          }
        },
-       { "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
-         (WPADBusMethodHandler) &wpas_dbus_handler_remove_network,
+       { "ProvisionDiscoveryPBCRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
          {
-                 { "path", "o", ARG_IN },
+                 { "peer_object", "o", ARG_OUT },
                  END_ARGS
          }
        },
-       { "SelectNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
-         (WPADBusMethodHandler) &wpas_dbus_handler_select_network,
+       { "ProvisionDiscoveryPBCResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
          {
-                 { "path", "o", ARG_IN },
+                 { "peer_object", "o", ARG_OUT },
                  END_ARGS
          }
        },
-       { "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
-         (WPADBusMethodHandler) &wpas_dbus_handler_add_blob,
+       { "ProvisionDiscoveryFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
          {
-                 { "name", "s", ARG_IN },
-                 { "data", "ay", ARG_IN },
+                 { "peer_object", "o", ARG_OUT },
+                 { "status", "i", ARG_OUT },
                  END_ARGS
          }
        },
-       { "GetBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
-         (WPADBusMethodHandler) &wpas_dbus_handler_get_blob,
+       { "GroupStarted", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
          {
-                 { "name", "s", ARG_IN },
-                 { "data", "ay", ARG_OUT },
+                 { "properties", "a{sv}", ARG_OUT },
                  END_ARGS
          }
        },
-       { "RemoveBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
-         (WPADBusMethodHandler) &wpas_dbus_handler_remove_blob,
+       { "GONegotiationSuccess", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
          {
-                 { "name", "s", ARG_IN },
                  END_ARGS
          }
        },
-#ifdef CONFIG_WPS
-       { "Start", WPAS_DBUS_NEW_IFACE_WPS,
-         (WPADBusMethodHandler) &wpas_dbus_handler_wps_start,
+       { "GONegotiationFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
          {
-                 { "args", "a{sv}", ARG_IN },
-                 { "output", "a{sv}", ARG_OUT },
+                 { "status", "i", ARG_OUT },
                  END_ARGS
          }
        },
-#endif /* CONFIG_WPS */
-       { NULL, NULL, NULL, { END_ARGS } }
-};
-
-static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
-       { "Capabilities", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{sv}",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_capabilities,
-         NULL, R
-       },
-       { "State", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_state,
-         NULL, R
-       },
-       { "Scanning", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_scanning,
-         NULL, R
-       },
-       { "ApScan", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_ap_scan,
-         (WPADBusPropertyAccessor) wpas_dbus_setter_ap_scan,
-         RW
-       },
-       { "Ifname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_ifname,
-         NULL, R
-       },
-       { "Driver", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_driver,
-         NULL, R
-       },
-       { "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_bridge_ifname,
-         NULL, R
-       },
-       { "CurrentBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_current_bss,
-         NULL, R
-       },
-       { "CurrentNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_current_network,
-         NULL, R
-       },
-       { "Blobs", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{say}",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_blobs,
-         NULL, R
-       },
-       { "BSSs", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_bsss,
-         NULL, R
-       },
-       { "Networks", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_networks,
-         NULL, R
-       },
-#ifdef CONFIG_WPS
-       { "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b",
-         (WPADBusPropertyAccessor) wpas_dbus_getter_process_credentials,
-         (WPADBusPropertyAccessor) wpas_dbus_setter_process_credentials,
-         RW
-       },
-#endif /* CONFIG_WPS */
-       { NULL, NULL, NULL, NULL, NULL, 0 }
-};
-
-static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
-       { "ScanDone", WPAS_DBUS_NEW_IFACE_INTERFACE,
+       { "GONegotiationRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
          {
-                 { "success", "b", ARG_OUT },
+                 { "path", "o", ARG_OUT },
+                 { "dev_passwd_id", "i", ARG_OUT },
                  END_ARGS
          }
        },
-       { "BSSAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
+       { "InvitationResult", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
          {
-                 { "path", "o", ARG_OUT },
-                 { "properties", "a{sv}", ARG_OUT },
+                 { "invite_result", "a{sv}", ARG_OUT },
                  END_ARGS
          }
        },
-       { "BSSRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
+       { "GroupFinished", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
          {
-                 { "path", "o", ARG_OUT },
+                 { "ifname", "s", ARG_OUT },
+                 { "role", "s", ARG_OUT },
                  END_ARGS
          }
        },
-       { "BlobAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
+       { "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
          {
-                 { "name", "s", ARG_OUT },
+                 { "sd_request", "a{sv}", ARG_OUT },
                  END_ARGS
          }
        },
-       { "BlobRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
+       { "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
          {
-                 { "name", "s", ARG_OUT },
+                 { "sd_response", "a{sv}", ARG_OUT },
                  END_ARGS
          }
        },
-       { "NetworkAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
+       { "PersistentGroupAdded", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
          {
                  { "path", "o", ARG_OUT },
                  { "properties", "a{sv}", ARG_OUT },
                  END_ARGS
          }
        },
-       { "NetworkRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
+       { "PersistentGroupRemoved", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
          {
                  { "path", "o", ARG_OUT },
                  END_ARGS
          }
        },
-       { "NetworkSelected", WPAS_DBUS_NEW_IFACE_INTERFACE,
+       { "WpsFailed", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
          {
-                 { "path", "o", ARG_OUT },
+                 { "name", "s", ARG_OUT },
+                 { "args", "a{sv}", ARG_OUT },
                  END_ARGS
          }
        },
-       { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_INTERFACE,
+#endif /* CONFIG_P2P */
+       { "Certification", WPAS_DBUS_NEW_IFACE_INTERFACE,
          {
-                 { "properties", "a{sv}", ARG_OUT },
+                 { "certification", "a{sv}", ARG_OUT },
                  END_ARGS
          }
        },
-#ifdef CONFIG_WPS
-       { "Event", WPAS_DBUS_NEW_IFACE_WPS,
-         {
-                 { "name", "s", ARG_OUT },
-                 { "args", "a{sv}", ARG_OUT },
-                 END_ARGS
-         }
+       { NULL, NULL, { END_ARGS } }
+};
+
+
+int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
+{
+
+       struct wpa_dbus_object_desc *obj_desc = NULL;
+       struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus;
+       int next;
+
+       /* Do nothing if the control interface is not turned on */
+       if (ctrl_iface == NULL)
+               return 0;
+
+       /* Create and set the interface's object path */
+       wpa_s->dbus_new_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
+       if (wpa_s->dbus_new_path == NULL)
+               return -1;
+       next = ctrl_iface->next_objid++;
+       os_snprintf(wpa_s->dbus_new_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   WPAS_DBUS_NEW_PATH_INTERFACES "/%u",
+                   next);
+
+       obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+       if (!obj_desc) {
+               wpa_printf(MSG_ERROR, "Not enough memory "
+                          "to create object description");
+               goto err;
+       }
+
+       wpas_dbus_register(obj_desc, wpa_s, NULL, wpas_dbus_interface_methods,
+                          wpas_dbus_interface_properties,
+                          wpas_dbus_interface_signals);
+
+       wpa_printf(MSG_DEBUG, "dbus: Register interface object '%s'",
+                  wpa_s->dbus_new_path);
+       if (wpa_dbus_register_object_per_iface(ctrl_iface,
+                                              wpa_s->dbus_new_path,
+                                              wpa_s->ifname, obj_desc))
+               goto err;
+
+       wpas_dbus_signal_interface_added(wpa_s);
+
+       return 0;
+
+err:
+       os_free(wpa_s->dbus_new_path);
+       wpa_s->dbus_new_path = NULL;
+       free_dbus_object_desc(obj_desc);
+       return -1;
+}
+
+
+int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+       struct wpas_dbus_priv *ctrl_iface;
+
+       /* Do nothing if the control interface is not turned on */
+       if (wpa_s == NULL || wpa_s->global == NULL)
+               return 0;
+       ctrl_iface = wpa_s->global->dbus;
+       if (ctrl_iface == NULL)
+               return 0;
+
+       wpa_printf(MSG_DEBUG, "dbus: Unregister interface object '%s'",
+                  wpa_s->dbus_new_path);
+       if (wpa_dbus_unregister_object_per_iface(ctrl_iface,
+                                                wpa_s->dbus_new_path))
+               return -1;
+
+       wpas_dbus_signal_interface_removed(wpa_s);
+
+       os_free(wpa_s->dbus_new_path);
+       wpa_s->dbus_new_path = NULL;
+
+       return 0;
+}
+
+#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,
+         NULL
+       },
+       { "IEs", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
+         wpas_dbus_getter_p2p_peer_ies,
+         NULL
+       },
+       { NULL, NULL, NULL, NULL, NULL }
+};
+
+static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = {
+
+       { NULL, NULL, { END_ARGS } }
+};
+
+/**
+ * wpas_dbus_signal_peer - Send a peer related event signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @dev: peer device object
+ * @interface: name of the interface emitting this signal.
+ *     In case of peer objects, it would be emitted by either
+ *     the "interface object" or by "peer objects"
+ * @sig_name: signal name - DeviceFound
+ *
+ * Notify listeners about event related with newly found p2p peer device
+ */
+static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s,
+                                 const u8 *dev_addr, const char *interface,
+                                 const char *sig_name)
+{
+       struct wpas_dbus_priv *iface;
+       DBusMessage *msg;
+       DBusMessageIter iter;
+       char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+       iface = wpa_s->global->dbus;
+
+       /* Do nothing if the control interface is not turned on */
+       if (iface == NULL)
+               return;
+
+       os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+                   wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+       msg = dbus_message_new_signal(wpa_s->dbus_new_path, interface,
+                                     sig_name);
+       if (msg == NULL)
+               return;
+
+       dbus_message_iter_init_append(msg, &iter);
+       path = peer_obj_path;
+       if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+                                           &path))
+               goto err;
+
+       dbus_connection_send(iface->con, msg, NULL);
+
+       dbus_message_unref(msg);
+       return;
+
+err:
+       wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+       dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_peer_found - Send a peer found signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @dev: peer device object
+ *
+ * Notify listeners about find a p2p peer device found
+ */
+void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
+                                       const u8 *dev_addr)
+{
+       wpas_dbus_signal_peer(wpa_s, dev_addr,
+                             WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+                             "DeviceFound");
+}
+
+/**
+ * wpas_dbus_signal_peer_lost - Send a peer lost signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @dev: peer device object
+ *
+ * Notify listeners about lost a p2p peer device
+ */
+void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
+                                      const u8 *dev_addr)
+{
+       wpas_dbus_signal_peer(wpa_s, dev_addr,
+                             WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+                             "DeviceLost");
+}
+
+/**
+ * wpas_dbus_register_peer - Register a discovered peer object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: network configuration data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers network representing object with dbus
+ */
+int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr)
+{
+       struct wpas_dbus_priv *ctrl_iface;
+       struct wpa_dbus_object_desc *obj_desc;
+       struct peer_handler_args *arg;
+       char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+       /* Do nothing if the control interface is not turned on */
+       if (wpa_s == NULL || wpa_s->global == NULL)
+               return 0;
+
+       ctrl_iface = wpa_s->global->dbus;
+       if (ctrl_iface == NULL)
+               return 0;
+
+       os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+                   wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+       wpa_printf(MSG_INFO, "dbus: Register peer object '%s'",
+                  peer_obj_path);
+       obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+       if (!obj_desc) {
+               wpa_printf(MSG_ERROR, "Not enough memory "
+                          "to create object description");
+               goto err;
+       }
+
+       /* allocate memory for handlers arguments */
+       arg = os_zalloc(sizeof(struct peer_handler_args));
+       if (!arg) {
+               wpa_printf(MSG_ERROR, "Not enough memory "
+                          "to create arguments for method");
+               goto err;
+       }
+
+       arg->wpa_s = wpa_s;
+       os_memcpy(arg->p2p_device_addr, dev_addr, ETH_ALEN);
+
+       wpas_dbus_register(obj_desc, arg, wpa_dbus_free,
+                          NULL,
+                          wpas_dbus_p2p_peer_properties,
+                          wpas_dbus_p2p_peer_signals);
+
+       if (wpa_dbus_register_object_per_iface(ctrl_iface, peer_obj_path,
+                                              wpa_s->ifname, obj_desc))
+               goto err;
+
+       return 0;
+
+err:
+       free_dbus_object_desc(obj_desc);
+       return -1;
+}
+
+/**
+ * wpas_dbus_unregister_peer - Unregister a peer object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @dev_addr: p2p device addr
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers network representing object with dbus
+ */
+int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
+                                 const u8 *dev_addr)
+{
+       struct wpas_dbus_priv *ctrl_iface;
+       char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+       int ret;
+
+       /* Do nothing if the control interface is not turned on */
+       if (wpa_s == NULL || wpa_s->global == NULL ||
+           wpa_s->dbus_new_path == NULL)
+               return 0;
+       ctrl_iface = wpa_s->global->dbus;
+       if (ctrl_iface == NULL)
+               return 0;
+
+       os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+                   wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+       wpa_printf(MSG_INFO, "dbus: Unregister peer object '%s'",
+                  peer_obj_path);
+       ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, peer_obj_path);
+
+       return ret;
+}
+
+
+static const struct wpa_dbus_property_desc wpas_dbus_p2p_group_properties[] = {
+       { "Members", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ao",
+         wpas_dbus_getter_p2p_group_members,
+         NULL
+       },
+       { "Properties",
+         WPAS_DBUS_NEW_IFACE_P2P_GROUP, "a{sv}",
+         wpas_dbus_getter_p2p_group_properties,
+         wpas_dbus_setter_p2p_group_properties
        },
-       { "Credentials", WPAS_DBUS_NEW_IFACE_WPS,
+       { NULL, NULL, NULL, NULL, NULL }
+};
+
+static const struct wpa_dbus_signal_desc wpas_dbus_p2p_group_signals[] = {
+       { "PeerJoined", WPAS_DBUS_NEW_IFACE_P2P_GROUP,
          {
-                 { "credentials", "a{sv}", ARG_OUT },
+                 { "peer", "o", ARG_OUT },
                  END_ARGS
          }
        },
-       { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_WPS,
+       { "PeerDisconnected", WPAS_DBUS_NEW_IFACE_P2P_GROUP,
          {
-                 { "properties", "a{sv}", ARG_OUT },
+                 { "peer", "o", ARG_OUT },
                  END_ARGS
          }
        },
-#endif /* CONFIG_WPS */
        { NULL, NULL, { END_ARGS } }
 };
 
+/**
+ * wpas_dbus_register_p2p_group - Register a p2p group object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: SSID struct
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers p2p group representing object with dbus
+ */
+void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
+                                 struct wpa_ssid *ssid)
+{
+       struct wpas_dbus_priv *ctrl_iface;
+       struct wpa_dbus_object_desc *obj_desc;
+       char group_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+       /* Do nothing if the control interface is not turned on */
+       if (wpa_s == NULL || wpa_s->global == NULL)
+               return;
 
-int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
+       ctrl_iface = wpa_s->global->dbus;
+       if (ctrl_iface == NULL)
+               return;
+
+       if (wpa_s->dbus_groupobj_path) {
+               wpa_printf(MSG_INFO, "%s: Group object '%s' already exists",
+                          __func__, wpa_s->dbus_groupobj_path);
+               return;
+       }
+
+       if (wpas_dbus_get_group_obj_path(wpa_s, ssid, group_obj_path) < 0)
+               return;
+
+       wpa_s->dbus_groupobj_path = os_strdup(group_obj_path);
+       if (wpa_s->dbus_groupobj_path == NULL)
+               return;
+
+       wpa_printf(MSG_INFO, "dbus: Register group object '%s'",
+                  group_obj_path);
+       obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+       if (!obj_desc) {
+               wpa_printf(MSG_ERROR, "Not enough memory "
+                          "to create object description");
+               goto err;
+       }
+
+       wpas_dbus_register(obj_desc, wpa_s, NULL, NULL,
+                          wpas_dbus_p2p_group_properties,
+                          wpas_dbus_p2p_group_signals);
+
+       if (wpa_dbus_register_object_per_iface(ctrl_iface, group_obj_path,
+                                              wpa_s->ifname, obj_desc))
+               goto err;
+
+       return;
+
+err:
+       if (wpa_s->dbus_groupobj_path) {
+               os_free(wpa_s->dbus_groupobj_path);
+               wpa_s->dbus_groupobj_path = NULL;
+       }
+
+       free_dbus_object_desc(obj_desc);
+}
+
+/**
+ * wpas_dbus_unregister_p2p_group - Unregister a p2p group object from dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: network name of the p2p group started
+ */
+void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
+                                   const struct wpa_ssid *ssid)
 {
+       struct wpas_dbus_priv *ctrl_iface;
+
+       /* Do nothing if the control interface is not turned on */
+       if (wpa_s == NULL || wpa_s->global == NULL)
+               return;
+
+       ctrl_iface = wpa_s->global->dbus;
+       if (ctrl_iface == NULL)
+               return;
+
+       if (!wpa_s->dbus_groupobj_path) {
+               wpa_printf(MSG_DEBUG,
+                          "%s: Group object '%s' already unregistered",
+                          __func__, wpa_s->dbus_groupobj_path);
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "dbus: Unregister group object '%s'",
+                  wpa_s->dbus_groupobj_path);
+
+       wpa_dbus_unregister_object_per_iface(ctrl_iface,
+                                            wpa_s->dbus_groupobj_path);
+
+       os_free(wpa_s->dbus_groupobj_path);
+       wpa_s->dbus_groupobj_path = NULL;
+}
+
+static const struct wpa_dbus_property_desc
+wpas_dbus_p2p_groupmember_properties[] = {
+       { "Properties", WPAS_DBUS_NEW_IFACE_P2P_GROUPMEMBER, "a{sv}",
+         wpas_dbus_getter_p2p_group_properties,
+         NULL
+       },
+       { NULL, NULL, NULL, NULL, NULL }
+};
 
+/**
+ * wpas_dbus_register_p2p_groupmember - Register a p2p groupmember
+ * object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @p2p_if_addr: i/f addr of the device joining this group
+ *
+ * Registers p2p groupmember representing object with dbus
+ */
+void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
+                                       const u8 *p2p_if_addr)
+{
+       struct wpas_dbus_priv *ctrl_iface;
        struct wpa_dbus_object_desc *obj_desc = NULL;
-       struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus;
-       int next;
+       struct groupmember_handler_args *arg;
+       char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
 
        /* Do nothing if the control interface is not turned on */
+       if (wpa_s == NULL || wpa_s->global == NULL)
+               return;
+
+       ctrl_iface = wpa_s->global->dbus;
        if (ctrl_iface == NULL)
-               return 0;
+               return;
 
-       /* Create and set the interface's object path */
-       wpa_s->dbus_new_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
-       if (wpa_s->dbus_new_path == NULL)
-               return -1;
-       next = ctrl_iface->next_objid++;
-       os_snprintf(wpa_s->dbus_new_path, WPAS_DBUS_OBJECT_PATH_MAX,
-                   WPAS_DBUS_NEW_PATH_INTERFACES "/%u",
-                   next);
+       if (!wpa_s->dbus_groupobj_path)
+               return;
+
+       os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+               "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR,
+               wpa_s->dbus_groupobj_path, MAC2STR(p2p_if_addr));
 
        obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
        if (!obj_desc) {
@@ -1513,50 +3279,198 @@ int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
                goto err;
        }
 
-       wpas_dbus_register(obj_desc, wpa_s, NULL, wpas_dbus_interface_methods,
-                          wpas_dbus_interface_properties,
-                          wpas_dbus_interface_signals);
+       /* allocate memory for handlers arguments */
+       arg = os_zalloc(sizeof(struct groupmember_handler_args));
+       if (!arg) {
+               wpa_printf(MSG_ERROR, "Not enough memory "
+                          "to create arguments for method");
+               goto err;
+       }
 
-       wpa_printf(MSG_DEBUG, "dbus: Register interface object '%s'",
-                  wpa_s->dbus_new_path);
-       if (wpa_dbus_register_object_per_iface(ctrl_iface,
-                                              wpa_s->dbus_new_path,
+       arg->wpa_s = wpa_s;
+       os_memcpy(arg->member_addr, p2p_if_addr, ETH_ALEN);
+
+       wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
+                          wpas_dbus_p2p_groupmember_properties, NULL);
+
+       if (wpa_dbus_register_object_per_iface(ctrl_iface, groupmember_obj_path,
                                               wpa_s->ifname, obj_desc))
                goto err;
 
-       wpas_dbus_signal_interface_added(wpa_s);
+       wpa_printf(MSG_INFO,
+                  "dbus: Registered group member object '%s' successfully",
+                  groupmember_obj_path);
+       return;
+
+err:
+       free_dbus_object_desc(obj_desc);
+}
+
+/**
+ * wpas_dbus_unregister_p2p_groupmember - Unregister a p2p groupmember
+ * object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @p2p_if_addr: i/f addr of the device joining this group
+ *
+ * Unregisters p2p groupmember representing object with dbus
+ */
+void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
+                                         const u8 *p2p_if_addr)
+{
+       struct wpas_dbus_priv *ctrl_iface;
+       char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+       /* Do nothing if the control interface is not turned on */
+       if (wpa_s == NULL || wpa_s->global == NULL)
+               return;
+
+       ctrl_iface = wpa_s->global->dbus;
+       if (ctrl_iface == NULL)
+               return;
+
+       if (!wpa_s->dbus_groupobj_path)
+               return;
+
+       os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+               "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR,
+               wpa_s->dbus_groupobj_path, MAC2STR(p2p_if_addr));
+
+       wpa_dbus_unregister_object_per_iface(ctrl_iface, groupmember_obj_path);
+}
+
+
+static const struct wpa_dbus_property_desc
+       wpas_dbus_persistent_group_properties[] = {
+       { "Properties", WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, "a{sv}",
+         wpas_dbus_getter_persistent_group_properties,
+         wpas_dbus_setter_persistent_group_properties
+       },
+       { NULL, NULL, NULL, NULL, NULL }
+};
+
+/* No signals intended for persistent group objects */
+
+/**
+ * wpas_dbus_register_persistent_group - Register a configured(saved)
+ *     persistent group with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: persistent group (still represented as a network within wpa)
+ *       configuration data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers a persistent group representing object with dbus.
+ */
+int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
+                                       struct wpa_ssid *ssid)
+{
+       struct wpas_dbus_priv *ctrl_iface;
+       struct wpa_dbus_object_desc *obj_desc;
+       struct network_handler_args *arg;
+       char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+       /* Do nothing if the control interface is not turned on */
+       if (wpa_s == NULL || wpa_s->global == NULL)
+               return 0;
+
+       /* Make sure ssid is a persistent group */
+       if (ssid->disabled != 2 && !ssid->p2p_persistent_group)
+               return -1; /* should we return w/o complaining? */
+
+       ctrl_iface = wpa_s->global->dbus;
+       if (ctrl_iface == NULL)
+               return 0;
+
+       /*
+        * Intentionally not coming up with different numbering scheme
+        * for persistent groups.
+        */
+       os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
+                   wpa_s->dbus_new_path, ssid->id);
+
+       wpa_printf(MSG_DEBUG, "dbus: Register persistent group object '%s'",
+                  pgrp_obj_path);
+       obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+       if (!obj_desc) {
+               wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
+                          "object description");
+               goto err;
+       }
+
+       /*
+        * Reusing the same context structure as that for networks
+        * since these are represented using same data structure.
+        */
+       /* allocate memory for handlers arguments */
+       arg = os_zalloc(sizeof(struct network_handler_args));
+       if (!arg) {
+               wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
+                          "arguments for method");
+               goto err;
+       }
+
+       arg->wpa_s = wpa_s;
+       arg->ssid = ssid;
+
+       wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
+                          wpas_dbus_persistent_group_properties,
+                          NULL);
+
+       if (wpa_dbus_register_object_per_iface(ctrl_iface, pgrp_obj_path,
+                                              wpa_s->ifname, obj_desc))
+               goto err;
+
+       wpas_dbus_signal_persistent_group_added(wpa_s, ssid->id);
 
        return 0;
 
 err:
-       os_free(wpa_s->dbus_new_path);
-       wpa_s->dbus_new_path = NULL;
        free_dbus_object_desc(obj_desc);
        return -1;
 }
 
 
-int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
+/**
+ * wpas_dbus_unregister_persistent_group - Unregister a persistent_group
+ *     from dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @nid: network id
+ * Returns: 0 on success, -1 on failure
+ *
+ * Unregisters persistent group representing object from dbus
+ *
+ * NOTE: There is a slight issue with the semantics here. While the
+ * implementation simply means the persistent group is unloaded from memory,
+ * it should not get interpreted as the group is actually being erased/removed
+ * from persistent storage as well.
+ */
+int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s,
+                                         int nid)
 {
        struct wpas_dbus_priv *ctrl_iface;
+       char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+       int ret;
 
        /* Do nothing if the control interface is not turned on */
-       if (wpa_s == NULL || wpa_s->global == NULL)
+       if (wpa_s == NULL || wpa_s->global == NULL ||
+           wpa_s->dbus_new_path == NULL)
                return 0;
        ctrl_iface = wpa_s->global->dbus;
        if (ctrl_iface == NULL)
                return 0;
 
-       wpa_printf(MSG_DEBUG, "dbus: Unregister interface object '%s'",
-                  wpa_s->dbus_new_path);
-       if (wpa_dbus_unregister_object_per_iface(ctrl_iface,
-                                                wpa_s->dbus_new_path))
-               return -1;
+       os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
+                   wpa_s->dbus_new_path, nid);
 
-       wpas_dbus_signal_interface_removed(wpa_s);
+       wpa_printf(MSG_DEBUG, "dbus: Unregister persistent group object '%s'",
+                  pgrp_obj_path);
+       ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, pgrp_obj_path);
 
-       os_free(wpa_s->dbus_new_path);
-       wpa_s->dbus_new_path = NULL;
+       if (!ret)
+               wpas_dbus_signal_persistent_group_removed(wpa_s, nid);
 
-       return 0;
+       return ret;
 }
+
+#endif /* CONFIG_P2P */
index 80ea98c..62d1008 100644 (file)
 #ifndef CTRL_IFACE_DBUS_NEW_H
 #define CTRL_IFACE_DBUS_NEW_H
 
+#include "common/defs.h"
+#include "p2p/p2p.h"
+
 struct wpa_global;
 struct wpa_supplicant;
 struct wpa_ssid;
 struct wps_event_m2d;
 struct wps_event_fail;
 struct wps_credential;
-enum wpa_states;
 
 enum wpas_dbus_prop {
        WPAS_DBUS_PROP_AP_SCAN,
@@ -30,6 +32,8 @@ enum wpas_dbus_prop {
        WPAS_DBUS_PROP_STATE,
        WPAS_DBUS_PROP_CURRENT_BSS,
        WPAS_DBUS_PROP_CURRENT_NETWORK,
+       WPAS_DBUS_PROP_CURRENT_AUTH_MODE,
+       WPAS_DBUS_PROP_BSSS,
 };
 
 enum wpas_dbus_bss_prop {
@@ -59,6 +63,29 @@ enum wpas_dbus_bss_prop {
 #define WPAS_DBUS_NEW_BSSIDS_PART "BSSs"
 #define WPAS_DBUS_NEW_IFACE_BSS        WPAS_DBUS_NEW_INTERFACE ".BSS"
 
+#define WPAS_DBUS_NEW_IFACE_P2PDEVICE  \
+               WPAS_DBUS_NEW_IFACE_INTERFACE ".P2PDevice"
+
+/*
+ * Groups correspond to P2P groups where this device is a GO (owner)
+ */
+#define WPAS_DBUS_NEW_P2P_GROUPS_PART  "Groups"
+#define        WPAS_DBUS_NEW_IFACE_P2P_GROUP WPAS_DBUS_NEW_INTERFACE ".Group"
+
+/*
+ * Different dbus object for persistent groups so they do not get confused
+ * with regular (configured) network objects.
+ */
+#define WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "PersistentGroups"
+#define WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP \
+       WPAS_DBUS_NEW_INTERFACE ".PersistentGroup"
+
+#define WPAS_DBUS_NEW_P2P_PEERS_PART   "Peers"
+#define        WPAS_DBUS_NEW_IFACE_P2P_PEER WPAS_DBUS_NEW_INTERFACE ".Peer"
+
+#define WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART    "Members"
+#define        WPAS_DBUS_NEW_IFACE_P2P_GROUPMEMBER \
+       WPAS_DBUS_NEW_INTERFACE ".GroupMember"
 
 /* Errors */
 #define WPAS_DBUS_ERROR_UNKNOWN_ERROR \
@@ -76,11 +103,24 @@ enum wpas_dbus_bss_prop {
 #define WPAS_DBUS_ERROR_NETWORK_UNKNOWN \
        WPAS_DBUS_NEW_INTERFACE ".NetworkUnknown"
 
+#define WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE \
+       WPAS_DBUS_NEW_INTERFACE ".ConnectChannelUnavailable"
+#define WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED \
+       WPAS_DBUS_NEW_INTERFACE ".ConnectChannelUnsupported"
+#define WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR \
+       WPAS_DBUS_NEW_INTERFACE ".ConnectUnspecifiedError"
+
 #define WPAS_DBUS_ERROR_BLOB_EXISTS \
        WPAS_DBUS_NEW_INTERFACE ".BlobExists"
 #define WPAS_DBUS_ERROR_BLOB_UNKNOWN \
        WPAS_DBUS_NEW_INTERFACE ".BlobUnknown"
-
+/*
+ * 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
 
 #ifdef CONFIG_CTRL_IFACE_DBUS_NEW
 
@@ -97,6 +137,10 @@ void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s,
 void wpas_dbus_signal_network_enabled_changed(struct wpa_supplicant *wpa_s,
                                              struct wpa_ssid *ssid);
 void wpas_dbus_signal_network_selected(struct wpa_supplicant *wpa_s, int id);
+void wpas_dbus_signal_network_request(struct wpa_supplicant *wpa_s,
+                                     struct wpa_ssid *ssid,
+                                     enum wpa_ctrl_req_type rtype,
+                                     const char *default_text);
 void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, int success);
 void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
                               const struct wps_credential *cred);
@@ -120,6 +164,59 @@ void wpas_dbus_signal_debug_level_changed(struct wpa_global *global);
 void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global);
 void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global);
 
+int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr);
+void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
+                                          const u8 *dev_addr);
+int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
+                                 const u8 *dev_addr);
+void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
+                                          const u8 *dev_addr);
+void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
+                                       const char *role);
+void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+                                             const u8 *dev_addr, int request,
+                                             enum p2p_prov_disc_status status,
+                                             u16 config_methods,
+                                             unsigned int generated_pin);
+void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
+                                    const u8 *src, u16 dev_passwd_id);
+void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
+                                       const struct wpa_ssid *ssid,
+                                       int client, int network_id);
+void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
+                                 struct wpa_ssid *ssid);
+void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
+                                     struct p2p_go_neg_results *res);
+void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
+                                   const struct wpa_ssid *ssid);
+int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
+                                       struct wpa_ssid *ssid);
+int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s,
+                                         int nid);
+void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s,
+                                           int status, const u8 *bssid);
+void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
+                                       const u8 *p2p_if_addr);
+void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
+                                         const u8 *p2p_if_addr);
+void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
+                                           const u8 *member);
+void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
+                                    int freq, const u8 *sa, u8 dialog_token,
+                                    u16 update_indic, const u8 *tlvs,
+                                    size_t tlvs_len);
+void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
+                                     const u8 *sa, u16 update_indic,
+                                     const u8 *tlvs, size_t tlvs_len);
+void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
+                               const u8 *member);
+void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+                                    struct wps_event_fail *fail);
+void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
+                                   int depth, const char *subject,
+                                   const char *cert_hash,
+                                   const struct wpabuf *cert);
+
 #else /* CONFIG_CTRL_IFACE_DBUS_NEW */
 
 static inline int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
@@ -155,6 +252,12 @@ static inline void wpas_dbus_signal_network_selected(
 {
 }
 
+static inline void wpas_dbus_signal_network_request(
+       struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+       enum wpa_ctrl_req_type rtype, const char *default_txt)
+{
+}
+
 static inline void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s,
                                              int success)
 {
@@ -229,6 +332,147 @@ static inline void wpas_dbus_signal_debug_show_keys_changed(
 {
 }
 
+static inline int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s,
+                                         const u8 *dev_addr)
+{
+       return 0;
+}
+
+static inline int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
+                                           const u8 *dev_addr)
+{
+       return 0;
+}
+
+static inline void
+wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
+                                  const char *role)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+                                        const u8 *dev_addr, int request,
+                                        enum p2p_prov_disc_status status,
+                                        u16 config_methods,
+                                        unsigned int generated_pin)
+{
+}
+
+static inline void wpas_dbus_signal_p2p_go_neg_req(
+                               struct wpa_supplicant *wpa_s,
+                               const u8 *src,
+                               u16 dev_passwd_id)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
+                                  const struct wpa_ssid *ssid,
+                                  int client, int network_id)
+{
+}
+
+static inline void
+wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
+                            struct wpa_ssid *ssid)
+{
+}
+
+static inline int wpas_dbus_register_persistent_group(
+       struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+       return 0;
+}
+
+static inline int wpas_dbus_unregister_persistent_group(
+       struct wpa_supplicant *wpa_s, int nid)
+{
+       return 0;
+}
+
+static inline void
+wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
+                                struct p2p_go_neg_results *res)
+{
+}
+
+static inline void
+wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
+                              const struct wpa_ssid *ssid)
+{
+}
+
+static inline void wpas_dbus_signal_p2p_invitation_result(
+                               struct wpa_supplicant *wpa_s, int status,
+                               const u8 *bssid)
+{
+}
+
+static inline void
+wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
+                                  const u8 *p2p_if_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s, int freq,
+                               const u8 *sa, u8 dialog_token, u16 update_indic,
+                               const u8 *tlvs, size_t tlvs_len)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
+                                const u8 *sa, u16 update_indic,
+                                const u8 *tlvs, size_t tlvs_len)
+{
+}
+
+static inline void
+wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
+                                    const u8 *p2p_if_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
+                                const u8 *member)
+{
+}
+
+static inline void
+wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
+                                  const u8 *dev_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
+                                 const u8 *dev_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
+                                      const u8 *member)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+                               struct wps_event_fail *fail)
+{
+}
+
+static inline void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
+                                                 int depth,
+                                                 const char *subject,
+                                                 const char *cert_hash,
+                                                 const struct wpabuf *cert)
+{
+}
+
 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
 
 #endif /* CTRL_IFACE_DBUS_H_NEW */
index e2b5e50..8fc8aee 100644 (file)
@@ -25,9 +25,9 @@
 #include "../wpa_supplicant_i.h"
 #include "../driver_i.h"
 #include "../notify.h"
-#include "../wpas_glue.h"
 #include "../bss.h"
 #include "../scan.h"
+#include "../ctrl_iface.h"
 #include "dbus_new_helpers.h"
 #include "dbus_new.h"
 #include "dbus_new_handlers.h"
@@ -38,75 +38,11 @@ extern int wpa_debug_show_keys;
 extern int wpa_debug_timestamp;
 
 static const char *debug_strings[] = {
-       "msgdump", "debug", "info", "warning", "error", NULL
+       "excessive", "msgdump", "debug", "info", "warning", "error", NULL
 };
 
 
 /**
- * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts
- * @path: The dbus object path
- * @network: (out) the configured network this object path refers to, if any
- * @bssid: (out) the scanned bssid this object path refers to, if any
- * Returns: The object path of the network interface this path refers to
- *
- * For a given object path, decomposes the object path into object id, network,
- * and BSSID parts, if those parts exist.
- */
-static char * wpas_dbus_new_decompose_object_path(const char *path,
-                                                 char **network,
-                                                 char **bssid)
-{
-       const unsigned int dev_path_prefix_len =
-               strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/");
-       char *obj_path_only;
-       char *next_sep;
-
-       /* Be a bit paranoid about path */
-       if (!path || os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
-                               dev_path_prefix_len))
-               return NULL;
-
-       /* Ensure there's something at the end of the path */
-       if ((path + dev_path_prefix_len)[0] == '\0')
-               return NULL;
-
-       obj_path_only = os_strdup(path);
-       if (obj_path_only == NULL)
-               return NULL;
-
-       next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/');
-       if (next_sep != NULL) {
-               const char *net_part = os_strstr(
-                       next_sep, WPAS_DBUS_NEW_NETWORKS_PART "/");
-               const char *bssid_part = os_strstr(
-                       next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/");
-
-               if (network && net_part) {
-                       /* Deal with a request for a configured network */
-                       const char *net_name = net_part +
-                               os_strlen(WPAS_DBUS_NEW_NETWORKS_PART "/");
-                       *network = NULL;
-                       if (os_strlen(net_name))
-                               *network = os_strdup(net_name);
-               } else if (bssid && bssid_part) {
-                       /* Deal with a request for a scanned BSSID */
-                       const char *bssid_name = bssid_part +
-                               os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/");
-                       if (strlen(bssid_name))
-                               *bssid = os_strdup(bssid_name);
-                       else
-                               *bssid = NULL;
-               }
-
-               /* Cut off interface object path before "/" */
-               *next_sep = '\0';
-       }
-
-       return obj_path_only;
-}
-
-
-/**
  * wpas_dbus_error_unknown_error - Return a new InvalidArgs error message
  * @message: Pointer to incoming dbus message this error refers to
  * @arg: Optional string appended to error message
@@ -117,6 +53,20 @@ static char * wpas_dbus_new_decompose_object_path(const char *path,
 DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
                                            const char *arg)
 {
+       /*
+        * This function can be called as a result of a failure
+        * within internal getter calls, which will call this function
+        * with a NULL message parameter.  However, dbus_message_new_error
+        * looks very unkindly (i.e, abort()) on a NULL message, so
+        * in this case, we should not call it.
+        */
+       if (message == NULL) {
+               wpa_printf(MSG_INFO, "dbus: wpas_dbus_error_unknown_error "
+                          "called with NULL message (arg=%s)",
+                          arg ? arg : "N/A");
+               return NULL;
+       }
+
        return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR,
                                      arg);
 }
@@ -213,36 +163,35 @@ static struct wpa_supplicant * get_iface_by_dbus_path(
 
 /**
  * set_network_properties - Set properties of a configured network
- * @message: Pointer to incoming dbus message
  * @wpa_s: wpa_supplicant structure for a network interface
  * @ssid: wpa_ssid structure for a configured network
  * @iter: DBus message iterator containing dictionary of network
  * properties to set.
- * Returns: NULL when succeed or DBus error on failure
+ * @error: On failure, an error describing the failure
+ * Returns: TRUE if the request succeeds, FALSE if it failed
  *
  * Sets network configuration with parameters given id DBus dictionary
  */
-static DBusMessage * set_network_properties(DBusMessage *message,
-                                           struct wpa_supplicant *wpa_s,
-                                           struct wpa_ssid *ssid,
-                                           DBusMessageIter *iter)
+dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
+                                  struct wpa_ssid *ssid,
+                                  DBusMessageIter *iter,
+                                  DBusError *error)
 {
-
        struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
-       DBusMessage *reply = NULL;
        DBusMessageIter iter_dict;
+       char *value = NULL;
 
-       if (!wpa_dbus_dict_open_read(iter, &iter_dict))
-               return wpas_dbus_error_invalid_args(message, NULL);
+       if (!wpa_dbus_dict_open_read(iter, &iter_dict, error))
+               return FALSE;
 
        while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
-               char *value = NULL;
                size_t size = 50;
                int ret;
-               if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
-                       reply = wpas_dbus_error_invalid_args(message, NULL);
-                       break;
-               }
+
+               if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+                       goto error;
+
+               value = NULL;
                if (entry.type == DBUS_TYPE_ARRAY &&
                    entry.array_type == DBUS_TYPE_BYTE) {
                        if (entry.array_len <= 0)
@@ -311,71 +260,59 @@ static DBusMessage * set_network_properties(DBusMessage *message,
 
                os_free(value);
                wpa_dbus_dict_entry_clear(&entry);
-               continue;
-
-       error:
-               os_free(value);
-               reply = wpas_dbus_error_invalid_args(message, entry.key);
-               wpa_dbus_dict_entry_clear(&entry);
-               break;
        }
 
-       return reply;
+       return TRUE;
+
+error:
+       os_free(value);
+       wpa_dbus_dict_entry_clear(&entry);
+       dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+                            "invalid message format");
+       return FALSE;
 }
 
 
 /**
  * wpas_dbus_simple_property_getter - Get basic type property
- * @message: Pointer to incoming dbus message
+ * @iter: Message iter to use when appending arguments
  * @type: DBus type of property (must be basic type)
  * @val: pointer to place holding property value
- * Returns: The DBus message containing response for Properties.Get call
- * or DBus error message if error occurred.
+ * @error: On failure an error describing the failure
+ * Returns: TRUE if the request was successful, FALSE if it failed
  *
  * Generic getter for basic type properties. Type is required to be basic.
  */
-DBusMessage * wpas_dbus_simple_property_getter(DBusMessage *message,
-                                              const int type, const void *val)
+dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
+                                            const int type,
+                                            const void *val,
+                                            DBusError *error)
 {
-       DBusMessage *reply = NULL;
-       DBusMessageIter iter, variant_iter;
+       DBusMessageIter variant_iter;
 
        if (!dbus_type_is_basic(type)) {
-               wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_getter:"
-                          " given type is not basic");
-               return wpas_dbus_error_unknown_error(message, NULL);
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: given type is not basic", __func__);
+               return FALSE;
        }
 
-       if (message == NULL)
-               reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-       else
-               reply = dbus_message_new_method_return(message);
-
-       if (reply != NULL) {
-               dbus_message_iter_init_append(reply, &iter);
-               if (!dbus_message_iter_open_container(
-                           &iter, DBUS_TYPE_VARIANT,
-                           wpa_dbus_type_as_string(type), &variant_iter) ||
-                   !dbus_message_iter_append_basic(&variant_iter, type,
-                                                   val) ||
-                   !dbus_message_iter_close_container(&iter, &variant_iter)) {
-                       wpa_printf(MSG_ERROR, "dbus: "
-                                  "wpas_dbus_simple_property_getter: out of "
-                                  "memory to put property value into "
-                                  "message");
-                       dbus_message_unref(reply);
-                       reply = dbus_message_new_error(message,
-                                                      DBUS_ERROR_NO_MEMORY,
-                                                      NULL);
-               }
-       } else {
-               wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_getter:"
-                          " out of memory to return property value");
-               reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                              NULL);
-       }
+       if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+                                             wpa_dbus_type_as_string(type),
+                                             &variant_iter))
+               goto error;
 
-       return reply;
+       if (!dbus_message_iter_append_basic(&variant_iter, type, val))
+               goto error;
+
+       if (!dbus_message_iter_close_container(iter, &variant_iter))
+               goto error;
+
+       return TRUE;
+
+error:
+       dbus_set_error(error, DBUS_ERROR_FAILED,
+                      "%s: error constructing reply", __func__);
+       return FALSE;
 }
 
 
@@ -384,102 +321,79 @@ DBusMessage * wpas_dbus_simple_property_getter(DBusMessage *message,
  * @message: Pointer to incoming dbus message
  * @type: DBus type of property (must be basic type)
  * @val: pointer to place where value being set will be stored
- * Returns: NULL or DBus error message if error occurred.
+ * Returns: TRUE if the request was successful, FALSE if it failed
  *
  * Generic setter for basic type properties. Type is required to be basic.
  */
-DBusMessage * wpas_dbus_simple_property_setter(DBusMessage *message,
-                                              const int type, void *val)
+dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter,
+                                            DBusError *error,
+                                            const int type, void *val)
 {
-       DBusMessageIter iter, variant_iter;
+       DBusMessageIter variant_iter;
 
        if (!dbus_type_is_basic(type)) {
-               wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_setter:"
-                          " given type is not basic");
-               return wpas_dbus_error_unknown_error(message, NULL);
-       }
-
-       if (!dbus_message_iter_init(message, &iter)) {
-               wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_setter:"
-                          " out of memory to return scanning state");
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: given type is not basic", __func__);
+               return FALSE;
        }
 
-       /* omit first and second argument and get value from third */
-       dbus_message_iter_next(&iter);
-       dbus_message_iter_next(&iter);
-       dbus_message_iter_recurse(&iter, &variant_iter);
-
+       /* Look at the new value */
+       dbus_message_iter_recurse(iter, &variant_iter);
        if (dbus_message_iter_get_arg_type(&variant_iter) != type) {
-               wpa_printf(MSG_DEBUG, "dbus: wpas_dbus_simple_property_setter:"
-                          " wrong property type");
-               return wpas_dbus_error_invalid_args(message,
-                                                   "wrong property type");
+               dbus_set_error_const(error, DBUS_ERROR_FAILED,
+                                    "wrong property type");
+               return FALSE;
        }
        dbus_message_iter_get_basic(&variant_iter, val);
 
-       return NULL;
+       return TRUE;
 }
 
 
 /**
  * wpas_dbus_simple_array_property_getter - Get array type property
- * @message: Pointer to incoming dbus message
+ * @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
- * Returns: The DBus message containing response for Properties.Get call
- * or DBus error message if error occurred.
+ * @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.
  */
-DBusMessage * wpas_dbus_simple_array_property_getter(DBusMessage *message,
-                                                    const int type,
-                                                    const void *array,
-                                                    size_t array_len)
+dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
+                                                  const int type,
+                                                  const void *array,
+                                                  size_t array_len,
+                                                  DBusError *error)
 {
-       DBusMessage *reply = NULL;
-       DBusMessageIter iter, variant_iter, array_iter;
+       DBusMessageIter variant_iter, array_iter;
        char type_str[] = "a?"; /* ? will be replaced with subtype letter; */
        const char *sub_type_str;
        size_t element_size, i;
 
        if (!dbus_type_is_basic(type)) {
-               wpa_printf(MSG_ERROR, "dbus: "
-                          "wpas_dbus_simple_array_property_getter: given "
-                          "type is not basic");
-               return wpas_dbus_error_unknown_error(message, NULL);
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: given type is not basic", __func__);
+               return FALSE;
        }
 
        sub_type_str = wpa_dbus_type_as_string(type);
        type_str[1] = sub_type_str[0];
 
-       if (message == NULL)
-               reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-       else
-               reply = dbus_message_new_method_return(message);
-       if (reply == NULL) {
-               wpa_printf(MSG_ERROR, "dbus: "
-                          "wpas_dbus_simple_array_property_getter: out of "
-                          "memory to create return message");
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+       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;
        }
 
-       dbus_message_iter_init_append(reply, &iter);
-
-       if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
-                                             type_str, &variant_iter) ||
-           !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+       if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
                                              sub_type_str, &array_iter)) {
-               wpa_printf(MSG_ERROR, "dbus: "
-                          "wpas_dbus_simple_array_property_getter: out of "
-                          "memory to open container");
-               dbus_message_unref(reply);
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: failed to construct message 2", __func__);
+               return FALSE;
        }
 
        switch(type) {
@@ -507,11 +421,9 @@ DBusMessage * wpas_dbus_simple_array_property_getter(DBusMessage *message,
                element_size = sizeof(char *);
                break;
        default:
-               wpa_printf(MSG_ERROR, "dbus: "
-                          "wpas_dbus_simple_array_property_getter: "
-                          "fatal: unknown element type");
-               element_size = 1;
-               break;
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: unknown element type %d", __func__, type);
+               return FALSE;
        }
 
        for (i = 0; i < array_len; i++) {
@@ -519,17 +431,19 @@ DBusMessage * wpas_dbus_simple_array_property_getter(DBusMessage *message,
                                               array + i * element_size);
        }
 
-       if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
-           !dbus_message_iter_close_container(&iter, &variant_iter)) {
-               wpa_printf(MSG_ERROR, "dbus: "
-                          "wpas_dbus_simple_array_property_getter: out of "
-                          "memory to close container");
-               dbus_message_unref(reply);
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+       if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: failed to construct message 3", __func__);
+               return FALSE;
        }
 
-       return reply;
+       if (!dbus_message_iter_close_container(iter, &variant_iter)) {
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: failed to construct message 4", __func__);
+               return FALSE;
+       }
+
+       return TRUE;
 }
 
 
@@ -553,11 +467,12 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
        struct wpa_dbus_dict_entry entry;
        char *driver = NULL;
        char *ifname = NULL;
+       char *confname = NULL;
        char *bridge_ifname = NULL;
 
        dbus_message_iter_init(message, &iter);
 
-       if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+       if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
                goto error;
        while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
                if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
@@ -574,6 +489,12 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
                        wpa_dbus_dict_entry_clear(&entry);
                        if (ifname == NULL)
                                goto error;
+               } else if (!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") &&
                           (entry.type == DBUS_TYPE_STRING)) {
                        bridge_ifname = os_strdup(entry.str_value);
@@ -604,6 +525,7 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
                os_memset(&iface, 0, sizeof(iface));
                iface.driver = driver;
                iface.ifname = ifname;
+               iface.confname = confname;
                iface.bridge_ifname = bridge_ifname;
                /* Otherwise, have wpa_supplicant attach to it. */
                if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
@@ -706,79 +628,86 @@ DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
 
 /**
  * wpas_dbus_getter_debug_level - Get debug level
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: DBus message with value of debug level
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "DebugLevel" property.
  */
-DBusMessage * wpas_dbus_getter_debug_level(DBusMessage *message,
-                                          struct wpa_global *global)
+dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
+                                        DBusError *error,
+                                        void *user_data)
 {
        const char *str;
        int idx = wpa_debug_level;
+
        if (idx < 0)
                idx = 0;
-       if (idx > 4)
-               idx = 4;
+       if (idx > 5)
+               idx = 5;
        str = debug_strings[idx];
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-                                               &str);
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                               &str, error);
 }
 
 
 /**
  * wpas_dbus_getter_debug_timestamp - Get debug timestamp
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: DBus message with value of debug timestamp
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "DebugTimestamp" property.
  */
-DBusMessage * wpas_dbus_getter_debug_timestamp(DBusMessage *message,
-                                              struct wpa_global *global)
+dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
+                                             DBusError *error,
+                                             void *user_data)
 {
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-                                               &wpa_debug_timestamp);
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+                                               &wpa_debug_timestamp, error);
 
 }
 
 
 /**
  * wpas_dbus_getter_debug_show_keys - Get debug show keys
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: DBus message with value of debug show_keys
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "DebugShowKeys" property.
  */
-DBusMessage * wpas_dbus_getter_debug_show_keys(DBusMessage *message,
-                                              struct wpa_global *global)
+dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
+                                            DBusError *error,
+                                            void *user_data)
 {
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-                                               &wpa_debug_show_keys);
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+                                               &wpa_debug_show_keys, error);
 
 }
 
 /**
  * wpas_dbus_setter_debug_level - Set debug level
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: %NULL or DBus error message
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Setter for "DebugLevel" property.
  */
-DBusMessage * wpas_dbus_setter_debug_level(DBusMessage *message,
-                                          struct wpa_global *global)
+dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
+                                        DBusError *error, void *user_data)
 {
-       DBusMessage *reply;
+       struct wpa_global *global = user_data;
        const char *str = NULL;
        int i, val = -1;
 
-       reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_STRING,
-                                                &str);
-       if (reply)
-               return reply;
+       if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+                                             &str))
+               return FALSE;
 
        for (i = 0; debug_strings[i]; i++)
                if (os_strcmp(debug_strings[i], str) == 0) {
@@ -789,138 +718,142 @@ DBusMessage * wpas_dbus_setter_debug_level(DBusMessage *message,
        if (val < 0 ||
            wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp,
                                            wpa_debug_show_keys)) {
-               dbus_message_unref(reply);
-               return wpas_dbus_error_invalid_args(
-                       message, "Wrong debug level value");
+               dbus_set_error_const(error, DBUS_ERROR_FAILED, "wrong debug "
+                                    "level value");
+               return FALSE;
        }
 
-       return NULL;
+       return TRUE;
 }
 
 
 /**
  * wpas_dbus_setter_debug_timestamp - Set debug timestamp
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: %NULL or DBus error message
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Setter for "DebugTimestamp" property.
  */
-DBusMessage * wpas_dbus_setter_debug_timestamp(DBusMessage *message,
-                                              struct wpa_global *global)
+dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
+                                            DBusError *error,
+                                            void *user_data)
 {
-       DBusMessage *reply;
+       struct wpa_global *global = user_data;
        dbus_bool_t val;
 
-       reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN,
-                                                &val);
-       if (reply)
-               return reply;
+       if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
+                                             &val))
+               return FALSE;
 
        wpa_supplicant_set_debug_params(global, wpa_debug_level, val ? 1 : 0,
                                        wpa_debug_show_keys);
-
-       return NULL;
+       return TRUE;
 }
 
 
 /**
  * wpas_dbus_setter_debug_show_keys - Set debug show keys
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: %NULL or DBus error message
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Setter for "DebugShowKeys" property.
  */
-DBusMessage * wpas_dbus_setter_debug_show_keys(DBusMessage *message,
-                                              struct wpa_global *global)
+dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
+                                            DBusError *error,
+                                            void *user_data)
 {
-       DBusMessage *reply;
+       struct wpa_global *global = user_data;
        dbus_bool_t val;
 
-       reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN,
-                                                &val);
-       if (reply)
-               return reply;
+       if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
+                                             &val))
+               return FALSE;
 
        wpa_supplicant_set_debug_params(global, wpa_debug_level,
                                        wpa_debug_timestamp,
                                        val ? 1 : 0);
-
-       return NULL;
+       return TRUE;
 }
 
 
 /**
  * wpas_dbus_getter_interfaces - Request registered interfaces list
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: The object paths array containing registered interfaces
- * objects paths or DBus error on failure
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Interfaces" property. Handles requests
  * by dbus clients to return list of registered interfaces objects
  * paths
  */
-DBusMessage * wpas_dbus_getter_interfaces(DBusMessage *message,
-                                         struct wpa_global *global)
+dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
+                                       DBusError *error,
+                                       void *user_data)
 {
-       DBusMessage *reply = NULL;
+       struct wpa_global *global = user_data;
        struct wpa_supplicant *wpa_s;
        const char **paths;
        unsigned int i = 0, num = 0;
+       dbus_bool_t success;
 
        for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
                num++;
 
        paths = os_zalloc(num * sizeof(char*));
        if (!paths) {
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+               return FALSE;
        }
 
        for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
-               paths[i] = wpa_s->dbus_new_path;
+               paths[i++] = wpa_s->dbus_new_path;
 
-       reply = wpas_dbus_simple_array_property_getter(message,
-                                                      DBUS_TYPE_OBJECT_PATH,
-                                                      paths, num);
+       success = wpas_dbus_simple_array_property_getter(iter,
+                                                        DBUS_TYPE_OBJECT_PATH,
+                                                        paths, num, error);
 
        os_free(paths);
-       return reply;
+       return success;
 }
 
 
 /**
  * wpas_dbus_getter_eap_methods - Request supported EAP methods list
- * @message: Pointer to incoming dbus message
- * @nothing: not used argument. may be NULL or anything else
- * Returns: The object paths array containing supported EAP methods
- * represented by strings or DBus error on failure
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "EapMethods" property. Handles requests
  * by dbus clients to return list of strings with supported EAP methods
  */
-DBusMessage * wpas_dbus_getter_eap_methods(DBusMessage *message, void *nothing)
+dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
+                                        DBusError *error, void *user_data)
 {
-       DBusMessage *reply = NULL;
        char **eap_methods;
        size_t num_items = 0;
+       dbus_bool_t success;
 
        eap_methods = eap_get_names_as_string_array(&num_items);
        if (!eap_methods) {
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+               return FALSE;
        }
 
-       reply = wpas_dbus_simple_array_property_getter(message,
-                                                      DBUS_TYPE_STRING,
-                                                      eap_methods, num_items);
+       success = wpas_dbus_simple_array_property_getter(iter,
+                                                        DBUS_TYPE_STRING,
+                                                        eap_methods,
+                                                        num_items, error);
 
        while (num_items)
                os_free(eap_methods[--num_items]);
        os_free(eap_methods);
-       return reply;
+       return success;
 }
 
 
@@ -987,21 +920,24 @@ static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
                dbus_message_iter_recurse(&array_iter, &sub_array_iter);
 
                dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
-               if (len == 0) {
-                       dbus_message_iter_next(&array_iter);
-                       continue;
-               }
 
-               ssid = os_malloc(len);
-               if (ssid == NULL) {
-                       wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-                                  "out of memory. Cannot allocate memory for "
-                                  "SSID");
-                       *reply = dbus_message_new_error(
-                               message, DBUS_ERROR_NO_MEMORY, NULL);
-                       return -1;
+               if (len != 0) {
+                       ssid = os_malloc(len);
+                       if (ssid == NULL) {
+                               wpa_printf(MSG_DEBUG,
+                                          "wpas_dbus_handler_scan[dbus]: "
+                                          "out of memory. Cannot allocate "
+                                          "memory for SSID");
+                               *reply = dbus_message_new_error(
+                                       message, DBUS_ERROR_NO_MEMORY, NULL);
+                               return -1;
+                       }
+                       os_memcpy(ssid, val, len);
+               } else {
+                       /* Allow zero-length SSIDs */
+                       ssid = NULL;
                }
-               os_memcpy(ssid, val, len);
+
                ssids[ssids_num].ssid = ssid;
                ssids[ssids_num].ssid_len = len;
 
@@ -1260,14 +1196,16 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
                                "passive scan");
                        goto out;
                } else if (params.freqs && params.freqs[0]) {
-                       /* wildcard ssid */
-                       params.num_ssids++;
                        wpa_supplicant_trigger_scan(wpa_s, &params);
                } else {
                        wpa_s->scan_req = 2;
                        wpa_supplicant_req_scan(wpa_s, 0, 0);
                }
        } else if (!os_strcmp(type, "active")) {
+               if (!params.num_ssids) {
+                       /* Add wildcard ssid */
+                       params.num_ssids++;
+               }
                wpa_supplicant_trigger_scan(wpa_s, &params);
        } else {
                wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
@@ -1326,6 +1264,7 @@ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
        DBusMessageIter iter;
        struct wpa_ssid *ssid = NULL;
        char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
+       DBusError error;
 
        dbus_message_iter_init(message, &iter);
 
@@ -1343,11 +1282,15 @@ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
        ssid->disabled = 1;
        wpa_config_set_network_defaults(ssid);
 
-       reply = set_network_properties(message, wpa_s, ssid, &iter);
-       if (reply) {
+       dbus_error_init(&error);
+       if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
                wpa_printf(MSG_DEBUG, "wpas_dbus_handler_add_network[dbus]:"
                           "control interface couldn't set network "
                           "properties");
+               reply = wpas_dbus_reply_new_from_error(message, &error,
+                                                      DBUS_ERROR_INVALID_ARGS,
+                                                      "Failed to add network");
+               dbus_error_free(&error);
                goto err;
        }
 
@@ -1403,7 +1346,7 @@ 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, &net_id, NULL);
+       iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
        if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
                reply = wpas_dbus_error_invalid_args(message, op);
                goto out;
@@ -1444,6 +1387,42 @@ out:
 }
 
 
+static void remove_network(void *arg, struct wpa_ssid *ssid)
+{
+       struct wpa_supplicant *wpa_s = arg;
+
+       wpas_notify_network_removed(wpa_s, ssid);
+
+       if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
+               wpa_printf(MSG_ERROR,
+                          "wpas_dbus_handler_remove_all_networks[dbus]: "
+                          "error occurred when removing network %d",
+                          ssid->id);
+               return;
+       }
+
+       if (ssid == wpa_s->current_ssid)
+               wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+}
+
+
+/**
+ * wpas_dbus_handler_remove_all_networks - Remove all configured networks
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "RemoveAllNetworks" method call of a network interface.
+ */
+DBusMessage * wpas_dbus_handler_remove_all_networks(
+       DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+       /* NB: could check for failure and return an error */
+       wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s);
+       return NULL;
+}
+
+
 /**
  * wpas_dbus_handler_select_network - Attempt association with a network
  * @message: Pointer to incoming dbus message
@@ -1466,7 +1445,7 @@ 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, &net_id, NULL);
+       iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
        if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
                reply = wpas_dbus_error_invalid_args(message, op);
                goto out;
@@ -1495,6 +1474,70 @@ out:
 
 
 /**
+ * wpas_dbus_handler_network_reply - Reply to a NetworkRequest signal
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "NetworkReply" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
+                                             struct wpa_supplicant *wpa_s)
+{
+#ifdef IEEE8021X_EAPOL
+       DBusMessage *reply = NULL;
+       const char *op, *field, *value;
+       char *iface = NULL, *net_id = NULL;
+       int id;
+       struct wpa_ssid *ssid;
+
+       if (!dbus_message_get_args(message, NULL,
+                                  DBUS_TYPE_OBJECT_PATH, &op,
+                                  DBUS_TYPE_STRING, &field,
+                                  DBUS_TYPE_STRING, &value,
+                                  DBUS_TYPE_INVALID))
+               return wpas_dbus_error_invalid_args(message, NULL);
+
+       /* Extract the network ID and ensure the network */
+       /* is actually a child of this interface */
+       iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
+       if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+               reply = wpas_dbus_error_invalid_args(message, op);
+               goto out;
+       }
+
+       id = strtoul(net_id, NULL, 10);
+       if (errno == EINVAL) {
+               reply = wpas_dbus_error_invalid_args(message, net_id);
+               goto out;
+       }
+
+       ssid = wpa_config_get_network(wpa_s->conf, id);
+       if (ssid == NULL) {
+               reply = wpas_dbus_error_network_unknown(message);
+               goto out;
+       }
+
+       if (wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid,
+                                                     field, value) < 0)
+               reply = wpas_dbus_error_invalid_args(message, field);
+       else {
+               /* Tell EAP to retry immediately */
+               eapol_sm_notify_ctrl_response(wpa_s->eapol);
+       }
+
+out:
+       os_free(iface);
+       os_free(net_id);
+       return reply;
+#else /* IEEE8021X_EAPOL */
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
+       return wpas_dbus_error_unknown_error(message, "802.1X not included");
+#endif /* IEEE8021X_EAPOL */
+}
+
+
+/**
  * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
  * @message: Pointer to incoming dbus message
  * @wpa_s: %wpa_supplicant data structure
@@ -1658,38 +1701,102 @@ 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.
+ */
 
-/**
- * wpas_dbus_getter_capabilities - Return interface capabilities
+#if defined TIZEN_EXT
+/*
+ * wpas_dbus_handler_get_link_signal - Get link signal
  * @message: Pointer to incoming dbus message
  * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a dict of strings
+ * Returns: A dbus message containing an integer value(signal) or dbus error
  *
- * Getter for "Capabilities" property of an interface.
+ * Handler function for "GetLinkSignal" method call of network interface.
  */
-DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message,
-                                           struct wpa_supplicant *wpa_s)
+DBusMessage * wpas_dbus_handler_get_link_signal(DBusMessage *message,
+               struct wpa_supplicant *wpa_s)
 {
        DBusMessage *reply = NULL;
+       DBusMessageIter iter;
+       struct wpa_signal_info si;
+
+       if(wpa_drv_signal_poll(wpa_s, &si)) {
+               return dbus_message_new_error(message,
+                                                       WPAS_DBUS_ERROR_SIGNAL_UNKNOWN,
+                                                       "Can't get siganl");
+       }
+
+       reply = dbus_message_new_method_return(message);
+       if (!reply) {
+               reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+                                              NULL);
+               goto out;
+       }
+
+       dbus_message_iter_init_append(reply, &iter);
+
+       if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32,
+                                                 &(si.current_signal))) {
+               dbus_message_unref(reply);
+               reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+                                              NULL);
+               goto out;
+       }
+
+out:
+       return reply;
+}
+#endif
+
+/*
+ * wpas_dbus_handler_flush_bss - Flush the BSS cache
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL
+ *
+ * Handler function for "FlushBSS" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
+                                         struct wpa_supplicant *wpa_s)
+{
+       dbus_uint32_t age;
+
+       dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &age,
+                             DBUS_TYPE_INVALID);
+
+       if (age == 0)
+               wpa_bss_flush(wpa_s);
+       else
+               wpa_bss_flush_by_age(wpa_s, age);
+
+       return NULL;
+}
+
+
+/**
+ * wpas_dbus_getter_capabilities - Return interface capabilities
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "Capabilities" property of an interface.
+ */
+dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
+                                         DBusError *error, void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
        struct wpa_driver_capa capa;
        int res;
-       DBusMessageIter iter, iter_dict;
-       DBusMessageIter iter_dict_entry, iter_dict_val, iter_array,
+       DBusMessageIter iter_dict, iter_dict_entry, iter_dict_val, iter_array,
                variant_iter;
        const char *scans[] = { "active", "passive", "ssid" };
-       const char *modes[] = { "infrastructure", "ad-hoc", "ap" };
-       int n = sizeof(modes) / sizeof(char *);
 
-       if (message == NULL)
-               reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-       else
-               reply = dbus_message_new_method_return(message);
-       if (!reply)
-               goto nomem;
-
-       dbus_message_iter_init_append(reply, &iter);
-       if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
-                                             "a{sv}", &variant_iter))
+       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))
@@ -1949,41 +2056,78 @@ DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message,
                goto nomem;
 
        /***** Modes */
-       if (res < 0 || !(capa.flags & WPA_DRIVER_FLAGS_AP))
-               n--; /* exclude ap mode if it is not supported by the driver */
-       if (!wpa_dbus_dict_append_string_array(&iter_dict, "Modes", modes, n))
+       if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
+                                             &iter_dict_entry,
+                                             &iter_dict_val,
+                                             &iter_array))
                goto nomem;
 
+       if (!wpa_dbus_dict_string_array_add_element(
+                           &iter_array, "infrastructure"))
+               goto nomem;
+
+       if (!wpa_dbus_dict_string_array_add_element(
+                           &iter_array, "ad-hoc"))
+               goto nomem;
+
+       if (res >= 0) {
+               if (capa.flags & (WPA_DRIVER_FLAGS_AP)) {
+                       if (!wpa_dbus_dict_string_array_add_element(
+                                   &iter_array, "ap"))
+                               goto nomem;
+               }
+
+               if (capa.flags & (WPA_DRIVER_FLAGS_P2P_CAPABLE)) {
+                       if (!wpa_dbus_dict_string_array_add_element(
+                                   &iter_array, "p2p"))
+                               goto nomem;
+               }
+       }
+
+       if (!wpa_dbus_dict_end_string_array(&iter_dict,
+                                           &iter_dict_entry,
+                                           &iter_dict_val,
+                                           &iter_array))
+               goto nomem;
+       /***** Modes end */
+
+       if (res >= 0) {
+               dbus_int32_t max_scan_ssid = capa.max_scan_ssids;
+
+               if (!wpa_dbus_dict_append_int32(&iter_dict, "MaxScanSSID",
+                                               max_scan_ssid))
+                       goto nomem;
+       }
+
        if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
                goto nomem;
-       if (!dbus_message_iter_close_container(&iter, &variant_iter))
+       if (!dbus_message_iter_close_container(iter, &variant_iter))
                goto nomem;
 
-       return reply;
+       return TRUE;
 
 nomem:
-       if (reply)
-               dbus_message_unref(reply);
-
-       return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+       return FALSE;
 }
 
 
 /**
  * wpas_dbus_getter_state - Get interface state
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a STRING representing the current
- *          interface state
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "State" property.
  */
-DBusMessage * wpas_dbus_getter_state(DBusMessage *message,
-                                    struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
+                                  void *user_data)
 {
-       DBusMessage *reply = NULL;
+       struct wpa_supplicant *wpa_s = user_data;
        const char *str_state;
        char *state_ls, *tmp;
+       dbus_bool_t success = FALSE;
 
        str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
 
@@ -1991,141 +2135,317 @@ DBusMessage * wpas_dbus_getter_state(DBusMessage *message,
         */
        state_ls = tmp = os_strdup(str_state);
        if (!tmp) {
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+               return FALSE;
        }
        while (*tmp) {
                *tmp = tolower(*tmp);
                tmp++;
        }
 
-       reply = wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-                                                &state_ls);
+       success = wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                                  &state_ls, error);
 
        os_free(state_ls);
 
-       return reply;
+       return success;
 }
 
 
 /**
  * wpas_dbus_new_iface_get_scanning - Get interface scanning state
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing whether the interface is scanning
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "scanning" property.
  */
-DBusMessage * wpas_dbus_getter_scanning(DBusMessage *message,
-                                       struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
+                                      void *user_data)
 {
+       struct wpa_supplicant *wpa_s = user_data;
        dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-                                               &scanning);
+
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+                                               &scanning, error);
 }
 
 
 /**
  * wpas_dbus_getter_ap_scan - Control roaming mode
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A message containong value of ap_scan variable
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter function for "ApScan" property.
  */
-DBusMessage * wpas_dbus_getter_ap_scan(DBusMessage *message,
-                                      struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data)
 {
+       struct wpa_supplicant *wpa_s = user_data;
        dbus_uint32_t ap_scan = wpa_s->conf->ap_scan;
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_UINT32,
-                                               &ap_scan);
+
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+                                               &ap_scan, error);
 }
 
 
 /**
  * wpas_dbus_setter_ap_scan - Control roaming mode
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: NULL
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Setter function for "ApScan" property.
  */
-DBusMessage * wpas_dbus_setter_ap_scan(DBusMessage *message,
-                                      struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data)
 {
-       DBusMessage *reply = NULL;
+       struct wpa_supplicant *wpa_s = user_data;
        dbus_uint32_t ap_scan;
 
-       reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_UINT32,
-                                                &ap_scan);
-       if (reply)
-               return reply;
+       if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
+                                             &ap_scan))
+               return FALSE;
 
        if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
-               return wpas_dbus_error_invalid_args(
-                       message, "ap_scan must equal 0, 1 or 2");
+               dbus_set_error_const(error, DBUS_ERROR_FAILED,
+                                    "ap_scan must be 0, 1, or 2");
+               return FALSE;
        }
-       return NULL;
+       return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter function for "BSSExpireAge" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
+                                           DBusError *error,
+                                           void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age;
+
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+                                               &expire_age, error);
+}
+
+
+/**
+ * wpas_dbus_setter_bss_expire_age - Control BSS entry expiration age
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter function for "BSSExpireAge" property.
+ */
+dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter,
+                                           DBusError *error,
+                                           void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       dbus_uint32_t expire_age;
+
+       if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
+                                             &expire_age))
+               return FALSE;
+
+       if (wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age)) {
+               dbus_set_error_const(error, DBUS_ERROR_FAILED,
+                                    "BSSExpireAge must be >= 10");
+               return FALSE;
+       }
+       return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_bss_expire_count - Get BSS entry expiration scan count
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter function for "BSSExpireCount" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
+                                             DBusError *error,
+                                             void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_age;
+
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+                                               &expire_count, error);
+}
+
+
+/**
+ * wpas_dbus_setter_bss_expire_count - Control BSS entry expiration scan count
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter function for "BSSExpireCount" property.
+ */
+dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter,
+                                             DBusError *error,
+                                             void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       dbus_uint32_t expire_count;
+
+       if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
+                                             &expire_count))
+               return FALSE;
+
+       if (wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count)) {
+               dbus_set_error_const(error, DBUS_ERROR_FAILED,
+                                    "BSSExpireCount must be > 0");
+               return FALSE;
+       }
+       return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_country - Control country code
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter function for "Country" property.
+ */
+dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       char country[3];
+       char *str = country;
+
+       country[0] = wpa_s->conf->country[0];
+       country[1] = wpa_s->conf->country[1];
+       country[2] = '\0';
+
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                               &str, error);
+}
+
+
+/**
+ * wpas_dbus_setter_country - Control country code
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter function for "Country" property.
+ */
+dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       const char *country;
+
+       if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+                                             &country))
+               return FALSE;
+
+       if (!country[0] || !country[1]) {
+               dbus_set_error_const(error, DBUS_ERROR_FAILED,
+                                    "invalid country code");
+               return FALSE;
+       }
+
+       if (wpa_s->drv_priv != NULL && wpa_drv_set_country(wpa_s, country)) {
+               wpa_printf(MSG_DEBUG, "Failed to set country");
+               dbus_set_error_const(error, DBUS_ERROR_FAILED,
+                                    "failed to set country code");
+               return FALSE;
+       }
+
+       wpa_s->conf->country[0] = country[0];
+       wpa_s->conf->country[1] = country[1];
+       return TRUE;
 }
 
 
 /**
  * wpas_dbus_getter_ifname - Get interface name
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a name of network interface
- * associated with with wpa_s
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Ifname" property.
  */
-DBusMessage * wpas_dbus_getter_ifname(DBusMessage *message,
-                                     struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
+                                   void *user_data)
 {
+       struct wpa_supplicant *wpa_s = user_data;
        const char *ifname = wpa_s->ifname;
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-                                               &ifname);
+
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                               &ifname, error);
 }
 
 
 /**
  * wpas_dbus_getter_driver - Get interface name
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a name of network interface
- * driver associated with with wpa_s
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Driver" property.
  */
-DBusMessage * wpas_dbus_getter_driver(DBusMessage *message,
-                                     struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
+                                   void *user_data)
 {
+       struct wpa_supplicant *wpa_s = user_data;
        const char *driver;
 
        if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
                wpa_printf(MSG_DEBUG, "wpas_dbus_getter_driver[dbus]: "
                           "wpa_s has no driver set");
-               return wpas_dbus_error_unknown_error(message, NULL);
+               dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set",
+                              __func__);
+               return FALSE;
        }
 
        driver = wpa_s->driver->name;
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-                                               &driver);
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                               &driver, error);
 }
 
 
 /**
  * wpas_dbus_getter_current_bss - Get current bss object path
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a DBus object path to
- * current BSS
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "CurrentBSS" property.
  */
-DBusMessage * wpas_dbus_getter_current_bss(DBusMessage *message,
-                                          struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
+                                        DBusError *error,
+                                        void *user_data)
 {
-       DBusMessage *reply;
+       struct wpa_supplicant *wpa_s = user_data;
        char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf;
 
        if (wpa_s->current_bss)
@@ -2135,27 +2455,25 @@ DBusMessage * wpas_dbus_getter_current_bss(DBusMessage *message,
        else
                os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
 
-       reply = wpas_dbus_simple_property_getter(message,
-                                                DBUS_TYPE_OBJECT_PATH,
-                                                &bss_obj_path);
-
-       return reply;
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
+                                               &bss_obj_path, error);
 }
 
 
 /**
  * wpas_dbus_getter_current_network - Get current network object path
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a DBus object path to
- * current network
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "CurrentNetwork" property.
  */
-DBusMessage * wpas_dbus_getter_current_network(DBusMessage *message,
-                                              struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
+                                            DBusError *error,
+                                            void *user_data)
 {
-       DBusMessage *reply;
+       struct wpa_supplicant *wpa_s = user_data;
        char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf;
 
        if (wpa_s->current_ssid)
@@ -2165,70 +2483,98 @@ DBusMessage * wpas_dbus_getter_current_network(DBusMessage *message,
        else
                os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
 
-       reply = wpas_dbus_simple_property_getter(message,
-                                                DBUS_TYPE_OBJECT_PATH,
-                                                &net_obj_path);
-
-       return reply;
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
+                                               &net_obj_path, error);
 }
 
 
 /**
- * wpas_dbus_getter_bridge_ifname - Get interface name
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a name of bridge network
- * interface associated with with wpa_s
+ * wpas_dbus_getter_current_auth_mode - Get current authentication type
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
- * Getter for "BridgeIfname" property.
+ * Getter for "CurrentAuthMode" property.
  */
-DBusMessage * wpas_dbus_getter_bridge_ifname(DBusMessage *message,
-                                            struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
+                                              DBusError *error,
+                                              void *user_data)
 {
-       const char *bridge_ifname = NULL;
+       struct wpa_supplicant *wpa_s = user_data;
+       const char *eap_mode;
+       const char *auth_mode;
+       char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX];
+
+       if (wpa_s->wpa_state != WPA_COMPLETED) {
+               auth_mode = "INACTIVE";
+       } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
+           wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+               eap_mode = wpa_supplicant_get_eap_mode(wpa_s);
+               os_snprintf(eap_mode_buf, WPAS_DBUS_AUTH_MODE_MAX,
+                           "EAP-%s", eap_mode);
+               auth_mode = eap_mode_buf;
 
-       bridge_ifname = wpa_s->bridge_ifname;
-       if (bridge_ifname == NULL) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bridge_ifname[dbus]: "
-                          "wpa_s has no bridge interface name set");
-               return wpas_dbus_error_unknown_error(message, NULL);
+       } else {
+               auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt,
+                                            wpa_s->current_ssid->proto);
        }
 
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-                                               &bridge_ifname);
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                               &auth_mode, error);
+}
+
+
+/**
+ * wpas_dbus_getter_bridge_ifname - Get interface name
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "BridgeIfname" property.
+ */
+dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
+                                          DBusError *error,
+                                          void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       const char *bridge_ifname = wpa_s->bridge_ifname;
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                               &bridge_ifname, error);
 }
 
 
 /**
  * wpas_dbus_getter_bsss - Get array of BSSs objects
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: a dbus message containing an array of all known BSS objects
- * dbus paths
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "BSSs" property.
  */
-DBusMessage * wpas_dbus_getter_bsss(DBusMessage *message,
-                                   struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
+                                 void *user_data)
 {
-       DBusMessage *reply = NULL;
+       struct wpa_supplicant *wpa_s = user_data;
        struct wpa_bss *bss;
        char **paths;
        unsigned int i = 0;
+       dbus_bool_t success = FALSE;
 
        paths = os_zalloc(wpa_s->num_bss * sizeof(char *));
        if (!paths) {
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+               return FALSE;
        }
 
        /* Loop through scan results and append each result's object path */
        dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
                paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
                if (paths[i] == NULL) {
-                       reply = dbus_message_new_error(message,
-                                                      DBUS_ERROR_NO_MEMORY,
-                                                      NULL);
+                       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+                                            "no memory");
                        goto out;
                }
                /* Construct the object path for this BSS. */
@@ -2237,57 +2583,62 @@ DBusMessage * wpas_dbus_getter_bsss(DBusMessage *message,
                            wpa_s->dbus_new_path, bss->id);
        }
 
-       reply = wpas_dbus_simple_array_property_getter(message,
-                                                      DBUS_TYPE_OBJECT_PATH,
-                                                      paths, wpa_s->num_bss);
+       success = wpas_dbus_simple_array_property_getter(iter,
+                                                        DBUS_TYPE_OBJECT_PATH,
+                                                        paths, wpa_s->num_bss,
+                                                        error);
 
 out:
        while (i)
                os_free(paths[--i]);
        os_free(paths);
-       return reply;
+       return success;
 }
 
 
 /**
  * wpas_dbus_getter_networks - Get array of networks objects
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: a dbus message containing an array of all configured
- * networks dbus object paths.
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Networks" property.
  */
-DBusMessage * wpas_dbus_getter_networks(DBusMessage *message,
-                                       struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
+                                     void *user_data)
 {
-       DBusMessage *reply = NULL;
+       struct wpa_supplicant *wpa_s = user_data;
        struct wpa_ssid *ssid;
        char **paths;
        unsigned int i = 0, num = 0;
+       dbus_bool_t success = FALSE;
 
        if (wpa_s->conf == NULL) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_networks[dbus]: "
-                          "An error occurred getting networks list.");
-               return wpas_dbus_error_unknown_error(message, NULL);
+               wpa_printf(MSG_ERROR, "%s[dbus]: An error occurred getting "
+                          "networks list.", __func__);
+               dbus_set_error(error, DBUS_ERROR_FAILED, "%s: an error "
+                              "occurred getting the networks list", __func__);
+               return FALSE;
        }
 
        for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
-               num++;
+               if (!network_is_persistent_group(ssid))
+                       num++;
 
        paths = os_zalloc(num * sizeof(char *));
        if (!paths) {
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+               dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
+               return FALSE;
        }
 
        /* Loop through configured networks and append object path of each */
        for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+               if (network_is_persistent_group(ssid))
+                       continue;
                paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
                if (paths[i] == NULL) {
-                       reply = dbus_message_new_error(message,
-                                                      DBUS_ERROR_NO_MEMORY,
-                                                      NULL);
+                       dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
                        goto out;
                }
 
@@ -2297,50 +2648,40 @@ DBusMessage * wpas_dbus_getter_networks(DBusMessage *message,
                            wpa_s->dbus_new_path, ssid->id);
        }
 
-       reply = wpas_dbus_simple_array_property_getter(message,
-                                                      DBUS_TYPE_OBJECT_PATH,
-                                                      paths, num);
+       success = wpas_dbus_simple_array_property_getter(iter,
+                                                        DBUS_TYPE_OBJECT_PATH,
+                                                        paths, num, error);
 
 out:
        while (i)
                os_free(paths[--i]);
        os_free(paths);
-       return reply;
+       return success;
 }
 
 
 /**
  * wpas_dbus_getter_blobs - Get all blobs defined for this interface
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: a dbus message containing a dictionary of pairs (blob_name, blob)
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Blobs" property.
  */
-DBusMessage * wpas_dbus_getter_blobs(DBusMessage *message,
-                                    struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
+                                  void *user_data)
 {
-       DBusMessage *reply = NULL;
-       DBusMessageIter iter, variant_iter, dict_iter, entry_iter, array_iter;
+       struct wpa_supplicant *wpa_s = user_data;
+       DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
        struct wpa_config_blob *blob;
 
-       if (message == NULL)
-               reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-       else
-               reply = dbus_message_new_method_return(message);
-       if (!reply)
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+       if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
                                              "a{say}", &variant_iter) ||
            !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
                                              "{say}", &dict_iter)) {
-               dbus_message_unref(reply);
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+               return FALSE;
        }
 
        blob = wpa_s->conf->blobs;
@@ -2363,176 +2704,192 @@ DBusMessage * wpas_dbus_getter_blobs(DBusMessage *message,
                                                       &array_iter) ||
                    !dbus_message_iter_close_container(&dict_iter,
                                                       &entry_iter)) {
-                       dbus_message_unref(reply);
-                       return dbus_message_new_error(message,
-                                                     DBUS_ERROR_NO_MEMORY,
-                                                     NULL);
+                       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+                                            "no memory");
+                       return FALSE;
                }
 
                blob = blob->next;
        }
 
        if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
-           !dbus_message_iter_close_container(&iter, &variant_iter)) {
-               dbus_message_unref(reply);
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+           !dbus_message_iter_close_container(iter, &variant_iter)) {
+               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+               return FALSE;
        }
 
-       return reply;
+       return TRUE;
+}
+
+
+static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
+                                      DBusError *error, const char *func_name)
+{
+       struct wpa_bss *res = wpa_bss_get_id(args->wpa_s, args->id);
+
+       if (!res) {
+               wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found",
+                          func_name, args->id);
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: BSS %d not found",
+                              func_name, args->id);
+       }
+
+       return res;
 }
 
 
 /**
  * wpas_dbus_getter_bss_bssid - Return the BSSID of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the bssid for the requested bss
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "BSSID" property.
  */
-DBusMessage * wpas_dbus_getter_bss_bssid(DBusMessage *message,
-                                        struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
+                                      void *user_data)
 {
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_bssid[dbus]: no "
-                          "bss with id %d found", bss->id);
-               return NULL;
-       }
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
 
-       return wpas_dbus_simple_array_property_getter(message, DBUS_TYPE_BYTE,
-                                                     res->bssid, ETH_ALEN);
+       return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+                                                     res->bssid, ETH_ALEN,
+                                                     error);
 }
 
 
 /**
  * wpas_dbus_getter_bss_ssid - Return the SSID of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the ssid for the requested bss
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "SSID" property.
  */
-DBusMessage * wpas_dbus_getter_bss_ssid(DBusMessage *message,
-                                             struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
+                                     void *user_data)
 {
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_ssid[dbus]: no "
-                          "bss with id %d found", bss->id);
-               return NULL;
-       }
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
 
-       return wpas_dbus_simple_array_property_getter(message, DBUS_TYPE_BYTE,
-                                                     res->ssid,
-                                                     res->ssid_len);
+       return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+                                                     res->ssid, res->ssid_len,
+                                                     error);
 }
 
 
 /**
  * wpas_dbus_getter_bss_privacy - Return the privacy flag of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the privacy flag value of requested bss
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Privacy" property.
  */
-DBusMessage * wpas_dbus_getter_bss_privacy(DBusMessage *message,
-                                          struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
+                                        DBusError *error, void *user_data)
 {
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
        dbus_bool_t privacy;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_privacy[dbus]: no "
-                          "bss with id %d found", bss->id);
-               return NULL;
-       }
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
 
        privacy = (res->caps & IEEE80211_CAP_PRIVACY) ? TRUE : FALSE;
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-                                               &privacy);
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+                                               &privacy, error);
 }
 
 
 /**
  * wpas_dbus_getter_bss_mode - Return the mode of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the mode of requested bss
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Mode" property.
  */
-DBusMessage * wpas_dbus_getter_bss_mode(DBusMessage *message,
-                                       struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
+                                     void *user_data)
 {
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
        const char *mode;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_mode[dbus]: no "
-                          "bss with id %d found", bss->id);
-               return NULL;
-       }
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
 
        if (res->caps & IEEE80211_CAP_IBSS)
                mode = "ad-hoc";
        else
                mode = "infrastructure";
 
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-                                               &mode);
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                               &mode, error);
 }
 
 
 /**
  * wpas_dbus_getter_bss_level - Return the signal strength of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the signal strength of requested bss
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Level" property.
  */
-DBusMessage * wpas_dbus_getter_bss_signal(DBusMessage *message,
-                                         struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
+                                       DBusError *error, void *user_data)
 {
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_signal[dbus]: no "
-                          "bss with id %d found", bss->id);
-               return NULL;
-       }
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
 
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_INT16,
-                                               &res->level);
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT16,
+                                               &res->level, error);
 }
 
 
 /**
  * wpas_dbus_getter_bss_frequency - Return the frequency of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the frequency of requested bss
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Frequency" property.
  */
-DBusMessage * wpas_dbus_getter_bss_frequency(DBusMessage *message,
-                                            struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter,
+                                          DBusError *error, void *user_data)
 {
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_frequency[dbus]: "
-                          "no bss with id %d found", bss->id);
-               return NULL;
-       }
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
 
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_UINT16,
-                                               &res->freq);
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
+                                               &res->freq, error);
 }
 
 
@@ -2544,72 +2901,64 @@ static int cmp_u8s_desc(const void *a, const void *b)
 
 /**
  * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing sorted array of bit rates
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Rates" property.
  */
-DBusMessage * wpas_dbus_getter_bss_rates(DBusMessage *message,
-                                           struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
+                                      DBusError *error, void *user_data)
 {
-       DBusMessage *reply;
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
        u8 *ie_rates = NULL;
        u32 *real_rates;
        int rates_num, i;
+       dbus_bool_t success = FALSE;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_rates[dbus]: "
-                          "no bss with id %d found", bss->id);
-               return NULL;
-       }
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
 
        rates_num = wpa_bss_get_bit_rates(res, &ie_rates);
        if (rates_num < 0)
-               return NULL;
+               return FALSE;
 
        qsort(ie_rates, rates_num, 1, cmp_u8s_desc);
 
        real_rates = os_malloc(sizeof(u32) * rates_num);
        if (!real_rates) {
                os_free(ie_rates);
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+               return FALSE;
        }
 
        for (i = 0; i < rates_num; i++)
                real_rates[i] = ie_rates[i] * 500000;
 
-       reply = wpas_dbus_simple_array_property_getter(message,
-                                                      DBUS_TYPE_UINT32,
-                                                      real_rates, rates_num);
+       success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_UINT32,
+                                                        real_rates, rates_num,
+                                                        error);
 
        os_free(ie_rates);
        os_free(real_rates);
-       return reply;
+       return success;
 }
 
 
-static DBusMessage * wpas_dbus_get_bss_security_prop(
-       DBusMessage *message, struct wpa_ie_data *ie_data)
+static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
+                                                  struct wpa_ie_data *ie_data,
+                                                  DBusError *error)
 {
-       DBusMessage *reply;
-       DBusMessageIter iter, iter_dict, variant_iter;
+       DBusMessageIter iter_dict, variant_iter;
        const char *group;
        const char *pairwise[2]; /* max 2 pairwise ciphers is supported */
        const char *key_mgmt[7]; /* max 7 key managements may be supported */
        int n;
 
-       if (message == NULL)
-               reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-       else
-               reply = dbus_message_new_method_return(message);
-       if (!reply)
-               goto nomem;
-
-       dbus_message_iter_init_append(reply, &iter);
-       if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+       if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
                                              "a{sv}", &variant_iter))
                goto nomem;
 
@@ -2690,152 +3039,152 @@ static DBusMessage * wpas_dbus_get_bss_security_prop(
 
        if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
                goto nomem;
-       if (!dbus_message_iter_close_container(&iter, &variant_iter))
+       if (!dbus_message_iter_close_container(iter, &variant_iter))
                goto nomem;
 
-       return reply;
+       return TRUE;
 
 nomem:
-       if (reply)
-               dbus_message_unref(reply);
-
-       return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+       return FALSE;
 }
 
 
 /**
  * wpas_dbus_getter_bss_wpa - Return the WPA options of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the WPA options of requested bss
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "WPA" property.
  */
-DBusMessage * wpas_dbus_getter_bss_wpa(DBusMessage *message,
-                                      struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data)
 {
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
        struct wpa_ie_data wpa_data;
        const u8 *ie;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_wpa[dbus]: no "
-                          "bss with id %d found", bss->id);
-               return NULL;
-       }
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
 
        os_memset(&wpa_data, 0, sizeof(wpa_data));
        ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
        if (ie) {
-               if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0)
-                       return wpas_dbus_error_unknown_error(message,
-                                                            "invalid WPA IE");
+               if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
+                       dbus_set_error_const(error, DBUS_ERROR_FAILED,
+                                            "failed to parse WPA IE");
+                       return FALSE;
+               }
        }
 
-       return wpas_dbus_get_bss_security_prop(message, &wpa_data);
+       return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
 }
 
 
 /**
  * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the RSN options of requested bss
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "RSN" property.
  */
-DBusMessage * wpas_dbus_getter_bss_rsn(DBusMessage *message,
-                                      struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data)
 {
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
        struct wpa_ie_data wpa_data;
        const u8 *ie;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_rsn[dbus]: no "
-                          "bss with id %d found", bss->id);
-               return NULL;
-       }
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
 
        os_memset(&wpa_data, 0, sizeof(wpa_data));
        ie = wpa_bss_get_ie(res, WLAN_EID_RSN);
        if (ie) {
-               if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0)
-                       return wpas_dbus_error_unknown_error(message,
-                                                            "invalid RSN IE");
+               if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
+                       dbus_set_error_const(error, DBUS_ERROR_FAILED,
+                                            "failed to parse RSN IE");
+                       return FALSE;
+               }
        }
 
-       return wpas_dbus_get_bss_security_prop(message, &wpa_data);
+       return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
 }
 
 
 /**
  * wpas_dbus_getter_bss_ies - Return all IEs of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing IEs byte array
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "IEs" property.
  */
-DBusMessage * wpas_dbus_getter_bss_ies(DBusMessage *message,
-                                      struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data)
 {
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_ies[dbus]: no "
-                          "bss with id %d found", bss->id);
-               return NULL;
-       }
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
 
-       return wpas_dbus_simple_array_property_getter(message, DBUS_TYPE_BYTE,
-                                                     res + 1, res->ie_len);
+       return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+                                                     res + 1, res->ie_len,
+                                                     error);
 }
 
 
 /**
  * wpas_dbus_getter_enabled - Check whether network is enabled or disabled
- * @message: Pointer to incoming dbus message
- * @wpas_dbus_setter_enabled: wpa_supplicant structure for a network interface
- * and wpa_ssid structure for a configured network
- * Returns: DBus message with boolean indicating state of configured network
- * or DBus error on failure
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "enabled" property of a configured network.
  */
-DBusMessage * wpas_dbus_getter_enabled(DBusMessage *message,
-                                      struct network_handler_args *net)
+dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data)
 {
+       struct network_handler_args *net = user_data;
        dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE;
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-                                               &enabled);
+
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+                                               &enabled, error);
 }
 
 
 /**
  * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled
- * @message: Pointer to incoming dbus message
- * @wpas_dbus_setter_enabled: wpa_supplicant structure for a network interface
- * and wpa_ssid structure for a configured network
- * Returns: NULL indicating success or DBus error on failure
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Setter for "Enabled" property of a configured network.
  */
-DBusMessage * wpas_dbus_setter_enabled(DBusMessage *message,
-                                      struct network_handler_args *net)
+dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data)
 {
-       DBusMessage *reply = NULL;
-
+       struct network_handler_args *net = user_data;
        struct wpa_supplicant *wpa_s;
        struct wpa_ssid *ssid;
-
        dbus_bool_t enable;
 
-       reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN,
-                                                &enable);
-
-       if (reply)
-               return reply;
+       if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
+                                             &enable))
+               return FALSE;
 
        wpa_s = net->wpa_s;
        ssid = net->ssid;
@@ -2845,48 +3194,38 @@ DBusMessage * wpas_dbus_setter_enabled(DBusMessage *message,
        else
                wpa_supplicant_disable_network(wpa_s, ssid);
 
-       return NULL;
+       return TRUE;
 }
 
 
 /**
  * wpas_dbus_getter_network_properties - Get options for a configured network
- * @message: Pointer to incoming dbus message
- * @net: wpa_supplicant structure for a network interface and
- * wpa_ssid structure for a configured network
- * Returns: DBus message with network properties or DBus error on failure
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Properties" property of a configured network.
  */
-DBusMessage * wpas_dbus_getter_network_properties(
-       DBusMessage *message, struct network_handler_args *net)
+dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter,
+                                               DBusError *error,
+                                               void *user_data)
 {
-       DBusMessage *reply = NULL;
-       DBusMessageIter iter, variant_iter, dict_iter;
+       struct network_handler_args *net = user_data;
+       DBusMessageIter variant_iter, dict_iter;
        char **iterator;
-       char **props = wpa_config_get_all(net->ssid, 0);
-       if (!props)
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+       char **props = wpa_config_get_all(net->ssid, 1);
+       dbus_bool_t success = FALSE;
 
-       if (message == NULL)
-               reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-       else
-               reply = dbus_message_new_method_return(message);
-       if (!reply) {
-               reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                              NULL);
-               goto out;
+       if (!props) {
+               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+               return FALSE;
        }
 
-       dbus_message_iter_init_append(reply, &iter);
-
-       if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
-                       "a{sv}", &variant_iter) ||
+       if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}",
+                                             &variant_iter) ||
            !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) {
-               dbus_message_unref(reply);
-               reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                              NULL);
+               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
                goto out;
        }
 
@@ -2894,10 +3233,8 @@ DBusMessage * wpas_dbus_getter_network_properties(
        while (*iterator) {
                if (!wpa_dbus_dict_append_string(&dict_iter, *iterator,
                                                 *(iterator + 1))) {
-                       dbus_message_unref(reply);
-                       reply = dbus_message_new_error(message,
-                                                      DBUS_ERROR_NO_MEMORY,
-                                                      NULL);
+                       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+                                            "no memory");
                        goto out;
                }
                iterator += 2;
@@ -2905,13 +3242,13 @@ DBusMessage * wpas_dbus_getter_network_properties(
 
 
        if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
-           !dbus_message_iter_close_container(&iter, &variant_iter)) {
-               dbus_message_unref(reply);
-               reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                              NULL);
+           !dbus_message_iter_close_container(iter, &variant_iter)) {
+               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
                goto out;
        }
 
+       success = TRUE;
+
 out:
        iterator = props;
        while (*iterator) {
@@ -2919,39 +3256,27 @@ out:
                iterator++;
        }
        os_free(props);
-       return reply;
+       return success;
 }
 
 
 /**
  * wpas_dbus_setter_network_properties - Set options for a configured network
- * @message: Pointer to incoming dbus message
- * @net: wpa_supplicant structure for a network interface and
- * wpa_ssid structure for a configured network
- * Returns: NULL indicating success or DBus error on failure
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Setter for "Properties" property of a configured network.
  */
-DBusMessage * wpas_dbus_setter_network_properties(
-       DBusMessage *message, struct network_handler_args *net)
+dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
+                                               DBusError *error,
+                                               void *user_data)
 {
+       struct network_handler_args *net = user_data;
        struct wpa_ssid *ssid = net->ssid;
+       DBusMessageIter variant_iter;
 
-       DBusMessage *reply = NULL;
-       DBusMessageIter iter, variant_iter;
-
-       dbus_message_iter_init(message, &iter);
-
-       dbus_message_iter_next(&iter);
-       dbus_message_iter_next(&iter);
-
-       dbus_message_iter_recurse(&iter, &variant_iter);
-
-       reply = set_network_properties(message, net->wpa_s, ssid,
-                                      &variant_iter);
-       if (reply)
-               wpa_printf(MSG_DEBUG, "dbus control interface couldn't set "
-                          "network properties");
-
-       return reply;
+       dbus_message_iter_recurse(iter, &variant_iter);
+       return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
 }
index 3cdf9cb..eb72abd 100644 (file)
@@ -26,17 +26,20 @@ struct bss_handler_args {
        unsigned int id;
 };
 
-DBusMessage * wpas_dbus_simple_property_getter(DBusMessage *message,
-                                              const int type,
-                                              const void *val);
+dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
+                                            const int type,
+                                            const void *val,
+                                            DBusError *error);
 
-DBusMessage * wpas_dbus_simple_property_setter(DBusMessage *message,
-                                              const int type, void *val);
+dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter,
+                                            DBusError *error,
+                                            const int type, void *val);
 
-DBusMessage * wpas_dbus_simple_array_property_getter(DBusMessage *message,
-                                                    const int type,
-                                                    const void *array,
-                                                    size_t array_len);
+dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
+                                                  const int type,
+                                                  const void *array,
+                                                  size_t array_len,
+                                                  DBusError *error);
 
 DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
                                                 struct wpa_global *global);
@@ -47,29 +50,35 @@ DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
 DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
                                              struct wpa_global *global);
 
-DBusMessage * wpas_dbus_getter_debug_level(DBusMessage *message,
-                                          struct wpa_global *global);
+dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
+                                        DBusError *error,
+                                        void *user_data);
 
-DBusMessage * wpas_dbus_getter_debug_timestamp(DBusMessage *message,
-                                              struct wpa_global *global);
+dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
+                                             DBusError *error,
+                                             void *user_data);
 
-DBusMessage * wpas_dbus_getter_debug_show_keys(DBusMessage *message,
-                                              struct wpa_global *global);
+dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
+                                            DBusError *error,
+                                            void *user_data);
 
-DBusMessage * wpas_dbus_setter_debug_level(DBusMessage *message,
-                                          struct wpa_global *global);
+dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
+                                        DBusError *error, void *user_data);
 
-DBusMessage * wpas_dbus_setter_debug_timestamp(DBusMessage *message,
-                                              struct wpa_global *global);
+dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
+                                            DBusError *error,
+                                            void *user_data);
 
-DBusMessage * wpas_dbus_setter_debug_show_keys(DBusMessage *message,
-                                              struct wpa_global *global);
+dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
+                                            DBusError *error,
+                                            void *user_data);
 
-DBusMessage * wpas_dbus_getter_interfaces(DBusMessage *message,
-                                         struct wpa_global *global);
+dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
+                                       DBusError *error,
+                                       void *user_data);
 
-DBusMessage * wpas_dbus_getter_eap_methods(DBusMessage *message,
-                                          void *nothing);
+dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
+                                        DBusError *error, void *user_data);
 
 DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
                                     struct wpa_supplicant *wpa_s);
@@ -77,15 +86,26 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
 DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
                                           struct wpa_supplicant *wpa_s);
 
+dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
+                                  struct wpa_ssid *ssid,
+                                  DBusMessageIter *iter,
+                                  DBusError *error);
+
 DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
                                            struct wpa_supplicant *wpa_s);
 
 DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
                                               struct wpa_supplicant *wpa_s);
 
+DBusMessage * wpas_dbus_handler_remove_all_networks(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
 DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
                                               struct wpa_supplicant *wpa_s);
 
+DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
+                                             struct wpa_supplicant *wpa_s);
+
 DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
                                         struct wpa_supplicant *wpa_s);
 
@@ -95,98 +115,139 @@ DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
 DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
                                            struct wpa_supplicant *wpa_s);
 
-DBusMessage * wpas_dbus_getter_capabilities(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.
+ */
+#if defined TIZEN_EXT
+DBusMessage * wpas_dbus_handler_get_link_signal(DBusMessage *message,
                                            struct wpa_supplicant *wpa_s);
+#endif
 
-DBusMessage * wpas_dbus_getter_state(DBusMessage *message,
-                                    struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
+                                         struct wpa_supplicant *wpa_s);
 
-DBusMessage * wpas_dbus_getter_scanning(DBusMessage *message,
-                                       struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
+                                         DBusError *error, void *user_data);
 
-DBusMessage * wpas_dbus_getter_ap_scan(DBusMessage *message,
-                                      struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
+                                  void *user_data);
 
-DBusMessage * wpas_dbus_setter_ap_scan(DBusMessage *message,
-                                      struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
+                                     void *user_data);
 
-DBusMessage * wpas_dbus_getter_ifname(DBusMessage *message,
-                                     struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data);
 
-DBusMessage * wpas_dbus_getter_driver(DBusMessage *message,
-                                     struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data);
 
-DBusMessage * wpas_dbus_getter_bridge_ifname(DBusMessage *message,
-                                            struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
+                                           DBusError *error, void *user_data);
 
-DBusMessage * wpas_dbus_getter_current_bss(DBusMessage *message,
-                                          struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter,
+                                           DBusError *error,
+                                           void *user_data);
 
-DBusMessage * wpas_dbus_getter_current_network(DBusMessage *message,
-                                              struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
+                                             DBusError *error,
+                                             void *user_data);
+
+dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter,
+                                             DBusError *error,
+                                             void *user_data);
+
+dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data);
 
-DBusMessage * wpas_dbus_getter_bsss(DBusMessage *message,
-                                   struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data);
 
-DBusMessage * wpas_dbus_getter_networks(DBusMessage *message,
-                                       struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
+                                   void *user_data);
 
-DBusMessage * wpas_dbus_getter_blobs(DBusMessage *message,
-                                    struct wpa_supplicant *bss);
+dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
+                                   void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_bssid(DBusMessage *message,
-                                        struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
+                                          DBusError *error,
+                                          void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_ssid(DBusMessage *message,
-                                       struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
+                                        DBusError *error,
+                                        void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_privacy(DBusMessage *message,
-                                          struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
+                                            DBusError *error,
+                                            void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_mode(DBusMessage *message,
-                                       struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
+                                              DBusError *error,
+                                              void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_signal(DBusMessage *message,
-                                         struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
+                                 void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_frequency(DBusMessage *message,
-                                            struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
+                                     void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_rates(DBusMessage *message,
-                                        struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
+                                  void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_wpa(DBusMessage *message,
-                                      struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
+                                      void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_rsn(DBusMessage *message,
-                                      struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
+                                     void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_ies(DBusMessage *message,
-                                      struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
+                                        DBusError *error, void *user_data);
 
-DBusMessage * wpas_dbus_getter_enabled(DBusMessage *message,
-                                      struct network_handler_args *net);
+dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
+                                     void *user_data);
 
-DBusMessage * wpas_dbus_setter_enabled(DBusMessage *message,
-                                      struct network_handler_args *net);
+dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
+                                       DBusError *error, void *user_data);
 
-DBusMessage * wpas_dbus_getter_network_properties(
-       DBusMessage *message, struct network_handler_args *net);
+dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter,
+                                          DBusError *error, void *user_data);
 
-DBusMessage * wpas_dbus_setter_network_properties(
-       DBusMessage *message, struct network_handler_args *net);
+dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
+                                      DBusError *error, void *user_data);
+
+dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data);
+
+dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data);
+
+dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data);
+
+dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data);
+
+dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data);
+
+dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter,
+                                               DBusError *error,
+                                               void *user_data);
+
+dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
+                                               DBusError *error,
+                                               void *user_data);
 
 DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
                                          struct wpa_supplicant *wpa_s);
 
-DBusMessage * wpas_dbus_getter_process_credentials(
-       DBusMessage *message, struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter,
+       DBusError *error, void *user_data);
 
-DBusMessage * wpas_dbus_setter_process_credentials(
-       DBusMessage *message, struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_getter_credentials(DBusMessage *message,
-                                          struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter,
+                                                DBusError *error,
+                                                void *user_data);
 
 DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
                                           const char *arg);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
new file mode 100644 (file)
index 0000000..de0caad
--- /dev/null
@@ -0,0 +1,2158 @@
+/*
+ * WPA Supplicant / dbus-based control interface (P2P)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by 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 "utils/includes.h"
+#include "common.h"
+#include "../config.h"
+#include "../wpa_supplicant_i.h"
+#include "../wps_supplicant.h"
+#include "../notify.h"
+#include "dbus_new_helpers.h"
+#include "dbus_new.h"
+#include "dbus_new_handlers.h"
+#include "dbus_new_handlers_p2p.h"
+#include "dbus_dict_helpers.h"
+#include "p2p/p2p.h"
+#include "common/ieee802_11_defs.h"
+#include "ap/hostapd.h"
+#include "ap/ap_config.h"
+#include "ap/wps_hostapd.h"
+
+#include "../p2p_supplicant.h"
+
+/**
+ * Parses out the mac address from the peer object path.
+ * @peer_path - object path of the form
+ *     /fi/w1/wpa_supplicant1/Interfaces/n/Peers/00112233445566 (no colons)
+ * @addr - out param must be of ETH_ALEN size
+ * Returns 0 if valid (including MAC), -1 otherwise
+ */
+static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN])
+{
+       char *p;
+
+       if (!peer_path)
+               return -1;
+       p = strrchr(peer_path, '/');
+       if (!p)
+               return -1;
+       p++;
+       return hwaddr_compact_aton(p, addr);
+}
+
+
+/**
+ * wpas_dbus_error_persistent_group_unknown - Return a new PersistentGroupUnknown
+ * error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return an invalid persistent group error.
+ */
+static DBusMessage * wpas_dbus_error_persistent_group_unknown(
+       DBusMessage *message)
+{
+       return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
+                                     "There is no such persistent group in "
+                                     "this P2P device.");
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
+                                        struct wpa_supplicant *wpa_s)
+{
+       struct wpa_dbus_dict_entry entry;
+       DBusMessage *reply = NULL;
+       DBusMessageIter iter;
+       DBusMessageIter iter_dict;
+       unsigned int timeout = 0;
+       enum p2p_discovery_type type = P2P_FIND_ONLY_SOCIAL;
+       int num_req_dev_types = 0;
+       unsigned int i;
+       u8 *req_dev_types = NULL;
+
+       dbus_message_iter_init(message, &iter);
+       entry.key = NULL;
+
+       if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+               goto error;
+
+       while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+               if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+                       goto error;
+
+               if (!os_strcmp(entry.key, "Timeout") &&
+                   (entry.type == DBUS_TYPE_INT32)) {
+                       timeout = entry.uint32_value;
+               } else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) {
+                       if ((entry.type != DBUS_TYPE_ARRAY) ||
+                           (entry.array_type != WPAS_DBUS_TYPE_BINARRAY))
+                               goto error_clear;
+
+                       os_free(req_dev_types);
+                       req_dev_types =
+                               os_malloc(WPS_DEV_TYPE_LEN * entry.array_len);
+                       if (!req_dev_types)
+                               goto error_clear;
+
+                       for (i = 0; i < entry.array_len; i++) {
+                               if (wpabuf_len(entry.binarray_value[i]) !=
+                                                       WPS_DEV_TYPE_LEN)
+                                       goto error_clear;
+                               os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN,
+                                         wpabuf_head(entry.binarray_value[i]),
+                                         WPS_DEV_TYPE_LEN);
+                       }
+                       num_req_dev_types = entry.array_len;
+               } else if (!os_strcmp(entry.key, "DiscoveryType") &&
+                          (entry.type == DBUS_TYPE_STRING)) {
+                       if (!os_strcmp(entry.str_value, "start_with_full"))
+                               type = P2P_FIND_START_WITH_FULL;
+                       else if (!os_strcmp(entry.str_value, "social"))
+                               type = P2P_FIND_ONLY_SOCIAL;
+                       else if (!os_strcmp(entry.str_value, "progressive"))
+                               type = P2P_FIND_PROGRESSIVE;
+                       else
+                               goto error_clear;
+               } else
+                       goto error_clear;
+               wpa_dbus_dict_entry_clear(&entry);
+       }
+
+       wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types);
+       os_free(req_dev_types);
+       return reply;
+
+error_clear:
+       wpa_dbus_dict_entry_clear(&entry);
+error:
+       os_free(req_dev_types);
+       reply = wpas_dbus_error_invalid_args(message, entry.key);
+       return reply;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message,
+                                             struct wpa_supplicant *wpa_s)
+{
+       wpas_p2p_stop_find(wpa_s);
+       return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_rejectpeer(DBusMessage *message,
+                                              struct wpa_supplicant *wpa_s)
+{
+       DBusMessageIter iter;
+       char *peer_object_path = NULL;
+       u8 peer_addr[ETH_ALEN];
+
+       dbus_message_iter_init(message, &iter);
+       dbus_message_iter_get_basic(&iter, &peer_object_path);
+
+       if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
+               return wpas_dbus_error_invalid_args(message, NULL);
+
+       if (wpas_p2p_reject(wpa_s, peer_addr) < 0)
+               return wpas_dbus_error_unknown_error(message,
+                               "Failed to call wpas_p2p_reject method.");
+
+       return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_listen(DBusMessage *message,
+                                          struct wpa_supplicant *wpa_s)
+{
+       dbus_int32_t timeout = 0;
+
+       if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout,
+                                  DBUS_TYPE_INVALID))
+               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+                                             NULL);
+
+       if (wpas_p2p_listen(wpa_s, (unsigned int)timeout))
+               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+                                             NULL);
+
+       return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_extendedlisten(
+       DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+       unsigned int period = 0, interval = 0;
+       struct wpa_dbus_dict_entry entry;
+       DBusMessageIter iter;
+       DBusMessageIter iter_dict;
+
+       dbus_message_iter_init(message, &iter);
+       entry.key = NULL;
+
+       if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+               goto error;
+
+       while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+               if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+                       goto error;
+
+               if (!os_strcmp(entry.key, "period") &&
+                   (entry.type == DBUS_TYPE_INT32))
+                       period = entry.uint32_value;
+               else if (!os_strcmp(entry.key, "interval") &&
+                        (entry.type == DBUS_TYPE_INT32))
+                       interval = entry.uint32_value;
+               else
+                       goto error_clear;
+               wpa_dbus_dict_entry_clear(&entry);
+       }
+
+       if (wpas_p2p_ext_listen(wpa_s, period, interval))
+               return wpas_dbus_error_unknown_error(
+                       message, "failed to initiate a p2p_ext_listen.");
+
+       return NULL;
+
+error_clear:
+       wpa_dbus_dict_entry_clear(&entry);
+error:
+       return wpas_dbus_error_invalid_args(message, entry.key);
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_presence_request(
+       DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+       unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
+       struct wpa_dbus_dict_entry entry;
+       DBusMessageIter iter;
+       DBusMessageIter iter_dict;
+
+       dbus_message_iter_init(message, &iter);
+       entry.key = NULL;
+
+       if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+               goto error;
+
+       while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+               if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+                       goto error;
+
+               if (!os_strcmp(entry.key, "duration1") &&
+                   (entry.type == DBUS_TYPE_INT32))
+                       dur1 = entry.uint32_value;
+               else if (!os_strcmp(entry.key, "interval1") &&
+                        entry.type == DBUS_TYPE_INT32)
+                       int1 = entry.uint32_value;
+               else if (!os_strcmp(entry.key, "duration2") &&
+                        entry.type == DBUS_TYPE_INT32)
+                       dur2 = entry.uint32_value;
+               else if (!os_strcmp(entry.key, "interval2") &&
+                        entry.type == DBUS_TYPE_INT32)
+                       int2 = entry.uint32_value;
+               else
+                       goto error_clear;
+
+               wpa_dbus_dict_entry_clear(&entry);
+       }
+       if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0)
+               return wpas_dbus_error_unknown_error(message,
+                               "Failed to invoke presence request.");
+
+       return NULL;
+
+error_clear:
+       wpa_dbus_dict_entry_clear(&entry);
+error:
+       return wpas_dbus_error_invalid_args(message, entry.key);
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
+                                             struct wpa_supplicant *wpa_s)
+{
+       DBusMessageIter iter_dict;
+       DBusMessage *reply = NULL;
+       DBusMessageIter iter;
+       struct wpa_dbus_dict_entry entry;
+       char *pg_object_path = NULL;
+       int persistent_group = 0;
+       int freq = 0;
+       char *iface = NULL;
+       char *net_id_str = NULL;
+       unsigned int group_id = 0;
+       struct wpa_ssid *ssid;
+
+       dbus_message_iter_init(message, &iter);
+
+       if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+               goto inv_args;
+
+       while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+               if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+                       goto inv_args;
+
+               if (!os_strcmp(entry.key, "persistent") &&
+                   (entry.type == DBUS_TYPE_BOOLEAN)) {
+                       persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
+               } else if (!os_strcmp(entry.key, "frequency") &&
+                          (entry.type == DBUS_TYPE_INT32)) {
+                       freq = entry.int32_value;
+                       if (freq <= 0)
+                               goto inv_args_clear;
+               } else if (!os_strcmp(entry.key, "persistent_group_object") &&
+                          entry.type == DBUS_TYPE_OBJECT_PATH)
+                       pg_object_path = os_strdup(entry.str_value);
+               else
+                       goto inv_args_clear;
+
+               wpa_dbus_dict_entry_clear(&entry);
+       }
+
+       if (pg_object_path != NULL) {
+               /*
+                * A persistent group Object Path is defined meaning we want
+                * to re-invoke a persistent group.
+                */
+
+               iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
+                                                           &net_id_str, NULL);
+               if (iface == NULL ||
+                   os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+                       reply =
+                           wpas_dbus_error_invalid_args(message,
+                                                        pg_object_path);
+                       goto out;
+               }
+
+               group_id = strtoul(net_id_str, NULL, 10);
+               if (errno == EINVAL) {
+                       reply = wpas_dbus_error_invalid_args(
+                                               message, pg_object_path);
+                       goto out;
+               }
+
+               /* Get the SSID structure from the persistent group id */
+               ssid = wpa_config_get_network(wpa_s->conf, group_id);
+               if (ssid == NULL || ssid->disabled != 2)
+                       goto inv_args;
+
+               if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq)) {
+                       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))
+               goto inv_args;
+
+out:
+       os_free(pg_object_path);
+       os_free(net_id_str);
+       os_free(iface);
+       return reply;
+inv_args_clear:
+       wpa_dbus_dict_entry_clear(&entry);
+inv_args:
+       reply = wpas_dbus_error_invalid_args(message, NULL);
+       goto out;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_disconnect(DBusMessage *message,
+                                              struct wpa_supplicant *wpa_s)
+{
+       if (wpas_p2p_disconnect(wpa_s))
+               return wpas_dbus_error_unknown_error(message,
+                                               "failed to disconnect");
+
+       return NULL;
+}
+
+
+static dbus_bool_t wpa_dbus_p2p_check_enabled(struct wpa_supplicant *wpa_s,
+                                             DBusMessage *message,
+                                             DBusMessage **out_reply,
+                                             DBusError *error)
+{
+       /* Return an error message or an error if P2P isn't available */
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) {
+               if (out_reply) {
+                       *out_reply = dbus_message_new_error(
+                               message, DBUS_ERROR_FAILED,
+                               "P2P is not available for this interface");
+               }
+               dbus_set_error_const(error, DBUS_ERROR_FAILED,
+                                    "P2P is not available for this "
+                                    "interface");
+               return FALSE;
+       }
+       return TRUE;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_flush(DBusMessage *message,
+                                         struct wpa_supplicant *wpa_s)
+{
+       DBusMessage *reply = NULL;
+
+       if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
+               return reply;
+
+       os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+       wpa_s->force_long_sd = 0;
+       p2p_flush(wpa_s->global->p2p);
+
+       return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
+                                           struct wpa_supplicant *wpa_s)
+{
+       DBusMessageIter iter_dict;
+       DBusMessage *reply = NULL;
+       DBusMessageIter iter;
+       struct wpa_dbus_dict_entry entry;
+       char *peer_object_path = NULL;
+       int persistent_group = 0;
+       int join = 0;
+       int authorize_only = 0;
+       int go_intent = -1;
+       int freq = 0;
+       u8 addr[ETH_ALEN];
+       char *pin = NULL;
+       enum p2p_wps_method wps_method = WPS_NOT_READY;
+       int new_pin;
+       char *err_msg = NULL;
+       char *iface = NULL;
+
+       if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
+               return reply;
+
+       dbus_message_iter_init(message, &iter);
+
+       if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+               goto inv_args;
+
+       while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+               if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+                       goto inv_args;
+
+               if (!os_strcmp(entry.key, "peer") &&
+                   (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+                       peer_object_path = os_strdup(entry.str_value);
+               } else if (!os_strcmp(entry.key, "persistent") &&
+                          (entry.type == DBUS_TYPE_BOOLEAN)) {
+                       persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
+               } else if (!os_strcmp(entry.key, "join") &&
+                          (entry.type == DBUS_TYPE_BOOLEAN)) {
+                       join = (entry.bool_value == TRUE) ? 1 : 0;
+               } else if (!os_strcmp(entry.key, "authorize_only") &&
+                          (entry.type == DBUS_TYPE_BOOLEAN)) {
+                       authorize_only = (entry.bool_value == TRUE) ? 1 : 0;
+               } else if (!os_strcmp(entry.key, "frequency") &&
+                          (entry.type == DBUS_TYPE_INT32)) {
+                       freq = entry.int32_value;
+                       if (freq <= 0)
+                               goto inv_args_clear;
+               } else if (!os_strcmp(entry.key, "go_intent") &&
+                          (entry.type == DBUS_TYPE_INT32)) {
+                       go_intent = entry.int32_value;
+                       if ((go_intent < 0) || (go_intent > 15))
+                               goto inv_args_clear;
+               } else if (!os_strcmp(entry.key, "wps_method") &&
+                          (entry.type == DBUS_TYPE_STRING)) {
+                       if (!os_strcmp(entry.str_value, "pbc"))
+                               wps_method = WPS_PBC;
+                       else if (!os_strcmp(entry.str_value, "pin"))
+                               wps_method = WPS_PIN_DISPLAY;
+                       else if (!os_strcmp(entry.str_value, "display"))
+                               wps_method = WPS_PIN_DISPLAY;
+                       else if (!os_strcmp(entry.str_value, "keypad"))
+                               wps_method = WPS_PIN_KEYPAD;
+                       else
+                               goto inv_args_clear;
+               } else if (!os_strcmp(entry.key, "pin") &&
+                          (entry.type == DBUS_TYPE_STRING)) {
+                       pin = os_strdup(entry.str_value);
+               } else
+                       goto inv_args_clear;
+
+               wpa_dbus_dict_entry_clear(&entry);
+       }
+
+       if (!peer_object_path || (wps_method == WPS_NOT_READY) ||
+           (parse_peer_object_path(peer_object_path, addr) < 0) ||
+           (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
+               goto inv_args;
+
+       /*
+        * Validate the wps_method specified and the pin value.
+        */
+       if ((!pin || !pin[0]) && (wps_method == WPS_PIN_KEYPAD))
+               goto inv_args;
+
+       new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
+                                  persistent_group, join, authorize_only,
+                                  go_intent, freq);
+
+       if (new_pin >= 0) {
+               char npin[9];
+               char *generated_pin;
+               os_snprintf(npin, sizeof(npin), "%08d", new_pin);
+               generated_pin = npin;
+               reply = dbus_message_new_method_return(message);
+               dbus_message_append_args(reply, DBUS_TYPE_STRING,
+                                        &generated_pin, DBUS_TYPE_INVALID);
+       } else {
+               switch (new_pin) {
+               case -2:
+                       err_msg = "connect failed due to channel "
+                               "unavailability.";
+                       iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE;
+                       break;
+
+               case -3:
+                       err_msg = "connect failed due to unsupported channel.";
+                       iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED;
+                       break;
+
+               default:
+                       err_msg = "connect failed due to unspecified error.";
+                       iface = WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR;
+                       break;
+               }
+
+               /*
+                * TODO:
+                * Do we need specialized errors corresponding to above
+                * error conditions as against just returning a different
+                * error message?
+                */
+               reply = dbus_message_new_error(message, iface, err_msg);
+       }
+
+out:
+       os_free(peer_object_path);
+       os_free(pin);
+       return reply;
+inv_args_clear:
+       wpa_dbus_dict_entry_clear(&entry);
+inv_args:
+       reply = wpas_dbus_error_invalid_args(message, NULL);
+       goto out;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
+                                          struct wpa_supplicant *wpa_s)
+{
+       DBusMessageIter iter_dict;
+       DBusMessage *reply = NULL;
+       DBusMessageIter iter;
+       struct wpa_dbus_dict_entry entry;
+       char *peer_object_path = NULL;
+       char *pg_object_path = NULL;
+       char *iface = NULL;
+       char *net_id_str = NULL;
+       u8 peer_addr[ETH_ALEN];
+       unsigned int group_id = 0;
+       int persistent = 0;
+       struct wpa_ssid *ssid;
+
+       if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
+               return reply;
+
+       dbus_message_iter_init(message, &iter);
+
+       if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+               goto err;
+
+       while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+               if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+                       goto err;
+
+               if (!os_strcmp(entry.key, "peer") &&
+                   (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+                       peer_object_path = os_strdup(entry.str_value);
+                       wpa_dbus_dict_entry_clear(&entry);
+               } else if (!os_strcmp(entry.key, "persistent_group_object") &&
+                          (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+                       pg_object_path = os_strdup(entry.str_value);
+                       persistent = 1;
+                       wpa_dbus_dict_entry_clear(&entry);
+               } else {
+                       wpa_dbus_dict_entry_clear(&entry);
+                       goto err;
+               }
+       }
+
+       if (!peer_object_path ||
+           (parse_peer_object_path(peer_object_path, peer_addr) < 0) ||
+           (p2p_get_peer_info(wpa_s->global->p2p,
+                              peer_addr, 0, NULL, 0) < 0)) {
+               goto err;
+       }
+
+       if (persistent) {
+               /*
+                * A group ID is defined meaning we want to re-invoke a
+                * persistent group
+                */
+
+               iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
+                                                           &net_id_str, NULL);
+               if (iface == NULL ||
+                   os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+                       reply = wpas_dbus_error_invalid_args(message,
+                                                            pg_object_path);
+                       goto out;
+               }
+
+               group_id = strtoul(net_id_str, NULL, 10);
+               if (errno == EINVAL) {
+                       reply = wpas_dbus_error_invalid_args(
+                               message, pg_object_path);
+                       goto out;
+               }
+
+               /* Get the SSID structure from the persistent group id */
+               ssid = wpa_config_get_network(wpa_s->conf, group_id);
+               if (ssid == NULL || ssid->disabled != 2)
+                       goto err;
+
+               if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL) < 0) {
+                       reply = wpas_dbus_error_unknown_error(
+                               message,
+                               "Failed to reinvoke a persistent group");
+                       goto out;
+               }
+       } else {
+               /*
+                * No group ID means propose to a peer to join my active group
+                */
+               if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname,
+                                         peer_addr, NULL)) {
+                       reply = wpas_dbus_error_unknown_error(
+                               message, "Failed to join to an active group");
+                       goto out;
+               }
+       }
+
+out:
+       os_free(pg_object_path);
+       os_free(peer_object_path);
+       return reply;
+
+err:
+       reply = wpas_dbus_error_invalid_args(message, NULL);
+       goto out;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
+                                                 struct wpa_supplicant *wpa_s)
+{
+       DBusMessageIter iter;
+       char *peer_object_path = NULL;
+       char *config_method = NULL;
+       u8 peer_addr[ETH_ALEN];
+
+       dbus_message_iter_init(message, &iter);
+       dbus_message_iter_get_basic(&iter, &peer_object_path);
+
+       if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
+               return wpas_dbus_error_invalid_args(message, NULL);
+
+       dbus_message_iter_next(&iter);
+       dbus_message_iter_get_basic(&iter, &config_method);
+
+       /*
+        * Validation checks on config_method are being duplicated here
+        * to be able to return invalid args reply since the error code
+        * from p2p module are not granular enough (yet).
+        */
+       if (os_strcmp(config_method, "display") &&
+           os_strcmp(config_method, "keypad") &&
+           os_strcmp(config_method, "pbc") &&
+           os_strcmp(config_method, "pushbutton"))
+               return wpas_dbus_error_invalid_args(message, NULL);
+
+       if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method, 0) < 0)
+               return wpas_dbus_error_unknown_error(message,
+                               "Failed to send provision discovery request");
+
+       return NULL;
+}
+
+
+/*
+ * P2P Device property accessor methods.
+ */
+
+dbus_bool_t wpas_dbus_getter_p2p_device_properties(DBusMessageIter *iter,
+                                                  DBusError *error,
+                                                  void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       DBusMessageIter variant_iter, dict_iter;
+       DBusMessageIter iter_secdev_dict_entry, iter_secdev_dict_val,
+               iter_secdev_dict_array;
+       const char *dev_name;
+       int num_vendor_extensions = 0;
+       int i;
+       const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
+
+       if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
+               return FALSE;
+
+       if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+                                             "a{sv}", &variant_iter) ||
+           !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
+               goto err_no_mem;
+
+       /* DeviceName */
+       dev_name = wpa_s->conf->device_name;
+       if (dev_name &&
+           !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name))
+               goto err_no_mem;
+
+       /* Primary device type */
+       if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
+                                            (char *)wpa_s->conf->device_type,
+                                            WPS_DEV_TYPE_LEN))
+               goto err_no_mem;
+
+       /* Secondary device types */
+       if (wpa_s->conf->num_sec_device_types) {
+               if (!wpa_dbus_dict_begin_array(&dict_iter,
+                                              "SecondaryDeviceTypes",
+                                              DBUS_TYPE_ARRAY_AS_STRING
+                                              DBUS_TYPE_BYTE_AS_STRING,
+                                              &iter_secdev_dict_entry,
+                                              &iter_secdev_dict_val,
+                                              &iter_secdev_dict_array))
+                       goto err_no_mem;
+
+               for (i = 0; i < wpa_s->conf->num_sec_device_types; i++)
+                       wpa_dbus_dict_bin_array_add_element(
+                               &iter_secdev_dict_array,
+                               wpa_s->conf->sec_device_type[i],
+                               WPS_DEV_TYPE_LEN);
+
+               if (!wpa_dbus_dict_end_array(&dict_iter,
+                                            &iter_secdev_dict_entry,
+                                            &iter_secdev_dict_val,
+                                            &iter_secdev_dict_array))
+                       goto err_no_mem;
+       }
+
+       /* Vendor Extensions */
+       for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+               if (wpa_s->conf->wps_vendor_ext[i] == NULL)
+                       continue;
+               vendor_ext[num_vendor_extensions++] =
+                       wpa_s->conf->wps_vendor_ext[i];
+       }
+
+       if (num_vendor_extensions &&
+           !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
+                                              "VendorExtension",
+                                              vendor_ext,
+                                              num_vendor_extensions))
+               goto err_no_mem;
+
+       /* GO Intent */
+       if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
+                                        wpa_s->conf->p2p_go_intent))
+               goto err_no_mem;
+
+       /* Persistent Reconnect */
+       if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistantReconnect",
+                                      wpa_s->conf->persistent_reconnect))
+               goto err_no_mem;
+
+       /* Listen Reg Class */
+       if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
+                                        wpa_s->conf->p2p_listen_reg_class))
+               goto err_no_mem;
+
+       /* Listen Channel */
+       if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
+                                        wpa_s->conf->p2p_listen_channel))
+               goto err_no_mem;
+
+       /* Oper Reg Class */
+       if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
+                                        wpa_s->conf->p2p_oper_reg_class))
+               goto err_no_mem;
+
+       /* Oper Channel */
+       if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
+                                        wpa_s->conf->p2p_oper_channel))
+               goto err_no_mem;
+
+       /* SSID Postfix */
+       if (wpa_s->conf->p2p_ssid_postfix &&
+           !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
+                                        wpa_s->conf->p2p_ssid_postfix))
+               goto err_no_mem;
+
+       /* Intra Bss */
+       if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
+                                      wpa_s->conf->p2p_intra_bss))
+               goto err_no_mem;
+
+       /* Group Idle */
+       if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
+                                        wpa_s->conf->p2p_group_idle))
+               goto err_no_mem;
+
+       /* Dissasociation low ack */
+       if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
+                                        wpa_s->conf->disassoc_low_ack))
+               goto err_no_mem;
+
+       if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
+           !dbus_message_iter_close_container(iter, &variant_iter))
+               goto err_no_mem;
+
+       return TRUE;
+
+err_no_mem:
+       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+       return FALSE;
+}
+
+
+dbus_bool_t wpas_dbus_setter_p2p_device_properties(DBusMessageIter *iter,
+                                                  DBusError *error,
+                                                  void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       DBusMessageIter variant_iter, iter_dict;
+       struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
+       unsigned int i;
+
+       if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
+               return FALSE;
+
+       dbus_message_iter_recurse(iter, &variant_iter);
+       if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
+               return FALSE;
+
+       while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+               if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
+                       dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+                                            "invalid message format");
+                       return FALSE;
+               }
+
+               if (os_strcmp(entry.key, "DeviceName") == 0) {
+                       char *devname;
+
+                       if (entry.type != DBUS_TYPE_STRING)
+                               goto error;
+
+                       devname = os_strdup(entry.str_value);
+                       if (devname == NULL)
+                               goto err_no_mem_clear;
+
+                       os_free(wpa_s->conf->device_name);
+                       wpa_s->conf->device_name = devname;
+
+                       wpa_s->conf->changed_parameters |=
+                               CFG_CHANGED_DEVICE_NAME;
+               } else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) {
+                       if (entry.type != DBUS_TYPE_ARRAY ||
+                           entry.array_type != DBUS_TYPE_BYTE ||
+                           entry.array_len != WPS_DEV_TYPE_LEN)
+                               goto error;
+
+                       os_memcpy(wpa_s->conf->device_type,
+                                 entry.bytearray_value,
+                                 WPS_DEV_TYPE_LEN);
+                       wpa_s->conf->changed_parameters |=
+                               CFG_CHANGED_DEVICE_TYPE;
+               } else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) {
+                       if (entry.type != DBUS_TYPE_ARRAY ||
+                           entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
+                           entry.array_len > MAX_SEC_DEVICE_TYPES)
+                               goto error;
+
+                       for (i = 0; i < entry.array_len; i++)
+                               if (wpabuf_len(entry.binarray_value[i]) !=
+                                   WPS_DEV_TYPE_LEN)
+                                       goto err_no_mem_clear;
+                       for (i = 0; i < entry.array_len; i++)
+                               os_memcpy(wpa_s->conf->sec_device_type[i],
+                                         wpabuf_head(entry.binarray_value[i]),
+                                         WPS_DEV_TYPE_LEN);
+                       wpa_s->conf->num_sec_device_types = entry.array_len;
+                       wpa_s->conf->changed_parameters |=
+                                       CFG_CHANGED_SEC_DEVICE_TYPE;
+               } else if (os_strcmp(entry.key, "VendorExtension") == 0) {
+                       if ((entry.type != DBUS_TYPE_ARRAY) ||
+                           (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
+                           (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
+                               goto error;
+
+                       wpa_s->conf->changed_parameters |=
+                               CFG_CHANGED_VENDOR_EXTENSION;
+
+                       for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+                               wpabuf_free(wpa_s->conf->wps_vendor_ext[i]);
+                               if (i < entry.array_len) {
+                                       wpa_s->conf->wps_vendor_ext[i] =
+                                               entry.binarray_value[i];
+                                       entry.binarray_value[i] = NULL;
+                               } else
+                                       wpa_s->conf->wps_vendor_ext[i] = NULL;
+                       }
+               } else if ((os_strcmp(entry.key, "GOIntent") == 0) &&
+                          (entry.type == DBUS_TYPE_UINT32) &&
+                          (entry.uint32_value <= 15))
+                       wpa_s->conf->p2p_go_intent = entry.uint32_value;
+               else if ((os_strcmp(entry.key, "PersistantReconnect") == 0) &&
+                        (entry.type == DBUS_TYPE_BOOLEAN))
+                       wpa_s->conf->persistent_reconnect = entry.bool_value;
+               else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
+                        (entry.type == DBUS_TYPE_UINT32)) {
+                       wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
+                       wpa_s->conf->changed_parameters |=
+                               CFG_CHANGED_P2P_LISTEN_CHANNEL;
+               } else if ((os_strcmp(entry.key, "ListenChannel") == 0) &&
+                          (entry.type == DBUS_TYPE_UINT32)) {
+                       wpa_s->conf->p2p_listen_channel = entry.uint32_value;
+                       wpa_s->conf->changed_parameters |=
+                               CFG_CHANGED_P2P_LISTEN_CHANNEL;
+               } else if ((os_strcmp(entry.key, "OperRegClass") == 0) &&
+                          (entry.type == DBUS_TYPE_UINT32)) {
+                       wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
+                       wpa_s->conf->changed_parameters |=
+                               CFG_CHANGED_P2P_OPER_CHANNEL;
+               } else if ((os_strcmp(entry.key, "OperChannel") == 0) &&
+                          (entry.type == DBUS_TYPE_UINT32)) {
+                       wpa_s->conf->p2p_oper_channel = entry.uint32_value;
+                       wpa_s->conf->changed_parameters |=
+                               CFG_CHANGED_P2P_OPER_CHANNEL;
+               } else if (os_strcmp(entry.key, "SsidPostfix") == 0) {
+                       char *postfix;
+
+                       if (entry.type != DBUS_TYPE_STRING)
+                               goto error;
+
+                       postfix = os_strdup(entry.str_value);
+                       if (!postfix)
+                               goto err_no_mem_clear;
+
+                       os_free(wpa_s->conf->p2p_ssid_postfix);
+                       wpa_s->conf->p2p_ssid_postfix = postfix;
+
+                       wpa_s->conf->changed_parameters |=
+                                       CFG_CHANGED_P2P_SSID_POSTFIX;
+               } else if ((os_strcmp(entry.key, "IntraBss") == 0) &&
+                          (entry.type == DBUS_TYPE_BOOLEAN)) {
+                       wpa_s->conf->p2p_intra_bss = entry.bool_value;
+                       wpa_s->conf->changed_parameters |=
+                               CFG_CHANGED_P2P_INTRA_BSS;
+               } else if ((os_strcmp(entry.key, "GroupIdle") == 0) &&
+                          (entry.type == DBUS_TYPE_UINT32))
+                       wpa_s->conf->p2p_group_idle = entry.uint32_value;
+               else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
+                        entry.type == DBUS_TYPE_UINT32)
+                       wpa_s->conf->disassoc_low_ack = entry.uint32_value;
+               else
+                       goto error;
+
+               wpa_dbus_dict_entry_clear(&entry);
+       }
+
+       if (wpa_s->conf->changed_parameters) {
+               /* Some changed parameters requires to update config*/
+               wpa_supplicant_update_config(wpa_s);
+       }
+
+       return TRUE;
+
+ error:
+       dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+                            "invalid message format");
+       wpa_dbus_dict_entry_clear(&entry);
+       return FALSE;
+
+ err_no_mem_clear:
+       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+       wpa_dbus_dict_entry_clear(&entry);
+       return FALSE;
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
+                                      void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       struct p2p_data *p2p = wpa_s->global->p2p;
+       int next = 0, i = 0;
+       int num = 0, out_of_mem = 0;
+       const u8 *addr;
+       const struct p2p_peer_info *peer_info = NULL;
+       dbus_bool_t success = FALSE;
+
+       struct dl_list peer_objpath_list;
+       struct peer_objpath_node {
+               struct dl_list list;
+               char path[WPAS_DBUS_OBJECT_PATH_MAX];
+       } *node, *tmp;
+
+       char **peer_obj_paths = NULL;
+
+       if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
+               return FALSE;
+
+       dl_list_init(&peer_objpath_list);
+
+       /* Get the first peer info */
+       peer_info = p2p_get_peer_found(p2p, NULL, next);
+
+       /* Get next and accumulate them */
+       next = 1;
+       while (peer_info != NULL) {
+               node = os_zalloc(sizeof(struct peer_objpath_node));
+               if (!node) {
+                       out_of_mem = 1;
+                       goto error;
+               }
+
+               addr = peer_info->p2p_device_addr;
+               os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX,
+                           "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
+                           "/" COMPACT_MACSTR,
+                           wpa_s->dbus_new_path, MAC2STR(addr));
+               dl_list_add_tail(&peer_objpath_list, &node->list);
+               num++;
+
+               peer_info = p2p_get_peer_found(p2p, addr, next);
+       }
+
+       /*
+        * Now construct the peer object paths in a form suitable for
+        * array_property_getter helper below.
+        */
+       peer_obj_paths = os_zalloc(num * sizeof(char *));
+
+       if (!peer_obj_paths) {
+               out_of_mem = 1;
+               goto error;
+       }
+
+       dl_list_for_each_safe(node, tmp, &peer_objpath_list,
+                             struct peer_objpath_node, list)
+               peer_obj_paths[i++] = node->path;
+
+       success = wpas_dbus_simple_array_property_getter(iter,
+                                                        DBUS_TYPE_OBJECT_PATH,
+                                                        peer_obj_paths, num,
+                                                        error);
+
+error:
+       if (peer_obj_paths)
+               os_free(peer_obj_paths);
+
+       dl_list_for_each_safe(node, tmp, &peer_objpath_list,
+                             struct peer_objpath_node, list) {
+               dl_list_del(&node->list);
+               os_free(node);
+       }
+       if (out_of_mem)
+               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+
+       return success;
+}
+
+
+enum wpas_p2p_role {
+       WPAS_P2P_ROLE_DEVICE,
+       WPAS_P2P_ROLE_GO,
+       WPAS_P2P_ROLE_CLIENT,
+};
+
+static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+       if (!ssid)
+               return WPAS_P2P_ROLE_DEVICE;
+       if (wpa_s->wpa_state != WPA_COMPLETED)
+               return WPAS_P2P_ROLE_DEVICE;
+
+       switch (ssid->mode) {
+       case WPAS_MODE_P2P_GO:
+       case WPAS_MODE_P2P_GROUP_FORMATION:
+               return WPAS_P2P_ROLE_GO;
+       case WPAS_MODE_INFRA:
+               if (ssid->p2p_group)
+                       return WPAS_P2P_ROLE_CLIENT;
+               return WPAS_P2P_ROLE_DEVICE;
+       default:
+               return WPAS_P2P_ROLE_DEVICE;
+       }
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
+                                     void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       char *str;
+
+       switch (wpas_get_p2p_role(wpa_s)) {
+       case WPAS_P2P_ROLE_GO:
+               str = "GO";
+               break;
+       case WPAS_P2P_ROLE_CLIENT:
+               str = "client";
+               break;
+       default:
+               str = "device";
+       }
+
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &str,
+                                               error);
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
+                                      void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+
+       if (wpa_s->dbus_groupobj_path == NULL)
+               return FALSE;
+
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
+                                               &wpa_s->dbus_groupobj_path,
+                                               error);
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
+                                       DBusError *error, void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+       if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
+               return FALSE;
+
+       os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+                   wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
+       path = go_peer_obj_path;
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
+                                               &path, error);
+}
+
+
+/*
+ * Peer object properties accessor methods
+ */
+
+dbus_bool_t wpas_dbus_getter_p2p_peer_properties(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;
+
+       if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
+               return FALSE;
+
+       /* get the peer info */
+       info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
+                                 peer_args->p2p_device_addr, 0);
+       if (info == NULL) {
+               dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
+               return FALSE;
+       }
+
+       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;
+
+       /* 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 (info->wps_sec_dev_type_list_len) {
+               const u8 *sec_dev_type_list = info->wps_sec_dev_type_list;
+               int num_sec_dev_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;
+                       }
+
+                       if (!wpa_dbus_dict_end_array(&dict_iter,
+                                               &iter_secdev_dict_entry,
+                                               &iter_secdev_dict_val,
+                                               &iter_secdev_dict_array))
+                               goto err_no_mem;
+               }
+       }
+
+       /* Add WPS vendor extensions attribute */
+       for (i = 0, num = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+               if (info->wps_vendor_ext[i] == NULL)
+                       continue;
+               vendor_extension[num] = info->wps_vendor_ext[i];
+               num++;
+       }
+
+       if (!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;
+
+       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)
+{
+       /* struct peer_handler_args *peer_args = user_data; */
+
+       dbus_set_error_const(error, DBUS_ERROR_FAILED, "not implemented");
+       return FALSE;
+}
+
+
+/**
+ * wpas_dbus_getter_persistent_groups - Get array of persistent group objects
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "PersistentGroups" property.
+ */
+dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
+                                              DBusError *error,
+                                              void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       struct wpa_ssid *ssid;
+       char **paths;
+       unsigned int i = 0, num = 0;
+       dbus_bool_t success = FALSE;
+
+       if (wpa_s->conf == NULL) {
+               wpa_printf(MSG_ERROR, "dbus: %s: "
+                          "An error occurred getting persistent groups list",
+                          __func__);
+               dbus_set_error_const(error, DBUS_ERROR_FAILED, "an error "
+                                    "occurred getting persistent groups list");
+               return FALSE;
+       }
+
+       for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
+               if (network_is_persistent_group(ssid))
+                       num++;
+
+       paths = os_zalloc(num * sizeof(char *));
+       if (!paths) {
+               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+               return FALSE;
+       }
+
+       /* Loop through configured networks and append object path of each */
+       for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+               if (!network_is_persistent_group(ssid))
+                       continue;
+               paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
+               if (paths[i] == NULL) {
+                       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+                                            "no memory");
+                       goto out;
+               }
+               /* Construct the object path for this network. */
+               os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
+                           "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
+                           wpa_s->dbus_new_path, ssid->id);
+       }
+
+       success = wpas_dbus_simple_array_property_getter(iter,
+                                                        DBUS_TYPE_OBJECT_PATH,
+                                                        paths, num, error);
+
+out:
+       while (i)
+               os_free(paths[--i]);
+       os_free(paths);
+       return success;
+}
+
+
+/**
+ * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
+ *     group
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "Properties" property of a persistent group.
+ */
+dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter,
+                                                        DBusError *error,
+                                                        void *user_data)
+{
+       struct network_handler_args *net = user_data;
+
+       /* Leveraging the fact that persistent group object is still
+        * represented in same manner as network within.
+        */
+       return wpas_dbus_getter_network_properties(iter, error, net);
+}
+
+
+/**
+ * wpas_dbus_setter_persistent_group_properties - Get options for a persistent
+ *     group
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "Properties" property of a persistent group.
+ */
+dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter,
+                                                        DBusError *error,
+                                                        void *user_data)
+{
+       struct network_handler_args *net = user_data;
+       struct wpa_ssid *ssid = net->ssid;
+       DBusMessageIter variant_iter;
+
+       /*
+        * Leveraging the fact that persistent group object is still
+        * represented in same manner as network within.
+        */
+       dbus_message_iter_recurse(iter, &variant_iter);
+       return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
+}
+
+
+/**
+ * wpas_dbus_new_iface_add_persistent_group - Add a new configured
+ *     persistent_group
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing the object path of the new
+ * persistent group
+ *
+ * Handler function for "AddPersistentGroup" method call of a P2P Device
+ * interface.
+ */
+DBusMessage * wpas_dbus_handler_add_persistent_group(
+       DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+       DBusMessage *reply = NULL;
+       DBusMessageIter iter;
+       struct wpa_ssid *ssid = NULL;
+       char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
+       DBusError error;
+
+       dbus_message_iter_init(message, &iter);
+
+       ssid = wpa_config_add_network(wpa_s->conf);
+       if (ssid == NULL) {
+               wpa_printf(MSG_ERROR, "dbus: %s: "
+                          "Cannot add new persistent group", __func__);
+               reply = wpas_dbus_error_unknown_error(
+                       message,
+                       "wpa_supplicant could not add "
+                       "a persistent group on this interface.");
+               goto err;
+       }
+
+       /* Mark the ssid as being a persistent group before the notification */
+       ssid->disabled = 2;
+       ssid->p2p_persistent_group = 1;
+       wpas_notify_persistent_group_added(wpa_s, ssid);
+
+       wpa_config_set_network_defaults(ssid);
+
+       dbus_error_init(&error);
+       if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
+               wpa_printf(MSG_DEBUG, "dbus: %s: "
+                          "Control interface could not set persistent group "
+                          "properties", __func__);
+               reply = wpas_dbus_reply_new_from_error(message, &error,
+                                                      DBUS_ERROR_INVALID_ARGS,
+                                                      "Failed to set network "
+                                                      "properties");
+               dbus_error_free(&error);
+               goto err;
+       }
+
+       /* Construct the object path for this network. */
+       os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
+                   wpa_s->dbus_new_path, ssid->id);
+
+       reply = dbus_message_new_method_return(message);
+       if (reply == NULL) {
+               reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+                                              NULL);
+               goto err;
+       }
+       if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
+                                     DBUS_TYPE_INVALID)) {
+               dbus_message_unref(reply);
+               reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+                                              NULL);
+               goto err;
+       }
+
+       return reply;
+
+err:
+       if (ssid) {
+               wpas_notify_persistent_group_removed(wpa_s, ssid);
+               wpa_config_remove_network(wpa_s->conf, ssid->id);
+       }
+       return reply;
+}
+
+
+/**
+ * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent
+ *     group
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "RemovePersistentGroup" method call of a P2P Device
+ * interface.
+ */
+DBusMessage * wpas_dbus_handler_remove_persistent_group(
+       DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+       DBusMessage *reply = NULL;
+       const char *op;
+       char *iface = NULL, *persistent_group_id = NULL;
+       int id;
+       struct wpa_ssid *ssid;
+
+       dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
+                             DBUS_TYPE_INVALID);
+
+       /*
+        * Extract the network ID and ensure the network is actually a child of
+        * this interface.
+        */
+       iface = wpas_dbus_new_decompose_object_path(op, 1,
+                                                   &persistent_group_id,
+                                                   NULL);
+       if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+               reply = wpas_dbus_error_invalid_args(message, op);
+               goto out;
+       }
+
+       id = strtoul(persistent_group_id, NULL, 10);
+       if (errno == EINVAL) {
+               reply = wpas_dbus_error_invalid_args(message, op);
+               goto out;
+       }
+
+       ssid = wpa_config_get_network(wpa_s->conf, id);
+       if (ssid == NULL) {
+               reply = wpas_dbus_error_persistent_group_unknown(message);
+               goto out;
+       }
+
+       wpas_notify_persistent_group_removed(wpa_s, ssid);
+
+       if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+               wpa_printf(MSG_ERROR, "dbus: %s: "
+                          "error occurred when removing persistent group %d",
+                          __func__, id);
+               reply = wpas_dbus_error_unknown_error(
+                       message,
+                       "error removing the specified persistent group on "
+                       "this interface.");
+               goto out;
+       }
+
+out:
+       os_free(iface);
+       os_free(persistent_group_id);
+       return reply;
+}
+
+
+static void remove_persistent_group(struct wpa_supplicant *wpa_s,
+                                   struct wpa_ssid *ssid)
+{
+       wpas_notify_persistent_group_removed(wpa_s, ssid);
+
+       if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
+               wpa_printf(MSG_ERROR, "dbus: %s: "
+                          "error occurred when removing persistent group %d",
+                          __func__, ssid->id);
+               return;
+       }
+}
+
+
+/**
+ * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured
+ * persistent groups
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "RemoveAllPersistentGroups" method call of a
+ * P2P Device interface.
+ */
+DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
+       DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+       struct wpa_ssid *ssid, *next;
+       struct wpa_config *config;
+
+       config = wpa_s->conf;
+       ssid = config->ssid;
+       while (ssid) {
+               next = ssid->next;
+               if (network_is_persistent_group(ssid))
+                       remove_persistent_group(wpa_s, ssid);
+               ssid = next;
+       }
+       return NULL;
+}
+
+
+/*
+ * Group object properties accessor methods
+ */
+
+dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
+                                              DBusError *error,
+                                              void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       struct wpa_ssid *ssid;
+       unsigned int num_members;
+       char **paths;
+       unsigned int i;
+       void *next = NULL;
+       const u8 *addr;
+       dbus_bool_t success = FALSE;
+
+       /* Ensure we are a GO */
+       if (wpa_s->wpa_state != WPA_COMPLETED)
+               return FALSE;
+
+       ssid = wpa_s->conf->ssid;
+       /* At present WPAS P2P_GO mode only applicable for p2p_go */
+       if (ssid->mode != WPAS_MODE_P2P_GO &&
+           ssid->mode != WPAS_MODE_AP &&
+           ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
+               return FALSE;
+
+       num_members = p2p_get_group_num_members(wpa_s->p2p_group);
+
+       paths = os_zalloc(num_members * sizeof(char *));
+       if (!paths)
+               goto out_of_memory;
+
+       i = 0;
+       while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) {
+               paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
+               if (!paths[i])
+                       goto out_of_memory;
+               os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
+                           "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART
+                           "/" COMPACT_MACSTR,
+                           wpa_s->dbus_groupobj_path, MAC2STR(addr));
+               i++;
+       }
+
+       success = wpas_dbus_simple_array_property_getter(iter,
+                                                        DBUS_TYPE_OBJECT_PATH,
+                                                        paths, num_members,
+                                                        error);
+
+       for (i = 0; i < num_members; i++)
+               os_free(paths[i]);
+       os_free(paths);
+       return success;
+
+out_of_memory:
+       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+       if (paths) {
+               for (i = 0; i < num_members; i++)
+                       os_free(paths[i]);
+               os_free(paths);
+       }
+       return FALSE;
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_group_properties(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;
+
+       if (!hapd) {
+               dbus_set_error_const(error, DBUS_ERROR_FAILED,
+                                    "internal error");
+               return FALSE;
+       }
+
+       if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+                                             "a{sv}", &variant_iter) ||
+           !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
+               goto err_no_mem;
+
+       /* 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];
+       }
+
+       if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter,
+                                              "WPSVendorExtensions",
+                                              vendor_ext, num_vendor_ext))
+               goto err_no_mem;
+
+       if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
+           !dbus_message_iter_close_container(iter, &variant_iter))
+               goto err_no_mem;
+
+       return TRUE;
+
+err_no_mem:
+       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+       return FALSE;
+}
+
+
+dbus_bool_t wpas_dbus_setter_p2p_group_properties(DBusMessageIter *iter,
+                                                 DBusError *error,
+                                                 void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       DBusMessageIter variant_iter, iter_dict;
+       struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
+       unsigned int i;
+       struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
+
+       if (!hapd) {
+               dbus_set_error_const(error, DBUS_ERROR_FAILED,
+                                    "internal error");
+               return FALSE;
+       }
+
+       dbus_message_iter_recurse(iter, &variant_iter);
+       if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
+               return FALSE;
+
+       while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+               if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
+                       dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+                                            "invalid message format");
+                       return FALSE;
+               }
+
+               if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
+                       if (entry.type != DBUS_TYPE_ARRAY ||
+                           entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
+                           entry.array_len > MAX_WPS_VENDOR_EXTENSIONS)
+                               goto error;
+
+                       for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+                               if (i < entry.array_len) {
+                                       hapd->conf->wps_vendor_ext[i] =
+                                               entry.binarray_value[i];
+                                       entry.binarray_value[i] = NULL;
+                               } else
+                                       hapd->conf->wps_vendor_ext[i] = NULL;
+                       }
+
+                       hostapd_update_wps(hapd);
+               } else
+                       goto error;
+
+               wpa_dbus_dict_entry_clear(&entry);
+       }
+
+       return TRUE;
+
+error:
+       wpa_dbus_dict_entry_clear(&entry);
+       dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+                            "invalid message format");
+       return FALSE;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
+                                               struct wpa_supplicant *wpa_s)
+{
+       DBusMessageIter iter_dict;
+       DBusMessage *reply = NULL;
+       DBusMessageIter iter;
+       struct wpa_dbus_dict_entry entry;
+       int upnp = 0;
+       int bonjour = 0;
+       char *service = NULL;
+       struct wpabuf *query = NULL;
+       struct wpabuf *resp = NULL;
+       u8 version = 0;
+
+       dbus_message_iter_init(message, &iter);
+
+       if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+               goto error;
+
+       if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+               if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+                       goto error;
+
+               if (!os_strcmp(entry.key, "service_type") &&
+                   (entry.type == DBUS_TYPE_STRING)) {
+                       if (!os_strcmp(entry.str_value, "upnp"))
+                               upnp = 1;
+                       else if (!os_strcmp(entry.str_value, "bonjour"))
+                               bonjour = 1;
+                       else
+                               goto error_clear;
+                       wpa_dbus_dict_entry_clear(&entry);
+               }
+       }
+
+       if (upnp == 1) {
+               while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+                       if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+                               goto error;
+
+                       if (!os_strcmp(entry.key, "version") &&
+                           entry.type == DBUS_TYPE_INT32)
+                               version = entry.uint32_value;
+                       else if (!os_strcmp(entry.key, "service") &&
+                                entry.type == DBUS_TYPE_STRING)
+                               service = os_strdup(entry.str_value);
+                       wpa_dbus_dict_entry_clear(&entry);
+               }
+               if (version <= 0 || service == NULL)
+                       goto error;
+
+               if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
+                       goto error;
+
+               os_free(service);
+       } 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);
+                       goto error;
+               }
+       } else
+               goto error;
+
+       return reply;
+error_clear:
+       wpa_dbus_dict_entry_clear(&entry);
+error:
+       return wpas_dbus_error_invalid_args(message, NULL);
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_delete_service(
+       DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+       DBusMessageIter iter_dict;
+       DBusMessage *reply = NULL;
+       DBusMessageIter iter;
+       struct wpa_dbus_dict_entry entry;
+       int upnp = 0;
+       int bonjour = 0;
+       int ret = 0;
+       char *service = NULL;
+       struct wpabuf *query = NULL;
+       u8 version = 0;
+
+       dbus_message_iter_init(message, &iter);
+
+       if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+               goto error;
+
+       if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+               if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+                       goto error;
+
+               if (!os_strcmp(entry.key, "service_type") &&
+                   (entry.type == DBUS_TYPE_STRING)) {
+                       if (!os_strcmp(entry.str_value, "upnp"))
+                               upnp = 1;
+                       else if (!os_strcmp(entry.str_value, "bonjour"))
+                               bonjour = 1;
+                       else
+                               goto error_clear;
+                       wpa_dbus_dict_entry_clear(&entry);
+               }
+       }
+       if (upnp == 1) {
+               while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+                       if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+                               goto error;
+                       if (!os_strcmp(entry.key, "version") &&
+                           entry.type == DBUS_TYPE_INT32)
+                               version = entry.uint32_value;
+                       else if (!os_strcmp(entry.key, "service") &&
+                                entry.type == DBUS_TYPE_STRING)
+                               service = os_strdup(entry.str_value);
+                       else
+                               goto error_clear;
+
+                       wpa_dbus_dict_entry_clear(&entry);
+               }
+
+               if (version <= 0 || service == NULL)
+                       goto error;
+
+               ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
+               os_free(service);
+               if (ret != 0)
+                       goto error;
+       } else if (bonjour == 1) {
+               while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+                       if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+                               goto error;
+
+                       if (!os_strcmp(entry.key, "query")) {
+                               if ((entry.type != DBUS_TYPE_ARRAY) ||
+                                   (entry.array_type != DBUS_TYPE_BYTE))
+                                       goto error_clear;
+                               query = wpabuf_alloc_copy(
+                                       entry.bytearray_value,
+                                       entry.array_len);
+                       } else
+                               goto error_clear;
+
+                       wpa_dbus_dict_entry_clear(&entry);
+               }
+
+               if (query == NULL)
+                       goto error;
+
+               ret = wpas_p2p_service_del_bonjour(wpa_s, query);
+               if (ret != 0)
+                       goto error;
+               wpabuf_free(query);
+       } else
+               goto error;
+
+       return reply;
+error_clear:
+       wpa_dbus_dict_entry_clear(&entry);
+error:
+       return wpas_dbus_error_invalid_args(message, NULL);
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_flush_service(DBusMessage *message,
+                                                 struct wpa_supplicant *wpa_s)
+{
+       wpas_p2p_service_flush(wpa_s);
+       return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_service_sd_req(
+       DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+       DBusMessageIter iter_dict;
+       DBusMessage *reply = NULL;
+       DBusMessageIter iter;
+       struct wpa_dbus_dict_entry entry;
+       int upnp = 0;
+       char *service = NULL;
+       char *peer_object_path = NULL;
+       struct wpabuf *tlv = NULL;
+       u8 version = 0;
+       u64 ref = 0;
+       u8 addr[ETH_ALEN];
+
+       dbus_message_iter_init(message, &iter);
+
+       if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+               goto error;
+
+       while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+               if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+                       goto error;
+               if (!os_strcmp(entry.key, "peer_object") &&
+                   entry.type == DBUS_TYPE_OBJECT_PATH) {
+                       peer_object_path = os_strdup(entry.str_value);
+               } else if (!os_strcmp(entry.key, "service_type") &&
+                          entry.type == DBUS_TYPE_STRING) {
+                       if (!os_strcmp(entry.str_value, "upnp"))
+                               upnp = 1;
+                       else
+                               goto error_clear;
+               } else if (!os_strcmp(entry.key, "version") &&
+                          entry.type == DBUS_TYPE_INT32) {
+                       version = entry.uint32_value;
+               } else if (!os_strcmp(entry.key, "service") &&
+                          entry.type == DBUS_TYPE_STRING) {
+                       service = os_strdup(entry.str_value);
+               } else if (!os_strcmp(entry.key, "tlv")) {
+                       if (entry.type != DBUS_TYPE_ARRAY ||
+                           entry.array_type != DBUS_TYPE_BYTE)
+                               goto error_clear;
+                       tlv = wpabuf_alloc_copy(entry.bytearray_value,
+                                               entry.array_len);
+               } else
+                       goto error_clear;
+
+               wpa_dbus_dict_entry_clear(&entry);
+       }
+
+       if (!peer_object_path ||
+           (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 (upnp == 1) {
+               if (version <= 0 || service == NULL)
+                       goto error;
+
+               ref = wpas_p2p_sd_request_upnp(wpa_s, addr, version, service);
+       } else {
+               if (tlv == NULL)
+                       goto error;
+               ref = wpas_p2p_sd_request(wpa_s, addr, tlv);
+               wpabuf_free(tlv);
+       }
+
+       if (ref != 0) {
+               reply = dbus_message_new_method_return(message);
+               dbus_message_append_args(reply, DBUS_TYPE_UINT64,
+                                        &ref, DBUS_TYPE_INVALID);
+       } else {
+               reply = wpas_dbus_error_unknown_error(
+                       message, "Unable to send SD request");
+       }
+out:
+       os_free(service);
+       os_free(peer_object_path);
+       return reply;
+error_clear:
+       wpa_dbus_dict_entry_clear(&entry);
+error:
+       if (tlv)
+               wpabuf_free(tlv);
+       reply = wpas_dbus_error_invalid_args(message, NULL);
+       goto out;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_service_sd_res(
+       DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+       DBusMessageIter iter_dict;
+       DBusMessage *reply = NULL;
+       DBusMessageIter iter;
+       struct wpa_dbus_dict_entry entry;
+       char *peer_object_path = NULL;
+       struct wpabuf *tlv = NULL;
+       int freq = 0;
+       int dlg_tok = 0;
+       u8 addr[ETH_ALEN];
+
+       dbus_message_iter_init(message, &iter);
+
+       if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+               goto error;
+
+       while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+               if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+                       goto error;
+
+               if (!os_strcmp(entry.key, "peer_object") &&
+                   entry.type == DBUS_TYPE_OBJECT_PATH) {
+                       peer_object_path = os_strdup(entry.str_value);
+               } else if (!os_strcmp(entry.key, "frequency") &&
+                          entry.type == DBUS_TYPE_INT32) {
+                       freq = entry.uint32_value;
+               } else if (!os_strcmp(entry.key, "dialog_token") &&
+                          entry.type == DBUS_TYPE_UINT32) {
+                       dlg_tok = entry.uint32_value;
+               } else if (!os_strcmp(entry.key, "tlvs")) {
+                       if (entry.type != DBUS_TYPE_ARRAY ||
+                           entry.array_type != DBUS_TYPE_BYTE)
+                               goto error_clear;
+                       tlv = wpabuf_alloc_copy(entry.bytearray_value,
+                                               entry.array_len);
+               } else
+                       goto error_clear;
+
+               wpa_dbus_dict_entry_clear(&entry);
+       }
+       if (!peer_object_path ||
+           (parse_peer_object_path(peer_object_path, addr) < 0) ||
+           (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
+               goto error;
+
+       if (tlv == NULL)
+               goto error;
+
+       wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
+       wpabuf_free(tlv);
+out:
+       os_free(peer_object_path);
+       return reply;
+error_clear:
+       wpa_dbus_dict_entry_clear(&entry);
+error:
+       reply = wpas_dbus_error_invalid_args(message, NULL);
+       goto out;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_service_sd_cancel_req(
+       DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+       DBusMessageIter iter;
+       u64 req = 0;
+
+       dbus_message_iter_init(message, &iter);
+       dbus_message_iter_get_basic(&iter, &req);
+
+       if (req == 0)
+               goto error;
+
+       if (!wpas_p2p_sd_cancel_request(wpa_s, req))
+               goto error;
+
+       return NULL;
+error:
+       return wpas_dbus_error_invalid_args(message, NULL);
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_service_update(
+       DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+       wpas_p2p_sd_service_update(wpa_s);
+       return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_serv_disc_external(
+       DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+       DBusMessageIter iter;
+       int ext = 0;
+
+       dbus_message_iter_init(message, &iter);
+       dbus_message_iter_get_basic(&iter, &ext);
+
+       wpa_s->p2p_sd_over_ctrl_iface = ext;
+
+       return NULL;
+
+}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
new file mode 100644 (file)
index 0000000..206e904
--- /dev/null
@@ -0,0 +1,170 @@
+
+/*
+ * WPA Supplicant / dbus-based control interface for p2p
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef DBUS_NEW_HANDLERS_P2P_H
+#define DBUS_NEW_HANDLERS_P2P_H
+
+struct peer_handler_args {
+       struct wpa_supplicant *wpa_s;
+       u8 p2p_device_addr[ETH_ALEN];
+};
+
+struct groupmember_handler_args {
+       struct wpa_supplicant *wpa_s;
+       u8 member_addr[ETH_ALEN];
+};
+
+/*
+ * P2P Device methods
+ */
+
+DBusMessage *wpas_dbus_handler_p2p_find(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_stop_find(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_rejectpeer(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_listen(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_extendedlisten(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_presence_request(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_prov_disc_req(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_group_add(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_connect(
+               DBusMessage *message,
+               struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_invite(
+               DBusMessage *message,
+               struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_disconnect(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_flush(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_add_service(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_delete_service(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_flush_service(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_service_sd_req(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_service_sd_res(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_service_sd_cancel_req(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_service_update(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_serv_disc_external(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+/*
+ * P2P Device property accessor methods.
+ */
+dbus_bool_t wpas_dbus_setter_p2p_device_properties(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_peers(DBusMessageIter *iter, DBusError *error,
+                                      void *user_data);
+
+dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
+                                     void *user_data);
+
+dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
+                                      void *user_data);
+
+dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
+                                       DBusError *error,
+                                       void *user_data);
+
+/*
+ * P2P Peer properties.
+ */
+dbus_bool_t wpas_dbus_getter_p2p_peer_properties(DBusMessageIter *iter,
+                                                DBusError *error,
+                                                void *user_data);
+
+dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
+                                         DBusError *error,
+                                         void *user_data);
+
+/*
+ * P2P Group properties
+ */
+
+dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
+                                              DBusError *error,
+                                              void *user_data);
+
+dbus_bool_t wpas_dbus_getter_p2p_group_properties(DBusMessageIter *iter,
+                                                 DBusError *error,
+                                                 void *user_data);
+
+dbus_bool_t wpas_dbus_setter_p2p_group_properties(DBusMessageIter *iter,
+                                                 DBusError *error,
+                                                 void *user_data);
+
+/*
+ * P2P Persistent Groups and properties
+ */
+
+dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
+                                              DBusError *error,
+                                              void *user_data);
+
+dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter,
+       DBusError *error, void *user_data);
+
+dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter,
+                                                        DBusError *error,
+                                                        void *user_data);
+
+DBusMessage * wpas_dbus_handler_add_persistent_group(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_remove_persistent_group(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+
+#endif /* DBUS_NEW_HANDLERS_P2P_H */
index dc44a59..a72cfb3 100644 (file)
@@ -19,6 +19,8 @@
 #include "../config.h"
 #include "../wpa_supplicant_i.h"
 #include "../wps_supplicant.h"
+#include "../driver_i.h"
+#include "../ap.h"
 #include "dbus_new_helpers.h"
 #include "dbus_new.h"
 #include "dbus_new_handlers.h"
@@ -30,6 +32,7 @@ struct wps_start_params {
        int type; /* 0 - not set, 1 - pin,      2 - pbc       */
        u8 *bssid;
        char *pin;
+       u8 *p2p_dev_addr;
 };
 
 
@@ -107,7 +110,7 @@ static int wpas_dbus_handler_wps_bssid(DBusMessage *message,
        dbus_message_iter_recurse(entry_iter, &variant_iter);
        if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY ||
            dbus_message_iter_get_element_type(&variant_iter) !=
-           DBUS_TYPE_ARRAY) {
+           DBUS_TYPE_BYTE) {
                wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Bssid type, "
                           "byte array required");
                *reply = wpas_dbus_error_invalid_args(
@@ -148,6 +151,41 @@ static int wpas_dbus_handler_wps_pin(DBusMessage *message,
 }
 
 
+#ifdef CONFIG_P2P
+static int wpas_dbus_handler_wps_p2p_dev_addr(DBusMessage *message,
+                                             DBusMessageIter *entry_iter,
+                                             struct wps_start_params *params,
+                                             DBusMessage **reply)
+{
+       DBusMessageIter variant_iter, array_iter;
+       int len;
+
+       dbus_message_iter_recurse(entry_iter, &variant_iter);
+       if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY ||
+           dbus_message_iter_get_element_type(&variant_iter) !=
+           DBUS_TYPE_BYTE) {
+               wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong "
+                          "P2PDeviceAddress type, byte array required");
+               *reply = wpas_dbus_error_invalid_args(
+                       message, "P2PDeviceAddress must be a byte array");
+               return -1;
+       }
+       dbus_message_iter_recurse(&variant_iter, &array_iter);
+       dbus_message_iter_get_fixed_array(&array_iter, &params->p2p_dev_addr,
+                                         &len);
+       if (len != ETH_ALEN) {
+               wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong "
+                          "P2PDeviceAddress length %d", len);
+               *reply = wpas_dbus_error_invalid_args(message,
+                                                     "P2PDeviceAddress "
+                                                     "has wrong length");
+               return -1;
+       }
+       return 0;
+}
+#endif /* CONFIG_P2P */
+
+
 static int wpas_dbus_handler_wps_start_entry(DBusMessage *message, char *key,
                                             DBusMessageIter *entry_iter,
                                             struct wps_start_params *params,
@@ -165,6 +203,11 @@ static int wpas_dbus_handler_wps_start_entry(DBusMessage *message, char *key,
        else if (os_strcmp(key, "Pin") == 0)
                return wpas_dbus_handler_wps_pin(message, entry_iter,
                                                 params, reply);
+#ifdef CONFIG_P2P
+       else if (os_strcmp(key, "P2PDeviceAddress") == 0)
+               return wpas_dbus_handler_wps_p2p_dev_addr(message, entry_iter,
+                                                         params, reply);
+#endif /* CONFIG_P2P */
 
        wpa_printf(MSG_DEBUG, "dbus: WPS.Start - unknown key %s", key);
        *reply = wpas_dbus_error_invalid_args(message, key);
@@ -231,11 +274,31 @@ DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
                ret = wpas_wps_start_reg(wpa_s, params.bssid, params.pin,
                                         NULL);
        else if (params.type == 1) {
-               ret = wpas_wps_start_pin(wpa_s, params.bssid, params.pin);
-               if (ret > 0)
-                       os_snprintf(npin, sizeof(npin), "%08d", ret);
-       } else
-               ret = wpas_wps_start_pbc(wpa_s, params.bssid);
+#ifdef CONFIG_AP
+               if (wpa_s->ap_iface)
+                       ret = wpa_supplicant_ap_wps_pin(wpa_s,
+                                                       params.bssid,
+                                                       params.pin,
+                                                       npin, sizeof(npin));
+               else
+#endif /* CONFIG_AP */
+               {
+                       ret = wpas_wps_start_pin(wpa_s, params.bssid,
+                                                params.pin, 0,
+                                                DEV_PW_DEFAULT);
+                       if (ret > 0)
+                               os_snprintf(npin, sizeof(npin), "%08d", ret);
+               }
+       } else {
+#ifdef CONFIG_AP
+               if (wpa_s->ap_iface)
+                       ret = wpa_supplicant_ap_wps_pbc(wpa_s,
+                                                       params.bssid,
+                                                       params.p2p_dev_addr);
+               else
+#endif /* CONFIG_AP */
+               ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0);
+       }
 
        if (ret < 0) {
                wpa_printf(MSG_DEBUG, "dbus: WPS.Start wpas_wps_failed in "
@@ -283,40 +346,43 @@ DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
  * wpas_dbus_getter_process_credentials - Check if credentials are processed
  * @message: Pointer to incoming dbus message
  * @wpa_s: %wpa_supplicant data structure
- * Returns: DBus message with a boolean on success or DBus error on failure
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "ProcessCredentials" property. Returns returned boolean will be
  * true if wps_cred_processing configuration field is not equal to 1 or false
  * if otherwise.
  */
-DBusMessage * wpas_dbus_getter_process_credentials(
-       DBusMessage *message, struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter,
+                                                DBusError *error,
+                                                void *user_data)
 {
+       struct wpa_supplicant *wpa_s = user_data;
        dbus_bool_t process = (wpa_s->conf->wps_cred_processing != 1);
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-                                               &process);
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+                                               &process, error);
 }
 
 
 /**
  * wpas_dbus_setter_process_credentials - Set credentials_processed conf param
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: NULL on success or DBus error on failure
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Setter for "ProcessCredentials" property. Sets credentials_processed on 2
  * if boolean argument is true or on 1 if otherwise.
  */
-DBusMessage * wpas_dbus_setter_process_credentials(
-       DBusMessage *message, struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter,
+                                                DBusError *error,
+                                                void *user_data)
 {
-       DBusMessage *reply = NULL;
+       struct wpa_supplicant *wpa_s = user_data;
        dbus_bool_t process_credentials, old_pc;
 
-       reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN,
-                                                &process_credentials);
-       if (reply)
-               return reply;
+       if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
+                                             &process_credentials))
+               return FALSE;
 
        old_pc = (wpa_s->conf->wps_cred_processing != 1);
        wpa_s->conf->wps_cred_processing = (process_credentials ? 2 : 1);
@@ -327,5 +393,5 @@ DBusMessage * wpas_dbus_setter_process_credentials(
                                               WPAS_DBUS_NEW_IFACE_WPS,
                                               "ProcessCredentials");
 
-       return NULL;
+       return TRUE;
 }
index 06749db..e254365 100644 (file)
 #include "dbus_common_i.h"
 #include "dbus_new.h"
 #include "dbus_new_helpers.h"
+#include "dbus_dict_helpers.h"
 
 
-/**
- * recursive_iter_copy - Reads arguments from one iterator and
- * writes to another recursively
- * @from: iterator to read from
- * @to: iterator to write to
- *
- * Copies one iterator's elements to another. If any element in
- * iterator is of container type, its content is copied recursively
- */
-static void recursive_iter_copy(DBusMessageIter *from, DBusMessageIter *to)
-{
-
-       char *subtype = NULL;
-       int type;
-
-       /* iterate over iterator to copy */
-       while ((type = dbus_message_iter_get_arg_type(from)) !=
-              DBUS_TYPE_INVALID) {
-
-               /* simply copy basic type entries */
-               if (dbus_type_is_basic(type)) {
-                       if (dbus_type_is_fixed(type)) {
-                               /*
-                                * According to DBus documentation all
-                                * fixed-length types are guaranteed to fit
-                                * 8 bytes
-                                */
-                               dbus_uint64_t v;
-                               dbus_message_iter_get_basic(from, &v);
-                               dbus_message_iter_append_basic(to, type, &v);
-                       } else {
-                               char *v;
-                               dbus_message_iter_get_basic(from, &v);
-                               dbus_message_iter_append_basic(to, type, &v);
-                       }
-               } else {
-                       /* recursively copy container type entries */
-                       DBusMessageIter write_subiter, read_subiter;
-
-                       dbus_message_iter_recurse(from, &read_subiter);
-
-                       if (type == DBUS_TYPE_VARIANT ||
-                           type == DBUS_TYPE_ARRAY) {
-                               subtype = dbus_message_iter_get_signature(
-                                       &read_subiter);
-                       }
-
-                       dbus_message_iter_open_container(to, type, subtype,
-                                                        &write_subiter);
-
-                       recursive_iter_copy(&read_subiter, &write_subiter);
-
-                       dbus_message_iter_close_container(to, &write_subiter);
-                       if (subtype)
-                               dbus_free(subtype);
-               }
-
-               dbus_message_iter_next(from);
-       }
-}
-
-
-static unsigned int fill_dict_with_properties(
-       DBusMessageIter *dict_iter, const struct wpa_dbus_property_desc *props,
-       const char *interface, const void *user_data)
+static dbus_bool_t fill_dict_with_properties(
+       DBusMessageIter *dict_iter,
+       const struct wpa_dbus_property_desc *props,
+       const char *interface, void *user_data, DBusError *error)
 {
-       DBusMessage *reply;
-       DBusMessageIter entry_iter, ret_iter;
-       unsigned int counter = 0;
+       DBusMessageIter entry_iter;
        const struct wpa_dbus_property_desc *dsc;
 
        for (dsc = props; dsc && dsc->dbus_property; dsc++) {
-               if (!os_strncmp(dsc->dbus_interface, interface,
-                               WPAS_DBUS_INTERFACE_MAX) &&
-                   dsc->access != W && dsc->getter) {
-                       reply = dsc->getter(NULL, user_data);
-                       if (!reply)
-                               continue;
-
-                       if (dbus_message_get_type(reply) ==
-                           DBUS_MESSAGE_TYPE_ERROR) {
-                               dbus_message_unref(reply);
-                               continue;
-                       }
+               /* Only return properties for the requested D-Bus interface */
+               if (os_strncmp(dsc->dbus_interface, interface,
+                              WPAS_DBUS_INTERFACE_MAX) != 0)
+                       continue;
 
-                       dbus_message_iter_init(reply, &ret_iter);
+               /* Skip write-only properties */
+               if (dsc->getter == NULL)
+                       continue;
 
-                       dbus_message_iter_open_container(dict_iter,
-                                                        DBUS_TYPE_DICT_ENTRY,
-                                                        NULL, &entry_iter);
-                       dbus_message_iter_append_basic(
-                               &entry_iter, DBUS_TYPE_STRING,
-                               &dsc->dbus_property);
+               if (!dbus_message_iter_open_container(dict_iter,
+                                                     DBUS_TYPE_DICT_ENTRY,
+                                                     NULL, &entry_iter)) {
+                       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+                                            "no memory");
+                       return FALSE;
+               }
+               if (!dbus_message_iter_append_basic(&entry_iter,
+                                                   DBUS_TYPE_STRING,
+                                                   &dsc->dbus_property)) {
+                       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+                                            "no memory");
+                       return FALSE;
+               }
 
-                       recursive_iter_copy(&ret_iter, &entry_iter);
+               /* An error getting a property fails the request entirely */
+               if (!dsc->getter(&entry_iter, error, user_data))
+                       return FALSE;
 
-                       dbus_message_iter_close_container(dict_iter,
-                                                         &entry_iter);
-                       dbus_message_unref(reply);
-                       counter++;
-               }
+               dbus_message_iter_close_container(dict_iter, &entry_iter);
        }
 
-       return counter;
+       return TRUE;
 }
 
 
@@ -142,37 +80,44 @@ static unsigned int fill_dict_with_properties(
  * specified as argument. Returned message contains one dict argument
  * with properties names as keys and theirs values as values.
  */
-static DBusMessage * get_all_properties(
-       DBusMessage *message, char *interface,
-       struct wpa_dbus_object_desc *obj_dsc)
+static DBusMessage * get_all_properties(DBusMessage *message, char *interface,
+                                       struct wpa_dbus_object_desc *obj_dsc)
 {
-       /* Create and initialize the return message */
-       DBusMessage *reply = dbus_message_new_method_return(message);
+       DBusMessage *reply;
        DBusMessageIter iter, dict_iter;
-       int props_num;
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                                        DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                                        DBUS_TYPE_STRING_AS_STRING
-                                        DBUS_TYPE_VARIANT_AS_STRING
-                                        DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
-                                        &dict_iter);
+       DBusError error;
 
-       props_num = fill_dict_with_properties(&dict_iter, obj_dsc->properties,
-                                             interface, obj_dsc->user_data);
+       reply = dbus_message_new_method_return(message);
+       if (reply == NULL) {
+               wpa_printf(MSG_ERROR, "%s: out of memory creating dbus reply",
+                          __func__);
+               return NULL;
+       }
 
-       dbus_message_iter_close_container(&iter, &dict_iter);
+       dbus_message_iter_init_append(reply, &iter);
+       if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) {
+               wpa_printf(MSG_ERROR, "%s: out of memory creating reply",
+                          __func__);
+               dbus_message_unref(reply);
+               reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+                                              "out of memory");
+               return reply;
+       }
 
-       if (props_num == 0) {
+       dbus_error_init(&error);
+       if (!fill_dict_with_properties(&dict_iter, obj_dsc->properties,
+                                      interface, obj_dsc->user_data, &error))
+       {
                dbus_message_unref(reply);
-               reply = dbus_message_new_error(message,
-                                              DBUS_ERROR_INVALID_ARGS,
-                                              "No readable properties in "
-                                              "this interface");
+               reply = wpas_dbus_reply_new_from_error(message, &error,
+                                                      DBUS_ERROR_INVALID_ARGS,
+                                                      "No readable properties"
+                                                      " in this interface");
+               dbus_error_free(&error);
+               return reply;
        }
 
+       wpa_dbus_dict_close_write(&iter, &dict_iter);
        return reply;
 }
 
@@ -219,15 +164,33 @@ static DBusMessage * properties_get(DBusMessage *message,
                                    const struct wpa_dbus_property_desc *dsc,
                                    void *user_data)
 {
-       if (os_strcmp(dbus_message_get_signature(message), "ss"))
+       DBusMessage *reply;
+       DBusMessageIter iter;
+       DBusError error;
+
+       if (os_strcmp(dbus_message_get_signature(message), "ss")) {
                return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                                              NULL);
+       }
+
+       if (dsc->getter == NULL) {
+               return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                             "Property is write-only");
+       }
 
-       if (dsc->access != W && dsc->getter)
-               return dsc->getter(message, user_data);
+       reply = dbus_message_new_method_return(message);
+       dbus_message_iter_init_append(reply, &iter);
+
+       dbus_error_init(&error);
+       if (dsc->getter(&iter, &error, user_data) == FALSE) {
+               dbus_message_unref(reply);
+               reply = wpas_dbus_reply_new_from_error(
+                       message, &error, DBUS_ERROR_FAILED,
+                       "Failed to read property");
+               dbus_error_free(&error);
+       }
 
-       return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
-                                     "Property is write-only");
+       return reply;
 }
 
 
@@ -235,15 +198,38 @@ static DBusMessage * properties_set(DBusMessage *message,
                                    const struct wpa_dbus_property_desc *dsc,
                                    void *user_data)
 {
-       if (os_strcmp(dbus_message_get_signature(message), "ssv"))
+       DBusMessage *reply;
+       DBusMessageIter iter;
+       DBusError error;
+
+       if (os_strcmp(dbus_message_get_signature(message), "ssv")) {
                return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                                              NULL);
+       }
+
+       if (dsc->setter == NULL) {
+               return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                             "Property is read-only");
+       }
+
+       dbus_message_iter_init(message, &iter);
+       /* Skip the interface name and the property name */
+       dbus_message_iter_next(&iter);
+       dbus_message_iter_next(&iter);
 
-       if (dsc->access != R && dsc->setter)
-               return dsc->setter(message, user_data);
+       /* Iter will now point to the property's new value */
+       dbus_error_init(&error);
+       if (dsc->setter(&iter, &error, user_data) == TRUE) {
+               /* Success */
+               reply = dbus_message_new_method_return(message);
+       } else {
+               reply = wpas_dbus_reply_new_from_error(
+                       message, &error, DBUS_ERROR_FAILED,
+                       "Failed to set property");
+               dbus_error_free(&error);
+       }
 
-       return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
-                                     "Property is read-only");
+       return reply;
 }
 
 
@@ -552,6 +538,7 @@ int wpa_dbus_register_object_per_iface(
        struct wpa_dbus_object_desc *obj_desc)
 {
        DBusConnection *con;
+       DBusError error;
 
        DBusObjectPathVTable vtable = {
                &free_dbus_object_desc_cb, &message_handler,
@@ -566,14 +553,24 @@ int wpa_dbus_register_object_per_iface(
        obj_desc->connection = con;
        obj_desc->path = os_strdup(path);
 
+       dbus_error_init(&error);
        /* Register the message handler for the interface functions */
-       if (!dbus_connection_register_object_path(con, path, &vtable,
-                                                 obj_desc)) {
-               wpa_printf(MSG_ERROR, "dbus: Could not set up message "
-                          "handler for interface %s object %s", ifname, path);
+       if (!dbus_connection_try_register_object_path(con, path, &vtable,
+                                                     obj_desc, &error)) {
+               if (!os_strcmp(error.name, DBUS_ERROR_OBJECT_PATH_IN_USE)) {
+                       wpa_printf(MSG_DEBUG, "dbus: %s", error.message);
+               } else {
+                       wpa_printf(MSG_ERROR, "dbus: Could not set up message "
+                                  "handler for interface %s object %s",
+                                  ifname, path);
+                       wpa_printf(MSG_ERROR, "dbus error: %s", error.name);
+                       wpa_printf(MSG_ERROR, "dbus: %s", error.message);
+               }
+               dbus_error_free(&error);
                return -1;
        }
 
+       dbus_error_free(&error);
        return 0;
 }
 
@@ -611,14 +608,14 @@ int wpa_dbus_unregister_object_per_iface(
 }
 
 
-static void put_changed_properties(const struct wpa_dbus_object_desc *obj_dsc,
-                                  const char *interface,
-                                  DBusMessageIter *dict_iter)
+static dbus_bool_t put_changed_properties(
+       const struct wpa_dbus_object_desc *obj_dsc, const char *interface,
+       DBusMessageIter *dict_iter, int clear_changed)
 {
-       DBusMessage *getter_reply;
-       DBusMessageIter prop_iter, entry_iter;
+       DBusMessageIter entry_iter;
        const struct wpa_dbus_property_desc *dsc;
        int i;
+       DBusError error;
 
        for (dsc = obj_dsc->properties, i = 0; dsc && dsc->dbus_property;
             dsc++, i++) {
@@ -627,43 +624,94 @@ static void put_changed_properties(const struct wpa_dbus_object_desc *obj_dsc,
                        continue;
                if (os_strcmp(dsc->dbus_interface, interface) != 0)
                        continue;
-               obj_dsc->prop_changed_flags[i] = 0;
-
-               getter_reply = dsc->getter(NULL, obj_dsc->user_data);
-               if (!getter_reply ||
-                   dbus_message_get_type(getter_reply) ==
-                   DBUS_MESSAGE_TYPE_ERROR) {
-                       wpa_printf(MSG_ERROR, "dbus: %s: Cannot get new value "
-                                  "of property %s", __func__,
-                                  dsc->dbus_property);
-                       continue;
-               }
+               if (clear_changed)
+                       obj_dsc->prop_changed_flags[i] = 0;
 
-               if (!dbus_message_iter_init(getter_reply, &prop_iter) ||
-                   !dbus_message_iter_open_container(dict_iter,
+               if (!dbus_message_iter_open_container(dict_iter,
                                                      DBUS_TYPE_DICT_ENTRY,
-                                                     NULL, &entry_iter) ||
-                   !dbus_message_iter_append_basic(&entry_iter,
+                                                     NULL, &entry_iter))
+                       return FALSE;
+
+               if (!dbus_message_iter_append_basic(&entry_iter,
                                                    DBUS_TYPE_STRING,
                                                    &dsc->dbus_property))
-                       goto err;
-
-               recursive_iter_copy(&prop_iter, &entry_iter);
+                       return FALSE;
+
+               dbus_error_init(&error);
+               if (!dsc->getter(&entry_iter, &error, obj_dsc->user_data)) {
+                       if (dbus_error_is_set (&error)) {
+                               wpa_printf(MSG_ERROR, "dbus: %s: Cannot get "
+                                          "new value of property %s: (%s) %s",
+                                          __func__, dsc->dbus_property,
+                                          error.name, error.message);
+                       } else {
+                               wpa_printf(MSG_ERROR, "dbus: %s: Cannot get "
+                                          "new value of property %s",
+                                          __func__, dsc->dbus_property);
+                       }
+                       dbus_error_free(&error);
+                       return FALSE;
+               }
 
                if (!dbus_message_iter_close_container(dict_iter, &entry_iter))
-                       goto err;
-
-               dbus_message_unref(getter_reply);
+                       return FALSE;
        }
 
+       return TRUE;
+}
+
+
+static void do_send_prop_changed_signal(
+       DBusConnection *con, const char *path, const char *interface,
+       const struct wpa_dbus_object_desc *obj_dsc)
+{
+       DBusMessage *msg;
+       DBusMessageIter signal_iter, dict_iter;
+
+       msg = dbus_message_new_signal(path, DBUS_INTERFACE_PROPERTIES,
+                                     "PropertiesChanged");
+       if (msg == NULL)
+               return;
+
+       dbus_message_iter_init_append(msg, &signal_iter);
+
+       if (!dbus_message_iter_append_basic(&signal_iter, DBUS_TYPE_STRING,
+                                           &interface))
+               goto err;
+
+       /* Changed properties dict */
+       if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
+                                             "{sv}", &dict_iter))
+               goto err;
+
+       if (!put_changed_properties(obj_dsc, interface, &dict_iter, 0))
+               goto err;
+
+       if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
+               goto err;
+
+       /* Invalidated properties array (empty) */
+       if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
+                                             "s", &dict_iter))
+               goto err;
+
+       if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
+               goto err;
+
+       dbus_connection_send(con, msg, NULL);
+
+out:
+       dbus_message_unref(msg);
        return;
 
 err:
-       wpa_printf(MSG_ERROR, "dbus: %s: Cannot construct signal", __func__);
+       wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
+                  __func__);
+       goto out;
 }
 
 
-static void send_prop_changed_signal(
+static void do_send_deprecated_prop_changed_signal(
        DBusConnection *con, const char *path, const char *interface,
        const struct wpa_dbus_object_desc *obj_dsc)
 {
@@ -680,7 +728,8 @@ static void send_prop_changed_signal(
                                              "{sv}", &dict_iter))
                goto err;
 
-       put_changed_properties(obj_dsc, interface, &dict_iter);
+       if (!put_changed_properties(obj_dsc, interface, &dict_iter, 1))
+               goto err;
 
        if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
                goto err;
@@ -698,6 +747,29 @@ err:
 }
 
 
+static void send_prop_changed_signal(
+       DBusConnection *con, const char *path, const char *interface,
+       const struct wpa_dbus_object_desc *obj_dsc)
+{
+       /*
+        * First, send property change notification on the standardized
+        * org.freedesktop.DBus.Properties interface. This call will not
+        * clear the property change bits, so that they are preserved for
+        * the call that follows.
+        */
+       do_send_prop_changed_signal(con, path, interface, obj_dsc);
+
+       /*
+        * Now send PropertiesChanged on our own interface for backwards
+        * compatibility. This is deprecated and will be removed in a future
+        * release.
+        */
+       do_send_deprecated_prop_changed_signal(con, path, interface, obj_dsc);
+
+       /* Property change bits have now been cleared. */
+}
+
+
 static void flush_object_timeout_handler(void *eloop_ctx, void *timeout_ctx)
 {
        DBusConnection *con = eloop_ctx;
@@ -849,27 +921,147 @@ void wpa_dbus_mark_property_changed(struct wpas_dbus_priv *iface,
  * @iface: dbus priv struct
  * @path: path to DBus object which properties will be obtained
  * @interface: interface name which properties will be obtained
- * @dict_iter: correct, open DBus dictionary iterator.
+ * @iter: DBus message iter at which to append property dictionary.
  *
  * Iterates over all properties registered with object and execute getters
  * of those, which are readable and which interface matches interface
  * specified as argument. Obtained properties values are stored in
  * dict_iter dictionary.
  */
-void wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
-                                   const char *path, const char *interface,
-                                   DBusMessageIter *dict_iter)
+dbus_bool_t wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
+                                          const char *path,
+                                          const char *interface,
+                                          DBusMessageIter *iter)
 {
        struct wpa_dbus_object_desc *obj_desc = NULL;
+       DBusMessageIter dict_iter;
+       DBusError error;
 
        dbus_connection_get_object_path_data(iface->con, path,
                                             (void **) &obj_desc);
        if (!obj_desc) {
-               wpa_printf(MSG_ERROR, "dbus: wpa_dbus_get_object_properties: "
-                          "could not obtain object's private data: %s", path);
-               return;
+               wpa_printf(MSG_ERROR, "dbus: %s: could not obtain object's "
+                          "private data: %s", __func__, path);
+               return FALSE;
+       }
+
+       if (!wpa_dbus_dict_open_write(iter, &dict_iter)) {
+               wpa_printf(MSG_ERROR, "dbus: %s: failed to open message dict",
+                          __func__);
+               return FALSE;
+       }
+
+       dbus_error_init(&error);
+       if (!fill_dict_with_properties(&dict_iter, obj_desc->properties,
+                                      interface, obj_desc->user_data,
+                                      &error)) {
+               wpa_printf(MSG_ERROR, "dbus: %s: failed to get object"
+                          " properties: (%s) %s", __func__,
+                          dbus_error_is_set(&error) ? error.name : "none",
+                          dbus_error_is_set(&error) ? error.message : "none");
+               dbus_error_free(&error);
+               return FALSE;
        }
 
-       fill_dict_with_properties(dict_iter, obj_desc->properties,
-                                 interface, obj_desc->user_data);
+       return wpa_dbus_dict_close_write(iter, &dict_iter);
+}
+
+/**
+ * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts
+ * @path: The dbus object path
+ * @p2p_persistent_group: indicates whether to parse the path as a P2P
+ *                        persistent group object
+ * @network: (out) the configured network this object path refers to, if any
+ * @bssid: (out) the scanned bssid this object path refers to, if any
+ * Returns: The object path of the network interface this path refers to
+ *
+ * For a given object path, decomposes the object path into object id, network,
+ * and BSSID parts, if those parts exist.
+ */
+char *wpas_dbus_new_decompose_object_path(const char *path,
+                                          int p2p_persistent_group,
+                                          char **network,
+                                          char **bssid)
+{
+       const unsigned int dev_path_prefix_len =
+               os_strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/");
+       char *obj_path_only;
+       char *next_sep;
+
+       /* Be a bit paranoid about path */
+       if (!path || os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
+                               dev_path_prefix_len))
+               return NULL;
+
+       /* Ensure there's something at the end of the path */
+       if ((path + dev_path_prefix_len)[0] == '\0')
+               return NULL;
+
+       obj_path_only = os_strdup(path);
+       if (obj_path_only == NULL)
+               return NULL;
+
+       next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/');
+       if (next_sep != NULL) {
+               const char *net_part = os_strstr(
+                       next_sep, p2p_persistent_group ?
+                       WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/" :
+                       WPAS_DBUS_NEW_NETWORKS_PART "/");
+               const char *bssid_part = os_strstr(
+                       next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/");
+
+               if (network && net_part) {
+                       /* Deal with a request for a configured network */
+                       const char *net_name = net_part +
+                               os_strlen(p2p_persistent_group ?
+                                         WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART
+                                         "/" :
+                                         WPAS_DBUS_NEW_NETWORKS_PART "/");
+                       *network = NULL;
+                       if (os_strlen(net_name))
+                               *network = os_strdup(net_name);
+               } else if (bssid && bssid_part) {
+                       /* Deal with a request for a scanned BSSID */
+                       const char *bssid_name = bssid_part +
+                               os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/");
+                       if (os_strlen(bssid_name))
+                               *bssid = os_strdup(bssid_name);
+                       else
+                               *bssid = NULL;
+               }
+
+               /* Cut off interface object path before "/" */
+               *next_sep = '\0';
+       }
+
+       return obj_path_only;
+}
+
+
+/**
+ * wpas_dbus_reply_new_from_error - Create a new D-Bus error message from a
+ *   dbus error structure
+ * @message: The original request message for which the error is a reply
+ * @error: The error containing a name and a descriptive error cause
+ * @fallback_name: A generic error name if @error was not set
+ * @fallback_string: A generic error string if @error was not set
+ * Returns: A new D-Bus error message
+ *
+ * Given a DBusMessage structure, creates a new D-Bus error message using
+ * the error name and string contained in that structure.
+ */
+DBusMessage * wpas_dbus_reply_new_from_error(DBusMessage *message,
+                                            DBusError *error,
+                                            const char *fallback_name,
+                                            const char *fallback_string)
+{
+       if (error && error->name && error->message) {
+               return dbus_message_new_error(message, error->name,
+                                             error->message);
+       }
+       if (fallback_name && fallback_string) {
+               return dbus_message_new_error(message, fallback_name,
+                                             fallback_string);
+       }
+       return NULL;
 }
index 8db7a37..d6e7b48 100644 (file)
@@ -22,8 +22,9 @@ typedef DBusMessage * (* WPADBusMethodHandler)(DBusMessage *message,
                                               void *user_data);
 typedef void (* WPADBusArgumentFreeFunction)(void *handler_arg);
 
-typedef DBusMessage * (* WPADBusPropertyAccessor)(DBusMessage *message,
-                                                 const void *user_data);
+typedef dbus_bool_t (* WPADBusPropertyAccessor)(DBusMessageIter *iter,
+                                                DBusError *error,
+                                               void *user_data);
 
 struct wpa_dbus_object_desc {
        DBusConnection *connection;
@@ -44,8 +45,6 @@ struct wpa_dbus_object_desc {
        WPADBusArgumentFreeFunction user_data_free_func;
 };
 
-enum dbus_prop_access { R, W, RW };
-
 enum dbus_arg_direction { ARG_IN, ARG_OUT };
 
 struct wpa_dbus_argument {
@@ -67,7 +66,7 @@ struct wpa_dbus_method_desc {
        /* method handling function */
        WPADBusMethodHandler method_handler;
        /* array of arguments */
-       struct wpa_dbus_argument args[3];
+       struct wpa_dbus_argument args[4];
 };
 
 /**
@@ -79,7 +78,7 @@ struct wpa_dbus_signal_desc {
        /* signal interface */
        const char *dbus_interface;
        /* array of arguments */
-       struct wpa_dbus_argument args[3];
+       struct wpa_dbus_argument args[4];
 };
 
 /**
@@ -96,14 +95,13 @@ struct wpa_dbus_property_desc {
        WPADBusPropertyAccessor getter;
        /* property setter function */
        WPADBusPropertyAccessor setter;
-       /* property access permissions */
-       enum dbus_prop_access access;
 };
 
 
 #define WPAS_DBUS_OBJECT_PATH_MAX 150
 #define WPAS_DBUS_INTERFACE_MAX 150
 #define WPAS_DBUS_METHOD_SIGNAL_PROP_MAX 50
+#define WPAS_DBUS_AUTH_MODE_MAX 64
 
 #define WPA_DBUS_INTROSPECTION_INTERFACE "org.freedesktop.DBus.Introspectable"
 #define WPA_DBUS_INTROSPECTION_METHOD "Introspect"
@@ -127,9 +125,10 @@ int wpa_dbus_unregister_object_per_iface(
        struct wpas_dbus_priv *ctrl_iface,
        const char *path);
 
-void wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
-                                   const char *path, const char *interface,
-                                   DBusMessageIter *dict_iter);
+dbus_bool_t wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
+                                          const char *path,
+                                          const char *interface,
+                                          DBusMessageIter *iter);
 
 
 void wpa_dbus_flush_all_changed_properties(DBusConnection *con);
@@ -144,4 +143,14 @@ void wpa_dbus_mark_property_changed(struct wpas_dbus_priv *iface,
 DBusMessage * wpa_dbus_introspect(DBusMessage *message,
                                  struct wpa_dbus_object_desc *obj_dsc);
 
+char *wpas_dbus_new_decompose_object_path(const char *path,
+                                          int p2p_persistent_group,
+                                          char **network,
+                                          char **bssid);
+
+DBusMessage *wpas_dbus_reply_new_from_error(DBusMessage *message,
+                                           DBusError *error,
+                                           const char *fallback_name,
+                                           const char *fallback_string);
+
 #endif /* WPA_DBUS_CTRL_H */
index c660c04..fb29f20 100644 (file)
@@ -43,7 +43,7 @@ static struct interfaces * add_interface(struct dl_list *list,
        iface = os_zalloc(sizeof(struct interfaces));
        if (!iface)
                return NULL;
-       iface->xml = wpabuf_alloc(3000);
+       iface->xml = wpabuf_alloc(6000);
        if (iface->xml == NULL) {
                os_free(iface);
                return NULL;
@@ -89,10 +89,11 @@ static void add_entry(struct wpabuf *xml, const char *type, const char *name,
 static void add_property(struct wpabuf *xml,
                         const struct wpa_dbus_property_desc *dsc)
 {
-       wpabuf_printf(xml, "<property name=\"%s\" type=\"%s\" access=\"%s\"/>",
+       wpabuf_printf(xml, "<property name=\"%s\" type=\"%s\" "
+                     "access=\"%s%s\"/>",
                      dsc->dbus_property, dsc->type,
-                     (dsc->access == R ? "read" :
-                      (dsc->access == W ? "write" : "readwrite")));
+                     dsc->getter ? "read" : "",
+                     dsc->setter ? "write" : "");
 }
 
 
@@ -250,7 +251,7 @@ DBusMessage * wpa_dbus_introspect(DBusMessage *message,
        DBusMessage *reply;
        struct wpabuf *xml;
 
-       xml = wpabuf_alloc(4000);
+       xml = wpabuf_alloc(8000);
        if (xml == NULL)
                return NULL;
 
index 7f25bf0..71ab61e 100644 (file)
@@ -23,7 +23,6 @@
 #include "../bss.h"
 #include "dbus_old.h"
 #include "dbus_old_handlers.h"
-#include "dbus_common.h"
 #include "dbus_common_i.h"
 
 
@@ -287,6 +286,8 @@ static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection,
                else if (!os_strcmp(method, "wpsReg"))
                        reply = wpas_dbus_iface_wps_reg(message, wpa_s);
 #endif /* CONFIG_WPS */
+               else if (!os_strcmp(method, "flush"))
+                       reply = wpas_dbus_iface_flush(message, wpa_s);
        }
 
        /* If the message was handled, send back the reply */
@@ -547,6 +548,59 @@ void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
 }
 #endif /* CONFIG_WPS */
 
+void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
+                                             int depth, const char *subject,
+                                             const char *cert_hash,
+                                             const struct wpabuf *cert)
+{
+       struct wpas_dbus_priv *iface;
+       DBusMessage *_signal = NULL;
+       const char *hash;
+       const char *cert_hex;
+       int cert_hex_len;
+
+       /* Do nothing if the control interface is not turned on */
+       if (wpa_s->global == NULL)
+               return;
+       iface = wpa_s->global->dbus;
+       if (iface == NULL)
+               return;
+
+       _signal = dbus_message_new_signal(wpa_s->dbus_path,
+                                         WPAS_DBUS_IFACE_INTERFACE,
+                                         "Certification");
+       if (_signal == NULL) {
+               wpa_printf(MSG_ERROR,
+                          "dbus: wpa_supplicant_dbus_notify_certification: "
+                          "Could not create dbus signal; likely out of "
+                          "memory");
+               return;
+       }
+
+       hash = cert_hash ? cert_hash : "";
+       cert_hex = cert ? wpabuf_head(cert) : "";
+       cert_hex_len = cert ? wpabuf_len(cert) : 0;
+
+       if (!dbus_message_append_args(_signal,
+                                     DBUS_TYPE_INT32,&depth,
+                                     DBUS_TYPE_STRING, &subject,
+                                     DBUS_TYPE_STRING, &hash,
+                                     DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+                                     &cert_hex, cert_hex_len,
+                                     DBUS_TYPE_INVALID)) {
+               wpa_printf(MSG_ERROR,
+                          "dbus: wpa_supplicant_dbus_notify_certification: "
+                          "Not enough memory to construct signal");
+               goto out;
+       }
+
+       dbus_connection_send(iface->con, _signal, NULL);
+
+out:
+       dbus_message_unref(_signal);
+
+}
+
 
 /**
  * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface
index a9840c2..9523867 100644 (file)
@@ -82,6 +82,10 @@ void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
                                             enum wpa_states old_state);
 void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
                                         const struct wps_credential *cred);
+void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
+                                             int depth, const char *subject,
+                                             const char *cert_hash,
+                                             const struct wpabuf *cert);
 
 char * wpas_dbus_decompose_object_path(const char *path, char **network,
                                        char **bssid);
@@ -114,6 +118,14 @@ wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
 {
 }
 
+static inline void
+wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
+                                             int depth, const char *subject,
+                                             const char *cert_hash,
+                                             const struct wpabuf *cert)
+{
+}
+
 static inline int
 wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
 {
index d914697..a7eabf3 100644 (file)
@@ -116,7 +116,7 @@ DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
                DBusMessageIter iter_dict;
                struct wpa_dbus_dict_entry entry;
 
-               if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+               if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
                        goto error;
                while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
                        if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
@@ -922,7 +922,7 @@ DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
 
        dbus_message_iter_init(message, &iter);
 
-       if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) {
+       if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) {
                reply = wpas_dbus_new_invalid_opts_error(message, NULL);
                goto out;
        }
@@ -1202,7 +1202,7 @@ DBusMessage * wpas_dbus_iface_set_smartcard_modules(
        if (!dbus_message_iter_init(message, &iter))
                goto error;
 
-       if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+       if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
                goto error;
 
        while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
@@ -1324,7 +1324,7 @@ DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
 
        dbus_message_iter_init(message, &iter);
 
-       if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+       if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
                return wpas_dbus_new_invalid_opts_error(message, NULL);
 
        while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
@@ -1434,3 +1434,35 @@ DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
 
        return wpas_dbus_new_success_reply(message);
 }
+
+
+/**
+ * wpas_dbus_iface_flush - Clear BSS of old or all inactive entries
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: %wpa_supplicant data structure
+ * Returns: a dbus message containing a UINT32 indicating success (1) or
+ *          failure (0), or returns a dbus error message with more information
+ *
+ * Handler function for "flush" method call. Handles requests for an
+ * interface with an optional "age" parameter that specifies the minimum
+ * age of a BSS to be flushed.
+ */
+DBusMessage * wpas_dbus_iface_flush(DBusMessage *message,
+                                   struct wpa_supplicant *wpa_s)
+{
+       int flush_age = 0;
+
+       if (os_strlen(dbus_message_get_signature(message)) != 0 &&
+           !dbus_message_get_args(message, NULL,
+                                  DBUS_TYPE_INT32, &flush_age,
+                                  DBUS_TYPE_INVALID)) {
+               return wpas_dbus_new_invalid_opts_error(message, NULL);
+       }
+
+       if (flush_age == 0)
+               wpa_bss_flush(wpa_s);
+       else
+               wpa_bss_flush_by_age(wpa_s, flush_age);
+
+       return wpas_dbus_new_success_reply(message);
+}
index 65e876f..009e807 100644 (file)
@@ -96,6 +96,9 @@ DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message,
 DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message,
                                      struct wpa_supplicant *wpa_s);
 
+DBusMessage * wpas_dbus_iface_flush(DBusMessage *message,
+                                   struct wpa_supplicant *wpa_s);
+
 DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message);
 DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message,
                                               const char *arg);
index b5879f3..c04b844 100644 (file)
@@ -43,9 +43,9 @@ DBusMessage * wpas_dbus_iface_wps_pbc(DBusMessage *message,
                return wpas_dbus_new_invalid_opts_error(message, NULL);
 
        if (!os_strcmp(arg_bssid, "any"))
-               ret = wpas_wps_start_pbc(wpa_s, NULL);
+               ret = wpas_wps_start_pbc(wpa_s, NULL, 0);
        else if (!hwaddr_aton(arg_bssid, bssid))
-               ret = wpas_wps_start_pbc(wpa_s, bssid);
+               ret = wpas_wps_start_pbc(wpa_s, bssid, 0);
        else {
                return wpas_dbus_new_invalid_opts_error(message,
                                                        "Invalid BSSID");
@@ -94,9 +94,11 @@ DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message,
        }
 
        if (os_strlen(pin) > 0)
-               ret = wpas_wps_start_pin(wpa_s, _bssid, pin);
+               ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0,
+                                        DEV_PW_DEFAULT);
        else
-               ret = wpas_wps_start_pin(wpa_s, _bssid, NULL);
+               ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0,
+                                        DEV_PW_DEFAULT);
 
        if (ret < 0) {
                return dbus_message_new_error(message,
diff --git a/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service b/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service
deleted file mode 100644 (file)
index 41a2f50..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-[D-BUS Service]
-Name=fi.epitest.hostap.WPASupplicant
-Exec=/usr/bin/wpa_supplicant -Dwext -B -u -ddd -t -f/tmp/wpa_supplicant.debug
-User=root
diff --git a/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in b/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in
new file mode 100644 (file)
index 0000000..0e4e57f
--- /dev/null
@@ -0,0 +1,4 @@
+[D-BUS Service]
+Name=fi.epitest.hostap.WPASupplicant
+User=root
+SystemdService=wpa_supplicant.service
diff --git a/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service b/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service
deleted file mode 100644 (file)
index 0fd25dc..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-[D-BUS Service]
-Name=fi.w1.wpa_supplicant1
-Exec=/usr/bin/wpa_supplicant -Dwext -B -u -t -ddd -f/tmp/wpa_supplicant.debug
-User=root
diff --git a/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in b/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in
new file mode 100644 (file)
index 0000000..078e713
--- /dev/null
@@ -0,0 +1,4 @@
+[D-BUS Service]
+Name=fi.w1.wpa_supplicant1
+User=root
+SystemdService=wpa_supplicant.service
index 8c32cb3..cff25d6 100644 (file)
@@ -78,10 +78,15 @@ CONFIG_DRIVER_ATMEL=y
 #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_DRIVER_NL80211=y
 
 # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
 #CONFIG_DRIVER_BSD=y
@@ -109,11 +114,6 @@ CONFIG_DRIVER_WEXT=y
 # Driver interface for development testing
 #CONFIG_DRIVER_TEST=y
 
-# Include client MLME (management frame processing) for test driver
-# This can be used to test MLME operations in hostapd with the test interface.
-# space.
-#CONFIG_CLIENT_MLME=y
-
 # Driver interface for wired Ethernet drivers
 CONFIG_DRIVER_WIRED=y
 
@@ -123,6 +123,10 @@ CONFIG_DRIVER_WIRED=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
@@ -190,6 +194,13 @@ CONFIG_EAP_LEAP=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
 
 # EAP-IKEv2
 #CONFIG_EAP_IKEV2=y
@@ -224,6 +235,10 @@ CONFIG_CTRL_IFACE=y
 # 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%
@@ -305,18 +320,24 @@ CONFIG_PEERKEY=y
 
 # Select TLS implementation
 # openssl = OpenSSL (default)
-# gnutls = GnuTLS (needed for TLS/IA, see also CONFIG_GNUTLS_EXTRA)
+# gnutls = GnuTLS
 # internal = Internal TLSv1 implementation (experimental)
 # none = Empty template
 #CONFIG_TLS=openssl
 
-# Whether to enable TLS/IA support, which is required for EAP-TTLSv1.
-# You need CONFIG_TLS=gnutls for this to have any effect. Please note that
-# even though the core GnuTLS library is released under LGPL, this extra
-# library uses GPL and as such, the terms of GPL apply to the combination
-# of wpa_supplicant and GnuTLS if this option is enabled. BSD license may not
-# apply for distribution of the resulting binary.
-#CONFIG_GNUTLS_EXTRA=y
+# 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
@@ -378,6 +399,11 @@ CONFIG_PEERKEY=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
+
 # Enable privilege separation (see README 'Privilege separation' for details)
 #CONFIG_PRIVSEP=y
 
@@ -402,3 +428,43 @@ CONFIG_PEERKEY=y
 #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
+
+# 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
diff --git a/wpa_supplicant/doc/docbook/.gitignore b/wpa_supplicant/doc/docbook/.gitignore
deleted file mode 100644 (file)
index 8c3945c..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-manpage.links
-manpage.refs
-*.8
-*.5
-*.html
-*.pdf
index 3aae51b..0ab4e15 100644 (file)
       </varlistentry>
 
       <varlistentry>
-       <term>atmel</term>
-       <listitem>
-         <para>ATMEL AT76C5XXx (USB, PCMCIA).</para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
        <term>wext</term>
        <listitem>
          <para>Linux wireless extensions (generic).</para>
       </varlistentry>
 
       <varlistentry>
-       <term>ndiswrapper</term>
-       <listitem>
-         <para>Linux ndiswrapper.</para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
        <term>broadcom</term>
        <listitem>
          <para>Broadcom wl.o driver.</para>
       </varlistentry>
 
       <varlistentry>
-       <term>ipw</term>
-       <listitem>
-         <para>Intel ipw2100/2200 driver.</para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
        <term>wired</term>
        <listitem>
          <para>wpa_supplicant wired Ethernet driver</para>
@@ -599,13 +578,6 @@ wpa_supplicant \
       </varlistentry>
 
       <varlistentry>
-       <term>ATMEL AT76C5XXx driver for USB and PCMCIA cards</term>
-       <listitem>
-         <para> (http://atmelwlandriver.sourceforge.net/).</para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
        <term>Linux ndiswrapper</term>
        <listitem>
          <para> (http://ndiswrapper.sourceforge.net/) with Windows
index a70aa6a..d61b3fd 100644 (file)
@@ -79,6 +79,23 @@ static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,
        return -1;
 }
 
+static inline int wpa_drv_sched_scan(struct wpa_supplicant *wpa_s,
+                                    struct wpa_driver_scan_params *params,
+                                    u32 interval)
+{
+       if (wpa_s->driver->sched_scan)
+               return wpa_s->driver->sched_scan(wpa_s->drv_priv,
+                                                params, interval);
+       return -1;
+}
+
+static inline int wpa_drv_stop_sched_scan(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->driver->stop_sched_scan)
+               return wpa_s->driver->stop_sched_scan(wpa_s->drv_priv);
+       return -1;
+}
+
 static inline struct wpa_scan_results * wpa_drv_get_scan_results2(
        struct wpa_supplicant *wpa_s)
 {
@@ -236,35 +253,6 @@ wpa_drv_get_hw_feature_data(struct wpa_supplicant *wpa_s, u16 *num_modes,
        return NULL;
 }
 
-static inline int wpa_drv_set_channel(struct wpa_supplicant *wpa_s,
-                                     enum hostapd_hw_mode phymode, int chan,
-                                     int freq)
-{
-       if (wpa_s->driver->set_channel)
-               return wpa_s->driver->set_channel(wpa_s->drv_priv, phymode,
-                                                 chan, freq);
-       return -1;
-}
-
-static inline int wpa_drv_set_ssid(struct wpa_supplicant *wpa_s,
-                                  const u8 *ssid, size_t ssid_len)
-{
-       if (wpa_s->driver->set_ssid) {
-               return wpa_s->driver->set_ssid(wpa_s->drv_priv, ssid,
-                                              ssid_len);
-       }
-       return -1;
-}
-
-static inline int wpa_drv_set_bssid(struct wpa_supplicant *wpa_s,
-                                   const u8 *bssid)
-{
-       if (wpa_s->driver->set_bssid) {
-               return wpa_s->driver->set_bssid(wpa_s->drv_priv, bssid);
-       }
-       return -1;
-}
-
 static inline int wpa_drv_set_country(struct wpa_supplicant *wpa_s,
                                      const char *alpha2)
 {
@@ -274,29 +262,11 @@ static inline int wpa_drv_set_country(struct wpa_supplicant *wpa_s,
 }
 
 static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
-                                   const u8 *data, size_t data_len)
+                                   const u8 *data, size_t data_len, int noack)
 {
        if (wpa_s->driver->send_mlme)
                return wpa_s->driver->send_mlme(wpa_s->drv_priv,
-                                               data, data_len);
-       return -1;
-}
-
-static inline int wpa_drv_mlme_add_sta(struct wpa_supplicant *wpa_s,
-                                      const u8 *addr, const u8 *supp_rates,
-                                      size_t supp_rates_len)
-{
-       if (wpa_s->driver->mlme_add_sta)
-               return wpa_s->driver->mlme_add_sta(wpa_s->drv_priv, addr,
-                                                  supp_rates, supp_rates_len);
-       return -1;
-}
-
-static inline int wpa_drv_mlme_remove_sta(struct wpa_supplicant *wpa_s,
-                                         const u8 *addr)
-{
-       if (wpa_s->driver->mlme_remove_sta)
-               return wpa_s->driver->mlme_remove_sta(wpa_s->drv_priv, addr);
+                                               data, data_len, noack);
        return -1;
 }
 
@@ -320,15 +290,11 @@ static inline int wpa_drv_send_ft_action(struct wpa_supplicant *wpa_s,
        return -1;
 }
 
-static inline int wpa_drv_set_beacon(struct wpa_supplicant *wpa_s,
-                                    const u8 *head, size_t head_len,
-                                    const u8 *tail, size_t tail_len,
-                                    int dtim_period, int beacon_int)
+static inline int wpa_drv_set_ap(struct wpa_supplicant *wpa_s,
+                                struct wpa_driver_ap_params *params)
 {
-       if (wpa_s->driver->set_beacon)
-               return wpa_s->driver->set_beacon(wpa_s->drv_priv, head,
-                                                head_len, tail, tail_len,
-                                                dtim_period, beacon_int);
+       if (wpa_s->driver->set_ap)
+               return wpa_s->driver->set_ap(wpa_s->drv_priv, params);
        return -1;
 }
 
@@ -351,12 +317,12 @@ static inline int wpa_drv_sta_remove(struct wpa_supplicant *wpa_s,
 static inline int wpa_drv_hapd_send_eapol(struct wpa_supplicant *wpa_s,
                                          const u8 *addr, const u8 *data,
                                          size_t data_len, int encrypt,
-                                         const u8 *own_addr)
+                                         const u8 *own_addr, u32 flags)
 {
        if (wpa_s->driver->hapd_send_eapol)
                return wpa_s->driver->hapd_send_eapol(wpa_s->drv_priv, addr,
                                                      data, data_len, encrypt,
-                                                     own_addr);
+                                                     own_addr, flags);
        return -1;
 }
 
@@ -383,14 +349,30 @@ static inline int wpa_drv_set_supp_port(struct wpa_supplicant *wpa_s,
 
 static inline int wpa_drv_send_action(struct wpa_supplicant *wpa_s,
                                      unsigned int freq,
+                                     unsigned int wait,
                                      const u8 *dst, const u8 *src,
                                      const u8 *bssid,
-                                     const u8 *data, size_t data_len)
+                                     const u8 *data, size_t data_len,
+                                     int no_cck)
 {
        if (wpa_s->driver->send_action)
                return wpa_s->driver->send_action(wpa_s->drv_priv, freq,
-                                                 dst, src, bssid, data,
-                                                 data_len);
+                                                 wait, dst, src, bssid,
+                                                 data, data_len, no_cck);
+       return -1;
+}
+
+static inline void wpa_drv_send_action_cancel_wait(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->driver->send_action_cancel_wait)
+               wpa_s->driver->send_action_cancel_wait(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_set_freq(struct wpa_supplicant *wpa_s,
+                                  struct hostapd_freq_params *freq)
+{
+       if (wpa_s->driver->set_freq)
+               return wpa_s->driver->set_freq(wpa_s->drv_priv, freq);
        return -1;
 }
 
@@ -398,12 +380,12 @@ static inline int wpa_drv_if_add(struct wpa_supplicant *wpa_s,
                                 enum wpa_driver_if_type type,
                                 const char *ifname, const u8 *addr,
                                 void *bss_ctx, char *force_ifname,
-                                u8 *if_addr)
+                                u8 *if_addr, const char *bridge)
 {
        if (wpa_s->driver->if_add)
                return wpa_s->driver->if_add(wpa_s->drv_priv, type, ifname,
                                             addr, bss_ctx, NULL, force_ifname,
-                                            if_addr);
+                                            if_addr, bridge);
        return -1;
 }
 
@@ -444,15 +426,6 @@ static inline int wpa_drv_probe_req_report(struct wpa_supplicant *wpa_s,
        return -1;
 }
 
-static inline int wpa_drv_disable_11b_rates(struct wpa_supplicant *wpa_s,
-                                           int disabled)
-{
-       if (wpa_s->driver->disable_11b_rates)
-               return wpa_s->driver->disable_11b_rates(wpa_s->drv_priv,
-                                                       disabled);
-       return -1;
-}
-
 static inline int wpa_drv_deinit_ap(struct wpa_supplicant *wpa_s)
 {
        if (wpa_s->driver->deinit_ap)
@@ -481,14 +454,213 @@ static inline int wpa_drv_signal_monitor(struct wpa_supplicant *wpa_s,
        return -1;
 }
 
+static inline int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
+                                     struct wpa_signal_info *si)
+{
+       if (wpa_s->driver->signal_poll)
+               return wpa_s->driver->signal_poll(wpa_s->drv_priv, si);
+       return -1;
+}
+
 static inline int wpa_drv_set_ap_wps_ie(struct wpa_supplicant *wpa_s,
                                        const struct wpabuf *beacon,
-                                       const struct wpabuf *proberesp)
+                                       const struct wpabuf *proberesp,
+                                       const struct wpabuf *assocresp)
 {
        if (!wpa_s->driver->set_ap_wps_ie)
                return -1;
        return wpa_s->driver->set_ap_wps_ie(wpa_s->drv_priv, beacon,
-                                           proberesp);
+                                           proberesp, assocresp);
+}
+
+static inline int wpa_drv_shared_freq(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s->driver->shared_freq)
+               return -1;
+       return wpa_s->driver->shared_freq(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_get_noa(struct wpa_supplicant *wpa_s,
+                                 u8 *buf, size_t buf_len)
+{
+       if (!wpa_s->driver->get_noa)
+               return -1;
+       return wpa_s->driver->get_noa(wpa_s->drv_priv, buf, buf_len);
+}
+
+static inline int wpa_drv_set_p2p_powersave(struct wpa_supplicant *wpa_s,
+                                           int legacy_ps, int opp_ps,
+                                           int ctwindow)
+{
+       if (!wpa_s->driver->set_p2p_powersave)
+               return -1;
+       return wpa_s->driver->set_p2p_powersave(wpa_s->drv_priv, legacy_ps,
+                                               opp_ps, ctwindow);
+}
+
+static inline int wpa_drv_ampdu(struct wpa_supplicant *wpa_s, int ampdu)
+{
+       if (!wpa_s->driver->ampdu)
+               return -1;
+       return wpa_s->driver->ampdu(wpa_s->drv_priv, ampdu);
+}
+
+static inline int wpa_drv_p2p_find(struct wpa_supplicant *wpa_s,
+                                  unsigned int timeout, int type)
+{
+       if (!wpa_s->driver->p2p_find)
+               return -1;
+       return wpa_s->driver->p2p_find(wpa_s->drv_priv, timeout, type);
+}
+
+static inline int wpa_drv_p2p_stop_find(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s->driver->p2p_stop_find)
+               return -1;
+       return wpa_s->driver->p2p_stop_find(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_p2p_listen(struct wpa_supplicant *wpa_s,
+                                    unsigned int timeout)
+{
+       if (!wpa_s->driver->p2p_listen)
+               return -1;
+       return wpa_s->driver->p2p_listen(wpa_s->drv_priv, timeout);
+}
+
+static inline int wpa_drv_p2p_connect(struct wpa_supplicant *wpa_s,
+                                     const u8 *peer_addr, int wps_method,
+                                     int go_intent,
+                                     const u8 *own_interface_addr,
+                                     unsigned int force_freq,
+                                     int persistent_group)
+{
+       if (!wpa_s->driver->p2p_connect)
+               return -1;
+       return wpa_s->driver->p2p_connect(wpa_s->drv_priv, peer_addr,
+                                         wps_method, go_intent,
+                                         own_interface_addr, force_freq,
+                                         persistent_group);
+}
+
+static inline int wpa_drv_wps_success_cb(struct wpa_supplicant *wpa_s,
+                                        const u8 *peer_addr)
+{
+       if (!wpa_s->driver->wps_success_cb)
+               return -1;
+       return wpa_s->driver->wps_success_cb(wpa_s->drv_priv, peer_addr);
+}
+
+static inline int
+wpa_drv_p2p_group_formation_failed(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s->driver->p2p_group_formation_failed)
+               return -1;
+       return wpa_s->driver->p2p_group_formation_failed(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_p2p_set_params(struct wpa_supplicant *wpa_s,
+                                        const struct p2p_params *params)
+{
+       if (!wpa_s->driver->p2p_set_params)
+               return -1;
+       return wpa_s->driver->p2p_set_params(wpa_s->drv_priv, params);
+}
+
+static inline int wpa_drv_p2p_prov_disc_req(struct wpa_supplicant *wpa_s,
+                                           const u8 *peer_addr,
+                                           u16 config_methods, int join)
+{
+       if (!wpa_s->driver->p2p_prov_disc_req)
+               return -1;
+       return wpa_s->driver->p2p_prov_disc_req(wpa_s->drv_priv, peer_addr,
+                                               config_methods, join);
+}
+
+static inline u64 wpa_drv_p2p_sd_request(struct wpa_supplicant *wpa_s,
+                                        const u8 *dst,
+                                        const struct wpabuf *tlvs)
+{
+       if (!wpa_s->driver->p2p_sd_request)
+               return 0;
+       return wpa_s->driver->p2p_sd_request(wpa_s->drv_priv, dst, tlvs);
+}
+
+static inline int wpa_drv_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s,
+                                               u64 req)
+{
+       if (!wpa_s->driver->p2p_sd_cancel_request)
+               return -1;
+       return wpa_s->driver->p2p_sd_cancel_request(wpa_s->drv_priv, req);
+}
+
+static inline int wpa_drv_p2p_sd_response(struct wpa_supplicant *wpa_s,
+                                         int freq, const u8 *dst,
+                                         u8 dialog_token,
+                                         const struct wpabuf *resp_tlvs)
+{
+       if (!wpa_s->driver->p2p_sd_response)
+               return -1;
+       return wpa_s->driver->p2p_sd_response(wpa_s->drv_priv, freq, dst,
+                                             dialog_token, resp_tlvs);
+}
+
+static inline int wpa_drv_p2p_service_update(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s->driver->p2p_service_update)
+               return -1;
+       return wpa_s->driver->p2p_service_update(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_p2p_reject(struct wpa_supplicant *wpa_s,
+                                    const u8 *addr)
+{
+       if (!wpa_s->driver->p2p_reject)
+               return -1;
+       return wpa_s->driver->p2p_reject(wpa_s->drv_priv, addr);
+}
+
+static inline int wpa_drv_p2p_invite(struct wpa_supplicant *wpa_s,
+                                    const u8 *peer, int role, const u8 *bssid,
+                                    const u8 *ssid, size_t ssid_len,
+                                    const u8 *go_dev_addr,
+                                    int persistent_group)
+{
+       if (!wpa_s->driver->p2p_invite)
+               return -1;
+       return wpa_s->driver->p2p_invite(wpa_s->drv_priv, peer, role, bssid,
+                                        ssid, ssid_len, go_dev_addr,
+                                        persistent_group);
+}
+
+static inline int wpa_drv_send_tdls_mgmt(struct wpa_supplicant *wpa_s,
+                                        const u8 *dst, u8 action_code,
+                                        u8 dialog_token, u16 status_code,
+                                        const u8 *buf, size_t len)
+{
+       if (wpa_s->driver->send_tdls_mgmt) {
+               return wpa_s->driver->send_tdls_mgmt(wpa_s->drv_priv, dst,
+                                                    action_code, dialog_token,
+                                                    status_code, buf, len);
+       }
+       return -1;
+}
+
+static inline int wpa_drv_tdls_oper(struct wpa_supplicant *wpa_s,
+                                   enum tdls_oper oper, const u8 *peer)
+{
+       if (!wpa_s->driver->tdls_oper)
+               return -1;
+       return wpa_s->driver->tdls_oper(wpa_s->drv_priv, oper, peer);
+}
+
+static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s,
+                                         const u8 *kek, const u8 *kck,
+                                         const u8 *replay_ctr)
+{
+       if (!wpa_s->driver->set_rekey_info)
+               return;
+       wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kck, replay_ctr);
 }
 
 #endif /* DRIVER_I_H */
index f668874..b3faaa1 100644 (file)
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "eap_peer/eap_methods.h"
 #include "eap_server/eap_methods.h"
+#include "wpa_supplicant_i.h"
 
 
 /**
@@ -130,6 +131,10 @@ int eap_register_methods(void)
                ret = eap_peer_tnc_register();
 #endif /* EAP_TNC */
 
+#ifdef EAP_PWD
+       if (ret == 0)
+               ret = eap_peer_pwd_register();
+#endif /* EAP_PWD */
 
 #ifdef EAP_SERVER_IDENTITY
        if (ret == 0)
@@ -231,5 +236,10 @@ int eap_register_methods(void)
                ret = eap_server_tnc_register();
 #endif /* EAP_SERVER_TNC */
 
+#ifdef EAP_SERVER_PWD
+       if (ret == 0)
+               ret = eap_server_pwd_register();
+#endif /* EAP_SERVER_PWD */
+
        return ret;
 }
index 4eed854..76f7527 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - test code
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * 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
 #include "config.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "eap_peer/eap.h"
+#include "eap_server/eap_methods.h"
 #include "eloop.h"
+#include "utils/base64.h"
 #include "rsn_supp/wpa.h"
 #include "eap_peer/eap_i.h"
 #include "wpa_supplicant_i.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
+#include "common/wpa_ctrl.h"
 #include "ctrl_iface.h"
 #include "pcsc_funcs.h"
 
@@ -74,6 +77,8 @@ struct eapol_test_data {
        char *connect_info;
        u8 own_addr[ETH_ALEN];
        struct extra_radius_attr *extra_attrs;
+
+       FILE *server_cert_file;
 };
 
 static struct eapol_test_data eapol_test;
@@ -290,7 +295,6 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
 static int eapol_test_eapol_send(void *ctx, int type, const u8 *buf,
                                 size_t len)
 {
-       /* struct wpa_supplicant *wpa_s = ctx; */
        printf("WPA: eapol_test_eapol_send(type=%d len=%lu)\n",
               type, (unsigned long) len);
        if (type == IEEE802_1X_TYPE_EAP_PACKET) {
@@ -304,16 +308,16 @@ static int eapol_test_eapol_send(void *ctx, int type, const u8 *buf,
 static void eapol_test_set_config_blob(void *ctx,
                                       struct wpa_config_blob *blob)
 {
-       struct wpa_supplicant *wpa_s = ctx;
-       wpa_config_set_blob(wpa_s->conf, blob);
+       struct eapol_test_data *e = ctx;
+       wpa_config_set_blob(e->wpa_s->conf, blob);
 }
 
 
 static const struct wpa_config_blob *
 eapol_test_get_config_blob(void *ctx, const char *name)
 {
-       struct wpa_supplicant *wpa_s = ctx;
-       return wpa_config_get_blob(wpa_s->conf, name);
+       struct eapol_test_data *e = ctx;
+       return wpa_config_get_blob(e->wpa_s->conf, name);
 }
 
 
@@ -382,6 +386,53 @@ static void eapol_sm_cb(struct eapol_sm *eapol, int success, void *ctx)
 }
 
 
+static void eapol_test_write_cert(FILE *f, const char *subject,
+                                 const struct wpabuf *cert)
+{
+       unsigned char *encoded;
+
+       encoded = base64_encode(wpabuf_head(cert), wpabuf_len(cert), NULL);
+       if (encoded == NULL)
+               return;
+       fprintf(f, "%s\n-----BEGIN CERTIFICATE-----\n%s"
+               "-----END CERTIFICATE-----\n\n", subject, encoded);
+       os_free(encoded);
+}
+
+
+static void eapol_test_cert_cb(void *ctx, int depth, const char *subject,
+                              const char *cert_hash,
+                              const struct wpabuf *cert)
+{
+       struct eapol_test_data *e = ctx;
+
+       wpa_msg(e->wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
+               "depth=%d subject='%s'%s%s",
+               depth, subject,
+               cert_hash ? " hash=" : "",
+               cert_hash ? cert_hash : "");
+
+       if (cert) {
+               char *cert_hex;
+               size_t len = wpabuf_len(cert) * 2 + 1;
+               cert_hex = os_malloc(len);
+               if (cert_hex) {
+                       wpa_snprintf_hex(cert_hex, len, wpabuf_head(cert),
+                                        wpabuf_len(cert));
+                       wpa_msg_ctrl(e->wpa_s, MSG_INFO,
+                                    WPA_EVENT_EAP_PEER_CERT
+                                    "depth=%d subject='%s' cert=%s",
+                                    depth, subject, cert_hex);
+                       os_free(cert_hex);
+               }
+
+               if (e->server_cert_file)
+                       eapol_test_write_cert(e->server_cert_file,
+                                             subject, cert);
+       }
+}
+
+
 static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
                      struct wpa_ssid *ssid)
 {
@@ -393,7 +444,7 @@ static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
                printf("Failed to allocate EAPOL context.\n");
                return -1;
        }
-       ctx->ctx = wpa_s;
+       ctx->ctx = e;
        ctx->msg_ctx = wpa_s;
        ctx->scard_ctx = wpa_s->scard;
        ctx->cb = eapol_sm_cb;
@@ -407,6 +458,8 @@ static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
        ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
        ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
        ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+       ctx->cert_cb = eapol_test_cert_cb;
+       ctx->cert_in_cb = 1;
 
        wpa_s->eapol = eapol_sm_init(ctx);
        if (wpa_s->eapol == NULL) {
@@ -963,7 +1016,7 @@ static void usage(void)
               "eapol_test [-nWS] -c<conf> [-a<AS IP>] [-p<AS port>] "
               "[-s<AS secret>]\\\n"
               "           [-r<count>] [-t<timeout>] [-C<Connect-Info>] \\\n"
-              "           [-M<client MAC address>] \\\n"
+              "           [-M<client MAC address>] [-o<server cert file] \\\n"
               "           [-N<attr spec>] \\\n"
               "           [-A<client IP>]\n"
               "eapol_test scard\n"
@@ -989,6 +1042,8 @@ static void usage(void)
               "  -M<client MAC address> = Set own MAC address "
               "(Calling-Station-Id,\n"
               "                           default: 02:00:00:00:00:01)\n"
+              "  -o<server cert file> = Write received server certificate\n"
+              "                         chain to the specified file\n"
               "  -N<attr spec> = send arbitrary attribute specified by:\n"
               "                  attr_id:syntax:value or attr_id\n"
               "                  attr_id - number id of the attribute\n"
@@ -1030,7 +1085,7 @@ int main(int argc, char *argv[])
        wpa_debug_show_keys = 1;
 
        for (;;) {
-               c = getopt(argc, argv, "a:A:c:C:M:nN:p:r:s:St:W");
+               c = getopt(argc, argv, "a:A:c:C:M:nN:o:p:r:s:St:W");
                if (c < 0)
                        break;
                switch (c) {
@@ -1055,6 +1110,16 @@ int main(int argc, char *argv[])
                case 'n':
                        eapol_test.no_mppe_keys++;
                        break;
+               case 'o':
+                       if (eapol_test.server_cert_file)
+                               fclose(eapol_test.server_cert_file);
+                       eapol_test.server_cert_file = fopen(optarg, "w");
+                       if (eapol_test.server_cert_file == NULL) {
+                               printf("Could not open '%s' for writing\n",
+                                      optarg);
+                               return -1;
+                       }
+                       break;
                case 'p':
                        as_port = atoi(optarg);
                        break;
@@ -1191,9 +1256,15 @@ int main(int argc, char *argv[])
        test_eapol_clean(&eapol_test, &wpa_s);
 
        eap_peer_unregister_methods();
+#ifdef CONFIG_AP
+       eap_server_unregister_methods();
+#endif /* CONFIG_AP */
 
        eloop_destroy();
 
+       if (eapol_test.server_cert_file)
+               fclose(eapol_test.server_cert_file);
+
        printf("MPPE keys OK: %d  mismatch: %d\n",
               eapol_test.num_mppe_ok, eapol_test.num_mppe_mismatch);
        if (eapol_test.num_mppe_mismatch)
index 1ee8b74..bd3a2bc 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - Driver event processing
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * 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
 #include "common/wpa_ctrl.h"
 #include "eap_peer/eap.h"
 #include "ap/hostapd.h"
+#include "p2p/p2p.h"
 #include "notify.h"
 #include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "crypto/random.h"
 #include "blacklist.h"
 #include "wpas_glue.h"
 #include "wps_supplicant.h"
 #include "ibss_rsn.h"
 #include "sme.h"
+#include "gas_query.h"
+#include "p2p_supplicant.h"
 #include "bgscan.h"
 #include "ap.h"
 #include "bss.h"
-#include "mlme.h"
 #include "scan.h"
+#include "offchannel.h"
 
 
 static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
@@ -49,27 +54,23 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
        if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid)
                return 0;
 
-       wpa_printf(MSG_DEBUG, "Select network based on association "
-                  "information");
+       wpa_dbg(wpa_s, MSG_DEBUG, "Select network based on association "
+               "information");
        ssid = wpa_supplicant_get_ssid(wpa_s);
        if (ssid == NULL) {
-               wpa_printf(MSG_INFO, "No network configuration found for the "
-                          "current AP");
+               wpa_msg(wpa_s, MSG_INFO,
+                       "No network configuration found for the current AP");
                return -1;
        }
 
        if (ssid->disabled) {
-               wpa_printf(MSG_DEBUG, "Selected network is disabled");
+               wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is disabled");
                return -1;
        }
 
-       wpa_printf(MSG_DEBUG, "Network configuration found for the current "
-                  "AP");
-       if (ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
-                             WPA_KEY_MGMT_WPA_NONE |
-                             WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_FT_IEEE8021X |
-                             WPA_KEY_MGMT_PSK_SHA256 |
-                             WPA_KEY_MGMT_IEEE8021X_SHA256)) {
+       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,
@@ -91,8 +92,7 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
 }
 
 
-static void wpa_supplicant_stop_countermeasures(void *eloop_ctx,
-                                               void *sock_ctx)
+void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx)
 {
        struct wpa_supplicant *wpa_s = eloop_ctx;
 
@@ -109,11 +109,31 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
 {
        int bssid_changed;
 
+#ifdef CONFIG_IBSS_RSN
+       ibss_rsn_deinit(wpa_s->ibss_rsn);
+       wpa_s->ibss_rsn = NULL;
+#endif /* CONFIG_IBSS_RSN */
+
+#ifdef CONFIG_AP
+       wpa_supplicant_ap_deinit(wpa_s);
+#endif /* CONFIG_AP */
+
+       if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+               return;
+
        wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
        bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
        os_memset(wpa_s->bssid, 0, ETH_ALEN);
        os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
        wpa_s->current_bss = NULL;
+       wpa_s->assoc_freq = 0;
+#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_SME
+       if (wpa_s->sme.ft_ies)
+               sme_update_ft_ies(wpa_s, NULL, NULL, 0);
+#endif /* CONFIG_SME */
+#endif /* CONFIG_IEEE80211R */
+
        if (bssid_changed)
                wpas_notify_bssid_changed(wpa_s);
 
@@ -145,8 +165,8 @@ static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s)
                }
        }
 
-       wpa_printf(MSG_DEBUG, "RSN: PMKID from assoc IE %sfound from PMKSA "
-                  "cache", pmksa_set == 0 ? "" : "not ");
+       wpa_dbg(wpa_s, MSG_DEBUG, "RSN: PMKID from assoc IE %sfound from "
+               "PMKSA cache", pmksa_set == 0 ? "" : "not ");
 }
 
 
@@ -154,14 +174,15 @@ static void wpa_supplicant_event_pmkid_candidate(struct wpa_supplicant *wpa_s,
                                                 union wpa_event_data *data)
 {
        if (data == NULL) {
-               wpa_printf(MSG_DEBUG, "RSN: No data in PMKID candidate event");
+               wpa_dbg(wpa_s, MSG_DEBUG, "RSN: No data in PMKID candidate "
+                       "event");
                return;
        }
-       wpa_printf(MSG_DEBUG, "RSN: PMKID candidate event - bssid=" MACSTR
-                  " index=%d preauth=%d",
-                  MAC2STR(data->pmkid_candidate.bssid),
-                  data->pmkid_candidate.index,
-                  data->pmkid_candidate.preauth);
+       wpa_dbg(wpa_s, MSG_DEBUG, "RSN: PMKID candidate event - bssid=" MACSTR
+               " index=%d preauth=%d",
+               MAC2STR(data->pmkid_candidate.bssid),
+               data->pmkid_candidate.index,
+               data->pmkid_candidate.preauth);
 
        pmksa_candidate_add(wpa_s->wpa, data->pmkid_candidate.bssid,
                            data->pmkid_candidate.index,
@@ -204,6 +225,7 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
                              struct wpa_ssid *ssid)
 {
 #ifdef IEEE8021X_EAPOL
+#ifdef PCSC_FUNCS
        int aka = 0, sim = 0, type;
 
        if (ssid->eap.pcsc == NULL || wpa_s->scard != NULL)
@@ -232,13 +254,14 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
                aka = 0;
 
        if (!sim && !aka) {
-               wpa_printf(MSG_DEBUG, "Selected network is configured to use "
-                          "SIM, but neither EAP-SIM nor EAP-AKA are enabled");
+               wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is configured to "
+                       "use SIM, but neither EAP-SIM nor EAP-AKA are "
+                       "enabled");
                return 0;
        }
 
-       wpa_printf(MSG_DEBUG, "Selected network is configured to use SIM "
-                  "(sim=%d aka=%d) - initialize PCSC", sim, aka);
+       wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is configured to use SIM "
+               "(sim=%d aka=%d) - initialize PCSC", sim, aka);
        if (sim && aka)
                type = SCARD_TRY_BOTH;
        else if (aka)
@@ -248,12 +271,13 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
 
        wpa_s->scard = scard_init(type);
        if (wpa_s->scard == NULL) {
-               wpa_printf(MSG_WARNING, "Failed to initialize SIM "
-                          "(pcsc-lite)");
+               wpa_msg(wpa_s, MSG_WARNING, "Failed to initialize SIM "
+                       "(pcsc-lite)");
                return -1;
        }
        wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
        eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
+#endif /* PCSC_FUNCS */
 #endif /* IEEE8021X_EAPOL */
 
        return 0;
@@ -287,6 +311,9 @@ static int wpa_supplicant_match_privacy(struct wpa_scan_res *bss,
                privacy = 1;
 #endif /* IEEE8021X_EAPOL */
 
+       if (wpa_key_mgmt_wpa(ssid->key_mgmt))
+               privacy = 1;
+
        if (bss->caps & IEEE80211_CAP_PRIVACY)
                return privacy;
        return !privacy;
@@ -301,53 +328,70 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
        int proto_match = 0;
        const u8 *rsn_ie, *wpa_ie;
        int ret;
+       int wep_ok;
 
        ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss);
        if (ret >= 0)
                return ret;
 
+       /* Allow TSN if local configuration accepts WEP use without WPA/WPA2 */
+       wep_ok = !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
+               (((ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
+                 ssid->wep_key_len[ssid->wep_tx_keyidx] > 0) ||
+                (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA));
+
        rsn_ie = wpa_scan_get_ie(bss, WLAN_EID_RSN);
        while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) {
                proto_match++;
 
                if (wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) {
-                       wpa_printf(MSG_DEBUG, "   skip RSN IE - parse failed");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - parse "
+                               "failed");
                        break;
                }
+
+               if (wep_ok &&
+                   (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
+               {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   selected based on TSN "
+                               "in RSN IE");
+                       return 1;
+               }
+
                if (!(ie.proto & ssid->proto)) {
-                       wpa_printf(MSG_DEBUG, "   skip RSN IE - proto "
-                                  "mismatch");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - proto "
+                               "mismatch");
                        break;
                }
 
                if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
-                       wpa_printf(MSG_DEBUG, "   skip RSN IE - PTK cipher "
-                                  "mismatch");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - PTK "
+                               "cipher mismatch");
                        break;
                }
 
                if (!(ie.group_cipher & ssid->group_cipher)) {
-                       wpa_printf(MSG_DEBUG, "   skip RSN IE - GTK cipher "
-                                  "mismatch");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - GTK "
+                               "cipher mismatch");
                        break;
                }
 
                if (!(ie.key_mgmt & ssid->key_mgmt)) {
-                       wpa_printf(MSG_DEBUG, "   skip RSN IE - key mgmt "
-                                  "mismatch");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - key mgmt "
+                               "mismatch");
                        break;
                }
 
 #ifdef CONFIG_IEEE80211W
                if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
                    ssid->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
-                       wpa_printf(MSG_DEBUG, "   skip RSN IE - no mgmt frame "
-                                  "protection");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - no mgmt "
+                               "frame protection");
                        break;
                }
 #endif /* CONFIG_IEEE80211W */
 
-               wpa_printf(MSG_DEBUG, "   selected based on RSN IE");
+               wpa_dbg(wpa_s, MSG_DEBUG, "   selected based on RSN IE");
                return 1;
        }
 
@@ -356,39 +400,60 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
                proto_match++;
 
                if (wpa_parse_wpa_ie(wpa_ie, 2 + wpa_ie[1], &ie)) {
-                       wpa_printf(MSG_DEBUG, "   skip WPA IE - parse failed");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - parse "
+                               "failed");
                        break;
                }
+
+               if (wep_ok &&
+                   (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
+               {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   selected based on TSN "
+                               "in WPA IE");
+                       return 1;
+               }
+
                if (!(ie.proto & ssid->proto)) {
-                       wpa_printf(MSG_DEBUG, "   skip WPA IE - proto "
-                                  "mismatch");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - proto "
+                               "mismatch");
                        break;
                }
 
                if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
-                       wpa_printf(MSG_DEBUG, "   skip WPA IE - PTK cipher "
-                                  "mismatch");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - PTK "
+                               "cipher mismatch");
                        break;
                }
 
                if (!(ie.group_cipher & ssid->group_cipher)) {
-                       wpa_printf(MSG_DEBUG, "   skip WPA IE - GTK cipher "
-                                  "mismatch");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - GTK "
+                               "cipher mismatch");
                        break;
                }
 
                if (!(ie.key_mgmt & ssid->key_mgmt)) {
-                       wpa_printf(MSG_DEBUG, "   skip WPA IE - key mgmt "
-                                  "mismatch");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - key mgmt "
+                               "mismatch");
                        break;
                }
 
-               wpa_printf(MSG_DEBUG, "   selected based on WPA IE");
+               wpa_dbg(wpa_s, MSG_DEBUG, "   selected based on WPA IE");
                return 1;
        }
 
-       if (proto_match == 0)
-               wpa_printf(MSG_DEBUG, "   skip - no WPA/RSN proto match");
+       if ((ssid->proto & (WPA_PROTO_WPA | WPA_PROTO_RSN)) &&
+           wpa_key_mgmt_wpa(ssid->key_mgmt) && proto_match == 0) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "   skip - no WPA/RSN proto match");
+               return 0;
+       }
+
+       if (!wpa_key_mgmt_wpa(ssid->key_mgmt)) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "   allow in non-WPA/WPA2");
+               return 1;
+       }
+
+       wpa_dbg(wpa_s, MSG_DEBUG, "   reject due to mismatch with "
+               "WPA/WPA2");
 
        return 0;
 }
@@ -407,263 +472,267 @@ static int freq_allowed(int *freqs, int freq)
        return 0;
 }
 
-/*
- * Oct, 26th. 2011. TIZEN
- * Add a function to check current networks is set for wps in this file
- */
 
-#ifdef CONFIG_WPS
-static int wpas_wps_in_use_events(struct wpa_config *conf)
+static int ht_supported(const struct hostapd_hw_modes *mode)
 {
-       struct wpa_ssid *ssid;
-       int wps = 0;
-
-       for (ssid = conf->ssid; ssid; ssid = ssid->next) {
-               if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
-                       continue;
-
-               wps = 1;
-
-               if (!ssid->eap.phase1)
-                       continue;
-
-               if (os_strstr(ssid->eap.phase1, "pbc=1"))
-                       return 2;
+       if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) {
+               /*
+                * The driver did not indicate whether it supports HT. Assume
+                * it does to avoid connection issues.
+                */
+               return 1;
        }
 
-       return wps;
+       /*
+        * IEEE Std 802.11n-2009 20.1.1:
+        * An HT non-AP STA shall support all EQM rates for one spatial stream.
+        */
+       return mode->mcs_set[0] == 0xff;
 }
-#endif /* CONFIG_WPS */
 
 
-static struct wpa_bss *
-wpa_supplicant_select_bss_wpa(struct wpa_supplicant *wpa_s,
-                             struct wpa_scan_results *scan_res,
-                             struct wpa_ssid *group,
-                             struct wpa_ssid **selected_ssid)
+static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_scan_res *bss)
 {
-       struct wpa_ssid *ssid;
-       struct wpa_scan_res *bss;
-       size_t i;
-       struct wpa_blacklist *e;
-       const u8 *ie;
+       const struct hostapd_hw_modes *mode = NULL, *modes;
+       const u8 scan_ie[2] = { WLAN_EID_SUPP_RATES, WLAN_EID_EXT_SUPP_RATES };
+       const u8 *rate_ie;
+       int i, j, k;
 
-       wpa_printf(MSG_DEBUG, "Try to find WPA-enabled AP");
-       for (i = 0; i < scan_res->num; i++) {
-               const u8 *ssid_;
-               u8 wpa_ie_len, rsn_ie_len, ssid_len;
-               bss = scan_res->res[i];
+       if (bss->freq == 0)
+               return 1; /* Cannot do matching without knowing band */
 
-               ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
-               ssid_ = ie ? ie + 2 : (u8 *) "";
-               ssid_len = ie ? ie[1] : 0;
-
-               ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
-               wpa_ie_len = ie ? ie[1] : 0;
-
-               ie = wpa_scan_get_ie(bss, WLAN_EID_RSN);
-               rsn_ie_len = ie ? ie[1] : 0;
-
-               wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
-                          "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x",
-                          (int) i, MAC2STR(bss->bssid),
-                          wpa_ssid_txt(ssid_, ssid_len),
-                          wpa_ie_len, rsn_ie_len, bss->caps);
+       modes = wpa_s->hw.modes;
+       if (modes == NULL) {
+               /*
+                * The driver does not provide any additional information
+                * about the utilized hardware, so allow the connection attempt
+                * to continue.
+                */
+               return 1;
+       }
 
-               e = wpa_blacklist_get(wpa_s, bss->bssid);
-               if (e && e->count > 1) {
-                       wpa_printf(MSG_DEBUG, "   skip - blacklisted");
-                       continue;
+       for (i = 0; i < wpa_s->hw.num_modes; i++) {
+               for (j = 0; j < modes[i].num_channels; j++) {
+                       int freq = modes[i].channels[j].freq;
+                       if (freq == bss->freq) {
+                               if (mode &&
+                                   mode->mode == HOSTAPD_MODE_IEEE80211G)
+                                       break; /* do not allow 802.11b replace
+                                               * 802.11g */
+                               mode = &modes[i];
+                               break;
+                       }
                }
+       }
 
-               if (ssid_len == 0) {
-                       wpa_printf(MSG_DEBUG, "   skip - SSID not known");
-                       continue;
-               }
+       if (mode == NULL)
+               return 0;
 
-               if (wpa_ie_len == 0 && rsn_ie_len == 0) {
-                       wpa_printf(MSG_DEBUG, "   skip - no WPA/RSN IE");
+       for (i = 0; i < (int) sizeof(scan_ie); i++) {
+               rate_ie = wpa_scan_get_ie(bss, scan_ie[i]);
+               if (rate_ie == NULL)
                        continue;
-               }
 
-               for (ssid = group; ssid; ssid = ssid->pnext) {
-                       int check_ssid = 1;
+               for (j = 2; j < rate_ie[1] + 2; j++) {
+                       int flagged = !!(rate_ie[j] & 0x80);
+                       int r = (rate_ie[j] & 0x7f) * 5;
 
-                       if (ssid->disabled) {
-                               wpa_printf(MSG_DEBUG, "   skip - disabled");
+                       /*
+                        * IEEE Std 802.11n-2009 7.3.2.2:
+                        * The new BSS Membership selector value is encoded
+                        * like a legacy basic rate, but it is not a rate and
+                        * only indicates if the BSS members are required to
+                        * support the mandatory features of Clause 20 [HT PHY]
+                        * in order to join the BSS.
+                        */
+                       if (flagged && ((rate_ie[j] & 0x7f) ==
+                                       BSS_MEMBERSHIP_SELECTOR_HT_PHY)) {
+                               if (!ht_supported(mode)) {
+                                       wpa_dbg(wpa_s, MSG_DEBUG,
+                                               "   hardware does not support "
+                                               "HT PHY");
+                                       return 0;
+                               }
                                continue;
                        }
 
-#ifdef CONFIG_WPS
-                       if (ssid->ssid_len == 0 &&
-                           wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
-                               check_ssid = 0;
-#endif /* CONFIG_WPS */
-
-                       if (check_ssid &&
-                           (ssid_len != ssid->ssid_len ||
-                            os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) {
-                               wpa_printf(MSG_DEBUG, "   skip - "
-                                          "SSID mismatch");
+                       if (!flagged)
                                continue;
-                       }
 
-                       if (ssid->bssid_set &&
-                           os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
-                               wpa_printf(MSG_DEBUG, "   skip - "
-                                          "BSSID mismatch");
-                               continue;
+                       /* check for legacy basic rates */
+                       for (k = 0; k < mode->num_rates; k++) {
+                               if (mode->rates[k] == r)
+                                       break;
                        }
-
-                       if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss))
-                               continue;
-
-                       if (!freq_allowed(ssid->freq_list, bss->freq)) {
-                               wpa_printf(MSG_DEBUG, "   skip - "
-                                          "frequency not allowed");
-                               continue;
+                       if (k == mode->num_rates) {
+                               /*
+                                * IEEE Std 802.11-2007 7.3.2.2 demands that in
+                                * order to join a BSS all required rates
+                                * have to be supported by the hardware.
+                                */
+                               wpa_dbg(wpa_s, MSG_DEBUG, "   hardware does "
+                                       "not support required rate %d.%d Mbps",
+                                       r / 10, r % 10);
+                               return 0;
                        }
-
-                       wpa_printf(MSG_DEBUG, "   selected WPA AP "
-                                  MACSTR " ssid='%s'",
-                                  MAC2STR(bss->bssid),
-                                  wpa_ssid_txt(ssid_, ssid_len));
-                       *selected_ssid = ssid;
-                       return wpa_bss_get(wpa_s, bss->bssid, ssid_, ssid_len);
                }
        }
 
-       return NULL;
+       return 1;
 }
 
 
-static struct wpa_bss *
-wpa_supplicant_select_bss_non_wpa(struct wpa_supplicant *wpa_s,
-                                 struct wpa_scan_results *scan_res,
-                                 struct wpa_ssid *group,
-                                 struct wpa_ssid **selected_ssid)
+static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
+                                           int i, struct wpa_scan_res *bss,
+                                           struct wpa_ssid *group)
 {
-       struct wpa_ssid *ssid;
-       struct wpa_scan_res *bss;
-       size_t i;
+       const u8 *ssid_;
+       u8 wpa_ie_len, rsn_ie_len, ssid_len;
+       int wpa;
        struct wpa_blacklist *e;
        const u8 *ie;
+       struct wpa_ssid *ssid;
 
-       wpa_printf(MSG_DEBUG, "Try to find non-WPA AP");
-       for (i = 0; i < scan_res->num; i++) {
-               const u8 *ssid_;
-               u8 wpa_ie_len, rsn_ie_len, ssid_len;
-               bss = scan_res->res[i];
+       ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
+       ssid_ = ie ? ie + 2 : (u8 *) "";
+       ssid_len = ie ? ie[1] : 0;
 
-               ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
-               ssid_ = ie ? ie + 2 : (u8 *) "";
-               ssid_len = ie ? ie[1] : 0;
+       ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+       wpa_ie_len = ie ? ie[1] : 0;
 
-               ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
-               wpa_ie_len = ie ? ie[1] : 0;
+       ie = wpa_scan_get_ie(bss, WLAN_EID_RSN);
+       rsn_ie_len = ie ? ie[1] : 0;
 
-               ie = wpa_scan_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),
+               wpa_ie_len, rsn_ie_len, bss->caps, bss->level,
+               wpa_scan_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? " wps" : "");
 
-               wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
-                          "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x",
-                          (int) i, MAC2STR(bss->bssid),
-                          wpa_ssid_txt(ssid_, ssid_len),
-                          wpa_ie_len, rsn_ie_len, bss->caps);
+       e = wpa_blacklist_get(wpa_s, bss->bssid);
+       if (e) {
+               int limit = 1;
+               if (wpa_supplicant_enabled_networks(wpa_s->conf) == 1) {
+                       /*
+                        * When only a single network is enabled, we can
+                        * trigger blacklisting on the first failure. This
+                        * should not be done with multiple enabled networks to
+                        * avoid getting forced to move into a worse ESS on
+                        * single error if there are no other BSSes of the
+                        * current ESS.
+                        */
+                       limit = 0;
+               }
+               if (e->count > limit) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip - blacklisted "
+                               "(count=%d limit=%d)", e->count, limit);
+                       return NULL;
+               }
+       }
+
+       if (ssid_len == 0) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "   skip - SSID not known");
+               return NULL;
+       }
 
-               e = wpa_blacklist_get(wpa_s, bss->bssid);
-               if (e && e->count > 1) {
-                       wpa_printf(MSG_DEBUG, "   skip - blacklisted");
+       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);
+
+               if (ssid->disabled) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip - disabled");
                        continue;
                }
 
-               if (ssid_len == 0) {
-                       wpa_printf(MSG_DEBUG, "   skip - SSID not known");
+#ifdef CONFIG_WPS
+               if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip - blacklisted "
+                               "(WPS)");
                        continue;
                }
 
-               for (ssid = group; ssid; ssid = ssid->pnext) {
-                       int check_ssid = ssid->ssid_len != 0;
+               if (wpa && ssid->ssid_len == 0 &&
+                   wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
+                       check_ssid = 0;
 
-                       if (ssid->disabled) {
-                               wpa_printf(MSG_DEBUG, "   skip - disabled");
-                               continue;
-                       }
-
-#ifdef CONFIG_WPS
-                       if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
-                               /* Only allow wildcard SSID match if an AP
-                                * advertises active WPS operation that matches
-                                * with our mode. */
-                               check_ssid = 1;
-                               if (ssid->ssid_len == 0 &&
-                                   wpas_wps_ssid_wildcard_ok(wpa_s, ssid,
-                                                             bss))
-                                       check_ssid = 0;
-                       }
+               if (!wpa && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+                       /* Only allow wildcard SSID match if an AP
+                        * advertises active WPS operation that matches
+                        * with our mode. */
+                       check_ssid = 1;
+                       if (ssid->ssid_len == 0 &&
+                           wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
+                               check_ssid = 0;
+               }
 #endif /* CONFIG_WPS */
 
-                       if (check_ssid &&
-                           (ssid_len != ssid->ssid_len ||
-                            os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) {
-                               wpa_printf(MSG_DEBUG, "   skip - "
-                                          "SSID mismatch");
-                               continue;
-                       }
+               if (ssid->bssid_set && ssid->ssid_len == 0 &&
+                   os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0)
+                       check_ssid = 0;
 
-                       if (ssid->bssid_set &&
-                           os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
-                               wpa_printf(MSG_DEBUG, "   skip - "
-                                          "BSSID mismatch");
-                               continue;
-                       }
+               if (check_ssid &&
+                   (ssid_len != ssid->ssid_len ||
+                    os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip - SSID mismatch");
+                       continue;
+               }
 
-                       if (!(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
-                           !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
-                           !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
-                               wpa_printf(MSG_DEBUG, "   skip - "
-                                          "non-WPA network not allowed");
-                               continue;
-                       }
+               if (ssid->bssid_set &&
+                   os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip - BSSID mismatch");
+                       continue;
+               }
 
-                       if ((ssid->key_mgmt &
-                            (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
-                             WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK |
-                             WPA_KEY_MGMT_IEEE8021X_SHA256 |
-                             WPA_KEY_MGMT_PSK_SHA256)) &&
-                           (wpa_ie_len != 0 || rsn_ie_len != 0)) {
-                               wpa_printf(MSG_DEBUG, "   skip - "
-                                          "WPA network");
-                               continue;
-                       }
+               if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss))
+                       continue;
 
-                       if (!wpa_supplicant_match_privacy(bss, ssid)) {
-                               wpa_printf(MSG_DEBUG, "   skip - "
-                                          "privacy mismatch");
-                               continue;
-                       }
+               if (!wpa &&
+                   !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
+                   !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
+                   !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip - non-WPA network "
+                               "not allowed");
+                       continue;
+               }
 
-                       if (bss->caps & IEEE80211_CAP_IBSS) {
-                               wpa_printf(MSG_DEBUG, "   skip - "
-                                          "IBSS (adhoc) network");
-                               continue;
-                       }
+               if (!wpa_supplicant_match_privacy(bss, ssid)) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip - privacy "
+                               "mismatch");
+                       continue;
+               }
 
-                       if (!freq_allowed(ssid->freq_list, bss->freq)) {
-                               wpa_printf(MSG_DEBUG, "   skip - "
-                                          "frequency not allowed");
-                               continue;
-                       }
+               if (bss->caps & IEEE80211_CAP_IBSS) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip - IBSS (adhoc) "
+                               "network");
+                       continue;
+               }
 
-                       wpa_printf(MSG_DEBUG, "   selected non-WPA AP "
-                                  MACSTR " ssid='%s'",
-                                  MAC2STR(bss->bssid),
-                                  wpa_ssid_txt(ssid_, ssid_len));
-                       *selected_ssid = ssid;
-                       return wpa_bss_get(wpa_s, bss->bssid, ssid_, ssid_len);
+               if (!freq_allowed(ssid->freq_list, bss->freq)) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip - frequency not "
+                               "allowed");
+                       continue;
+               }
+
+               if (!rate_match(wpa_s, bss)) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip - rate sets do "
+                               "not match");
+                       continue;
                }
+
+#ifdef CONFIG_P2P
+               /*
+                * TODO: skip the AP if its P2P IE has Group Formation
+                * bit set in the P2P Group Capability Bitmap and we
+                * are not in Group Formation with that device.
+                */
+#endif /* CONFIG_P2P */
+
+               /* Matching configuration found */
+               return ssid;
        }
 
+       /* No matching configuration found */
        return NULL;
 }
 
@@ -674,21 +743,31 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s,
                          struct wpa_ssid *group,
                          struct wpa_ssid **selected_ssid)
 {
-       struct wpa_bss *selected;
+       size_t i;
+
+       wpa_dbg(wpa_s, MSG_DEBUG, "Selecting BSS from priority group %d",
+               group->priority);
 
-       wpa_printf(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;
+
+               *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;
 
-       /* First, try to find WPA-enabled AP */
-       selected = wpa_supplicant_select_bss_wpa(wpa_s, scan_res, group,
-                                                selected_ssid);
-       if (selected)
-               return selected;
+               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);
+       }
 
-       /* If no WPA-enabled AP found, try to find non-WPA AP, if configuration
-        * allows this. */
-       return wpa_supplicant_select_bss_non_wpa(wpa_s, scan_res, group,
-                                                selected_ssid);
+       return NULL;
 }
 
 
@@ -710,8 +789,8 @@ wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
                }
 
                if (selected == NULL && wpa_s->blacklist) {
-                       wpa_printf(MSG_DEBUG, "No APs found - clear blacklist "
-                                  "and try again");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "No APs found - clear "
+                               "blacklist and try again");
                        wpa_blacklist_clear(wpa_s);
                        wpa_s->blacklist_cleared++;
                } else if (selected == NULL)
@@ -738,15 +817,22 @@ static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s,
 }
 
 
-void wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
-                           struct wpa_bss *selected,
-                           struct wpa_ssid *ssid)
+int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
+                          struct wpa_bss *selected,
+                          struct wpa_ssid *ssid)
 {
        if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) {
                wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP
                        "PBC session overlap");
-               wpa_supplicant_req_new_scan(wpa_s, 10, 0);
-               return;
+#ifdef CONFIG_P2P
+               if (wpas_p2p_notif_pbc_overlap(wpa_s) == 1)
+                       return -1;
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WPS
+               wpas_wps_cancel(wpa_s);
+#endif /* CONFIG_WPS */
+               return -1;
        }
 
        /*
@@ -756,18 +842,27 @@ void wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
         */
        if (wpa_s->reassociate ||
            (os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 &&
-            (wpa_s->wpa_state != WPA_ASSOCIATING ||
+            ((wpa_s->wpa_state != WPA_ASSOCIATING &&
+              wpa_s->wpa_state != WPA_AUTHENTICATING) ||
              os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) !=
              0))) {
                if (wpa_supplicant_scard_init(wpa_s, ssid)) {
                        wpa_supplicant_req_new_scan(wpa_s, 10, 0);
-                       return;
+                       return 0;
                }
+               wpa_msg(wpa_s, MSG_DEBUG, "Request association: "
+                       "reassociate: %d  selected: "MACSTR "  bssid: " MACSTR
+                       "  pending: " MACSTR "  wpa_state: %s",
+                       wpa_s->reassociate, MAC2STR(selected->bssid),
+                       MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
+                       wpa_supplicant_state_txt(wpa_s->wpa_state));
                wpa_supplicant_associate(wpa_s, selected, ssid);
        } else {
-               wpa_printf(MSG_DEBUG, "Already associated with the selected "
-                          "AP");
+               wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with the "
+                       "selected AP");
        }
+
+       return 0;
 }
 
 
@@ -778,7 +873,8 @@ wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s)
        struct wpa_ssid *ssid;
 
        for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
-               for (ssid = wpa_s->conf->pssid[prio]; ssid; ssid = ssid->pnext) {
+               for (ssid = wpa_s->conf->pssid[prio]; ssid; ssid = ssid->pnext)
+               {
                        if (ssid->disabled)
                                continue;
                        if (ssid->mode == IEEE80211_MODE_IBSS ||
@@ -793,28 +889,25 @@ wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s)
 /* TODO: move the rsn_preauth_scan_result*() to be called from notify.c based
  * on BSS added and BSS changed events */
 static void wpa_supplicant_rsn_preauth_scan_results(
-       struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res)
+       struct wpa_supplicant *wpa_s)
 {
-       int i;
+       struct wpa_bss *bss;
 
        if (rsn_preauth_scan_results(wpa_s->wpa) < 0)
                return;
 
-       for (i = scan_res->num - 1; i >= 0; i--) {
+       dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
                const u8 *ssid, *rsn;
-               struct wpa_scan_res *r;
-
-               r = scan_res->res[i];
 
-               ssid = wpa_scan_get_ie(r, WLAN_EID_SSID);
+               ssid = wpa_bss_get_ie(bss, WLAN_EID_SSID);
                if (ssid == NULL)
                        continue;
 
-               rsn = wpa_scan_get_ie(r, WLAN_EID_RSN);
+               rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
                if (rsn == NULL)
                        continue;
 
-               rsn_preauth_scan_result(wpa_s->wpa, r->bssid, ssid, rsn);
+               rsn_preauth_scan_result(wpa_s->wpa, bss->bssid, ssid, rsn);
        }
 
 }
@@ -843,9 +936,12 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
         *
         * 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];
@@ -866,17 +962,17 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
        if (!current_bss)
                return 1; /* current BSS not seen in scan results */
 
-       wpa_printf(MSG_DEBUG, "Considering within-ESS reassociation");
-       wpa_printf(MSG_DEBUG, "Current BSS: " MACSTR " level=%d",
-                  MAC2STR(current_bss->bssid), current_bss->level);
-       wpa_printf(MSG_DEBUG, "Selected BSS: " MACSTR " level=%d",
-                  MAC2STR(selected->bssid), selected->level);
+       wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation");
+       wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR " level=%d",
+               MAC2STR(current_bss->bssid), current_bss->level);
+       wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS: " MACSTR " level=%d",
+               MAC2STR(selected->bssid), selected->level);
 
        if (wpa_s->current_ssid->bssid_set &&
            os_memcmp(selected->bssid, wpa_s->current_ssid->bssid, ETH_ALEN) ==
            0) {
-               wpa_printf(MSG_DEBUG, "Allow reassociation - selected BSS has "
-                          "preferred BSSID");
+               wpa_dbg(wpa_s, MSG_DEBUG, "Allow reassociation - selected BSS "
+                       "has preferred BSSID");
                return 1;
        }
 
@@ -894,16 +990,16 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
                        min_diff = 5;
        }
        if (abs(current_bss->level - selected->level) < min_diff) {
-               wpa_printf(MSG_DEBUG, "Skip roam - too small difference in "
-                          "signal level");
+               wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - too small difference "
+                       "in signal level");
                return 0;
        }
 
        return 1;
 }
 
-
-static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
+/* Return < 0 if no scan results could be fetched. */
+static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
                                              union wpa_event_data *data)
 {
        struct wpa_bss *selected;
@@ -918,60 +1014,70 @@ static void 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 (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+                               "stopped scan processing");
+                       return -1;
+               }
+       }
+#endif /* CONFIG_P2P */
+
        scan_res = wpa_supplicant_get_scan_results(wpa_s,
                                                   data ? &data->scan_info :
                                                   NULL, 1);
        if (scan_res == NULL) {
-       /*
-        * September, 9th 2011. TIZEN
-        * broadcom driver returns scan abort due to enable 802.11b only
-        * Therefore, this part is changed temporally until driver is fixed or
-        * our poilcy is changed.
-        * The supplicant tries to scan forcebly again after 1sec.
-        */
-
-               /* original codes */
-               /*
                if (wpa_s->conf->ap_scan == 2 || ap)
-                       return;
-               wpa_printf(MSG_DEBUG, "Failed to get scan results - try "
-                          "scanning again");
+                       return -1;
+               wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results - try "
+                       "scanning again");
                wpa_supplicant_req_new_scan(wpa_s, 1, 0);
-               */
-
-               /* changed codes */
-
-               /* connman set ap_scan as 2, thus we remove this code */
+               return -1;
+       }
 
-               if (ap)
-                       return;
-               wpa_printf(MSG_DEBUG, "Failed to get scan results - try "
-                          "scanning again");
-               /*Real scan function check !wpa_s->scan_req thus next line is added*/
-               wpa_s->scan_req = 2;
-               /* wpa_supplicant_req_new_scan checks enabled networks exist
-                * however, there is not any enabled network in this function
-                * To skip the checking routine, next line which is called scan function directly is added. */
-               wpa_supplicant_req_scan(wpa_s, 1, 0);
-
-               /************/
-               return;
+#ifndef CONFIG_NO_RANDOM_POOL
+       size_t i, num;
+       num = scan_res->num;
+       if (num > 10)
+               num = 10;
+       for (i = 0; i < num; i++) {
+               u8 buf[5];
+               struct wpa_scan_res *res = scan_res->res[i];
+               buf[0] = res->bssid[5];
+               buf[1] = res->qual & 0xff;
+               buf[2] = res->noise & 0xff;
+               buf[3] = res->level & 0xff;
+               buf[4] = res->tsf & 0xff;
+               random_add_randomness(buf, sizeof(buf));
        }
+#endif /* CONFIG_NO_RANDOM_POOL */
 
        if (wpa_s->scan_res_handler) {
-               wpa_s->scan_res_handler(wpa_s, scan_res);
+               void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
+                                        struct wpa_scan_results *scan_res);
+
+               scan_res_handler = wpa_s->scan_res_handler;
                wpa_s->scan_res_handler = NULL;
+               scan_res_handler(wpa_s, scan_res);
+
                wpa_scan_results_free(scan_res);
-               return;
+               return 0;
        }
 
        if (ap) {
-               wpa_printf(MSG_DEBUG, "Ignore scan results in AP mode");
+               wpa_dbg(wpa_s, MSG_DEBUG, "Ignore scan results in AP mode");
+#ifdef CONFIG_AP
+               if (wpa_s->ap_iface->scan_cb)
+                       wpa_s->ap_iface->scan_cb(wpa_s->ap_iface);
+#endif /* CONFIG_AP */
                wpa_scan_results_free(scan_res);
-               return;
+               return 0;
        }
 
-       wpa_printf(MSG_DEBUG, "New scan results available");
+       wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available");
        wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
        wpas_notify_scan_results(wpa_s);
 
@@ -979,71 +1085,113 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 
        if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) {
                wpa_scan_results_free(scan_res);
-               return;
+               return 0;
        }
 
        if (wpa_s->disconnected) {
                wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
                wpa_scan_results_free(scan_res);
-               return;
+               return 0;
        }
 
-       if (bgscan_notify_scan(wpa_s) == 1) {
+       if (!wpas_driver_bss_selection(wpa_s) &&
+           bgscan_notify_scan(wpa_s, scan_res) == 1) {
                wpa_scan_results_free(scan_res);
-               return;
+               return 0;
        }
 
-       wpa_supplicant_rsn_preauth_scan_results(wpa_s, scan_res);
-
        selected = wpa_supplicant_pick_network(wpa_s, scan_res, &ssid);
 
        if (selected) {
                int skip;
                skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid,
-                                                                                       scan_res);
+                                                   scan_res);
                wpa_scan_results_free(scan_res);
+               if (skip) {
+                       wpa_supplicant_rsn_preauth_scan_results(wpa_s);
+                       return 0;
+               }
 
-               if (skip)
-                       return;
-               wpa_supplicant_connect(wpa_s, selected, ssid);
+               if (wpa_supplicant_connect(wpa_s, selected, ssid) < 0) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed");
+                       return -1;
+               }
+               wpa_supplicant_rsn_preauth_scan_results(wpa_s);
        } else {
                wpa_scan_results_free(scan_res);
-               wpa_printf(MSG_DEBUG, "No suitable network found");
+               wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
                ssid = wpa_supplicant_pick_new_network(wpa_s);
                if (ssid) {
-                       wpa_printf(MSG_DEBUG, "Setup a new network");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "Setup a new network");
                        wpa_supplicant_associate(wpa_s, NULL, ssid);
+                       wpa_supplicant_rsn_preauth_scan_results(wpa_s);
                } else {
-                       /*
-                        * Oct, 26th. 2011. TIZEN
-                        * In case of WPS, wpa_s->conf->ssid should not be NULL
-                        */
-                       int wps = 0;
-
-                       int timeout_sec = 5;
+                       int timeout_sec = wpa_s->scan_interval;
                        int timeout_usec = 0;
-
-                       wps = wpas_wps_in_use_events(wpa_s->conf);
-
-                       if (wps == 0) {
-                               struct wpa_ssid *start;
-                               wpa_s->associate_num = 2;
-                               wpa_s->reassociate = 0;
-                               wpa_s->disconnected = 1;
-                               if (wpa_s->conf->ssid != NULL) {
-                                       start = wpa_s->conf->ssid;
-                                       while (start) {
-                                               start->scan_ssid = 0;
-                                               start = start->next;
-                                       }
-                               }
+#ifdef CONFIG_P2P
+                       if (wpa_s->p2p_in_provisioning) {
+                               /*
+                                * Use shorter wait during P2P Provisioning
+                                * state to speed up group formation.
+                                */
+                               timeout_sec = 0;
+                               timeout_usec = 250000;
+                               wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
+                                                           timeout_usec);
+                               return 0;
                        }
+#endif /* CONFIG_P2P */
+                       if (wpa_supplicant_req_sched_scan(wpa_s))
+                               wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
+                                                           timeout_usec);
+               }
+       }
+       return 0;
+}
+
+
+static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
+                                             union wpa_event_data *data)
+{
+       const char *rn, *rn2;
+       struct wpa_supplicant *ifs;
 
-                       wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
-                                                   timeout_usec);
+       if (_wpa_supplicant_event_scan_results(wpa_s, data) < 0) {
+               /*
+                * If no scan results could be fetched, then no need to
+                * notify those interfaces that did not actually request
+                * this scan.
+                */
+               return;
+       }
+
+       /*
+        * Check other interfaces to see if they have the same radio-name. If
+        * so, they get updated with this same scan info.
+        */
+       if (!wpa_s->driver->get_radio_name)
+               return;
+
+       rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+       if (rn == NULL || rn[0] == '\0')
+               return;
+
+       wpa_dbg(wpa_s, MSG_DEBUG, "Checking for other virtual interfaces "
+               "sharing same radio (%s) in event_scan_results", rn);
+
+       for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+               if (ifs == wpa_s || !ifs->driver->get_radio_name)
+                       continue;
+
+               rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
+               if (rn2 && os_strcmp(rn, rn2) == 0) {
+                       wpa_printf(MSG_DEBUG, "%s: Updating scan results from "
+                                  "sibling", ifs->ifname);
+                       _wpa_supplicant_event_scan_results(ifs, data);
                }
        }
 }
+
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 
 
@@ -1053,19 +1201,25 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
        int l, len, found = 0, wpa_found, rsn_found;
        const u8 *p;
 
-       wpa_printf(MSG_DEBUG, "Association info event");
+       wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
        if (data->assoc_info.req_ies)
                wpa_hexdump(MSG_DEBUG, "req_ies", data->assoc_info.req_ies,
                            data->assoc_info.req_ies_len);
-       if (data->assoc_info.resp_ies)
+       if (data->assoc_info.resp_ies) {
                wpa_hexdump(MSG_DEBUG, "resp_ies", data->assoc_info.resp_ies,
                            data->assoc_info.resp_ies_len);
+#ifdef CONFIG_TDLS
+               wpa_tdls_assoc_resp_ies(wpa_s->wpa, data->assoc_info.resp_ies,
+                                       data->assoc_info.resp_ies_len);
+#endif /* CONFIG_TDLS */
+       }
        if (data->assoc_info.beacon_ies)
                wpa_hexdump(MSG_DEBUG, "beacon_ies",
                            data->assoc_info.beacon_ies,
                            data->assoc_info.beacon_ies_len);
        if (data->assoc_info.freq)
-               wpa_printf(MSG_DEBUG, "freq=%u MHz", data->assoc_info.freq);
+               wpa_dbg(wpa_s, MSG_DEBUG, "freq=%u MHz",
+                       data->assoc_info.freq);
 
        p = data->assoc_info.req_ies;
        l = data->assoc_info.req_ies_len;
@@ -1102,8 +1256,8 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
                                                 data->assoc_info.resp_ies,
                                                 data->assoc_info.resp_ies_len,
                                                 bssid) < 0) {
-                       wpa_printf(MSG_DEBUG, "FT: Validation of "
-                                  "Reassociation Response failed");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "FT: Validation of "
+                               "Reassociation Response failed");
                        wpa_supplicant_deauthenticate(
                                wpa_s, WLAN_REASON_INVALID_IE);
                        return -1;
@@ -1113,6 +1267,27 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
        p = data->assoc_info.resp_ies;
        l = data->assoc_info.resp_ies_len;
 
+#ifdef CONFIG_WPS_STRICT
+       if (p && wpa_s->current_ssid &&
+           wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_WPS) {
+               struct wpabuf *wps;
+               wps = ieee802_11_vendor_ie_concat(p, l, WPS_IE_VENDOR_TYPE);
+               if (wps == NULL) {
+                       wpa_msg(wpa_s, MSG_INFO, "WPS-STRICT: AP did not "
+                               "include WPS IE in (Re)Association Response");
+                       return -1;
+               }
+
+               if (wps_validate_assoc_resp(wps) < 0) {
+                       wpabuf_free(wps);
+                       wpa_supplicant_deauthenticate(
+                               wpa_s, WLAN_REASON_INVALID_IE);
+                       return -1;
+               }
+               wpabuf_free(wps);
+       }
+#endif /* CONFIG_WPS_STRICT */
+
        /* Go through the IEs and make a copy of the MDIE, if present. */
        while (p && l >= 2) {
                len = p[1] + 2;
@@ -1175,6 +1350,14 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
        if (wpa_found || rsn_found)
                wpa_s->ap_ies_from_associnfo = 1;
 
+       if (wpa_s->assoc_freq && data->assoc_info.freq &&
+           wpa_s->assoc_freq != data->assoc_info.freq) {
+               wpa_printf(MSG_DEBUG, "Operating frequency changed from "
+                          "%u to %u MHz",
+                          wpa_s->assoc_freq, data->assoc_info.freq);
+               wpa_supplicant_update_scan_results(wpa_s);
+       }
+
        wpa_s->assoc_freq = data->assoc_info.freq;
 
        return 0;
@@ -1194,7 +1377,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                hostapd_notif_assoc(wpa_s->ap_iface->bss[0],
                                    data->assoc_info.addr,
                                    data->assoc_info.req_ies,
-                                   data->assoc_info.req_ies_len);
+                                   data->assoc_info.req_ies_len,
+                                   data->assoc_info.reassoc);
                return;
        }
 #endif /* CONFIG_AP */
@@ -1204,23 +1388,23 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
         * 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;
 
        wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
-       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-               os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
-       if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) ||
-           (wpa_drv_get_bssid(wpa_s, bssid) >= 0 &&
-            os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0)) {
-               wpa_msg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID="
+       if (wpa_drv_get_bssid(wpa_s, bssid) >= 0 &&
+           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);
@@ -1304,6 +1488,23 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
                eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
                eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+       } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
+                  wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
+               /*
+                * The driver will take care of RSN 4-way handshake, so we need
+                * to allow EAPOL supplicant to complete its work without
+                * waiting for WPA supplicant.
+                */
+               eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+       } else if (ft_completed) {
+               /*
+                * FT protocol completed - make sure EAPOL state machine ends
+                * up in authenticated.
+                */
+               wpa_supplicant_cancel_auth_timeout(wpa_s);
+               wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+               eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+               eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
        }
 
        if (wpa_s->pending_eapol_rx) {
@@ -1313,9 +1514,9 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                if (age.sec == 0 && age.usec < 100000 &&
                    os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) ==
                    0) {
-                       wpa_printf(MSG_DEBUG, "Process pending EAPOL frame "
-                                  "that was received just before association "
-                                  "notification");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "Process pending EAPOL "
+                               "frame that was received just before "
+                               "association notification");
                        wpa_supplicant_rx_eapol(
                                wpa_s, wpa_s->pending_eapol_rx_src,
                                wpabuf_head(wpa_s->pending_eapol_rx),
@@ -1325,25 +1526,6 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                wpa_s->pending_eapol_rx = NULL;
        }
 
-#ifdef CONFIG_BGSCAN
-       if (wpa_s->current_ssid != wpa_s->bgscan_ssid) {
-               bgscan_deinit(wpa_s);
-               if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan) {
-                       if (bgscan_init(wpa_s, wpa_s->current_ssid)) {
-                               wpa_printf(MSG_DEBUG, "Failed to initialize "
-                                          "bgscan");
-                               /*
-                                * Live without bgscan; it is only used as a
-                                * roaming optimization, so the initial
-                                * connection is not affected.
-                                */
-                       } else
-                               wpa_s->bgscan_ssid = wpa_s->current_ssid;
-               } else
-                       wpa_s->bgscan_ssid = NULL;
-       }
-#endif /* CONFIG_BGSCAN */
-
        if ((wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
             wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
            wpa_s->current_ssid && wpa_drv_get_capa(wpa_s, &capa) == 0 &&
@@ -1351,26 +1533,80 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                /* Set static WEP keys again */
                wpa_set_wep_keys(wpa_s, wpa_s->current_ssid);
        }
+
+#ifdef CONFIG_IBSS_RSN
+       if (wpa_s->current_ssid &&
+           wpa_s->current_ssid->mode == WPAS_MODE_IBSS &&
+           wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
+           wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE &&
+           wpa_s->ibss_rsn == NULL) {
+               wpa_s->ibss_rsn = ibss_rsn_init(wpa_s);
+               if (!wpa_s->ibss_rsn) {
+                       wpa_msg(wpa_s, MSG_INFO, "Failed to init IBSS RSN");
+                       wpa_supplicant_deauthenticate(
+                               wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+                       return;
+               }
+
+               ibss_rsn_set_psk(wpa_s->ibss_rsn, wpa_s->current_ssid->psk);
+       }
+#endif /* CONFIG_IBSS_RSN */
 }
 
 
+static int disconnect_reason_recoverable(u16 reason_code)
+{
+       return reason_code == WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY ||
+               reason_code == WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA ||
+               reason_code == WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
+}
+
+/*
+ * 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)
+{
+       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_event_disassoc(struct wpa_supplicant *wpa_s,
                                          u16 reason_code)
 {
-       /*
-        * Oct, 26th. 2011. TIZEN
-        * A wps variable is added for check enabled networks is set for WPS
-        */
-       int wps = 0;
-
        const u8 *bssid;
-#ifdef CONFIG_SME
        int authenticating;
        u8 prev_pending_bssid[ETH_ALEN];
+       struct wpa_bss *fast_reconnect = NULL;
+       struct wpa_ssid *fast_reconnect_ssid = NULL;
 
        authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING;
        os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN);
-#endif /* CONFIG_SME */
 
        if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
                /*
@@ -1378,104 +1614,104 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
                 * generating streams of disconnected events when configuring
                 * IBSS for WPA-None. Ignore them for now.
                 */
-               wpa_printf(MSG_DEBUG, "Disconnect event - ignore in "
-                          "IBSS/WPA-None mode");
+               wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - ignore in "
+                       "IBSS/WPA-None mode");
                return;
        }
 
-#if 0
        if (wpa_s->wpa_state == WPA_4WAY_HANDSHAKE &&
            wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
                wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
                        "pre-shared key may be incorrect");
        }
-       if (wpa_s->wpa_state >= WPA_ASSOCIATED)
-               wpa_supplicant_req_scan(wpa_s, 0, 100000);
-#else
-       /*
-        * September, 29th 2011. TIZEN
-        *
-        * Because connman doesn't know authenticate fail
-        * thus connman doesn't try to deauthenticate
-        * We insert followings forcefully
-        */
-
-       if (wpa_s->wpa_state == WPA_4WAY_HANDSHAKE &&
-           wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
-               wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
-                       "pre-shared key may be incorrect");
-       }
-#endif
-
-       /*
-        * Oct, 26th. 2011. TIZEN
-        * A wps variable is added for check enabled networks is set for WPS
-        */
-       wps = wpas_wps_in_use_events(wpa_s->conf);
-
-       if (wps == 0) {
-               struct wpa_ssid *start = wpa_s->conf->ssid;
-               if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-                       ieee80211_sta_deauthenticate(wpa_s, reason_code);
+       if (!wpa_s->auto_reconnect_disabled ||
+           wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect enabled: try to "
+                       "reconnect (wps=%d wpa_state=%d)",
+                       wpa_s->key_mgmt == WPA_KEY_MGMT_WPS,
+                       wpa_s->wpa_state);
+               if (wpa_s->wpa_state == WPA_COMPLETED &&
+                   wpa_s->current_ssid &&
+                   wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
+                   disconnect_reason_recoverable(reason_code)) {
+                       /*
+                        * It looks like the AP has dropped association with
+                        * us, but could allow us to get back in. Try to
+                        * reconnect to the same BSS without full scan to save
+                        * time for some common cases.
+                        */
+                       fast_reconnect = wpa_s->current_bss;
+                       fast_reconnect_ssid = wpa_s->current_ssid;
+               } else if (wpa_s->wpa_state >= WPA_ASSOCIATING)
+                       wpa_supplicant_req_scan(wpa_s, 0, 100000);
                else
-                       wpa_drv_deauthenticate(wpa_s, wpa_s->bssid,
-                                                  reason_code);
-               wpa_s->current_ssid = NULL;
-               wpa_s->current_bss = NULL;
+                       wpa_dbg(wpa_s, MSG_DEBUG, "Do not request new "
+                                       "immediate scan");
+       } else {
+               wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect disabled: do not "
+                               "try to re-connect");
                wpa_s->reassociate = 0;
                wpa_s->disconnected = 1;
-               while (start) {
-                       start->scan_ssid = 0;
-                       start = start->next;
-               }
+               /*
+                * 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.
+                */
 
-               wpa_supplicant_cancel_auth_timeout(wpa_s);
+               /*
+                * Start
+                */
+#if defined TIZEN_EXT
+               wpa_supplicant_unset_scan_ssid(wpa_s);
+               wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED);
+               /*
+                * Finish
+                */
+#endif
        }
-       /***********************************************/
-
        bssid = wpa_s->bssid;
        if (is_zero_ether_addr(bssid))
                bssid = wpa_s->pending_bssid;
-       wpa_blacklist_add(wpa_s, bssid);
+       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 (wpa_supplicant_dynamic_keys(wpa_s)) {
-               wpa_printf(MSG_DEBUG, "Disconnect event - remove keys");
+               wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - remove keys");
                wpa_s->keys_cleared = 0;
                wpa_clear_keys(wpa_s, wpa_s->bssid);
        }
        wpa_supplicant_mark_disassoc(wpa_s);
-       bgscan_deinit(wpa_s);
-       wpa_s->bgscan_ssid = NULL;
-#ifdef CONFIG_SME
-       if (authenticating &&
-           (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) {
-               /*
-                * mac80211-workaround to force deauth on failed auth cmd,
-                * requires us to remain in authenticating state to allow the
-                * second authentication attempt to be continued properly.
-                */
-               wpa_printf(MSG_DEBUG, "SME: Allow pending authentication to "
-                          "proceed after disconnection event");
-               wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
-               os_memcpy(wpa_s->pending_bssid, prev_pending_bssid, ETH_ALEN);
+
+       if (authenticating && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
+               sme_disassoc_while_authenticating(wpa_s, prev_pending_bssid);
+
+       if (fast_reconnect) {
+#ifndef CONFIG_NO_SCAN_PROCESSING
+               wpa_dbg(wpa_s, MSG_DEBUG, "Try to reconnect to the same BSS");
+               if (wpa_supplicant_connect(wpa_s, fast_reconnect,
+                                          fast_reconnect_ssid) < 0) {
+                       /* Recover through full scan */
+                       wpa_supplicant_req_scan(wpa_s, 0, 100000);
+               }
+#endif /* CONFIG_NO_SCAN_PROCESSING */
        }
-#endif /* CONFIG_SME */
 }
 
 
 #ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
-static void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx,
-                                                   void *sock_ctx)
+void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx)
 {
        struct wpa_supplicant *wpa_s = eloop_ctx;
 
        if (!wpa_s->pending_mic_error_report)
                return;
 
-       wpa_printf(MSG_DEBUG, "WPA: Sending pending MIC error report");
+       wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Sending pending MIC error report");
        wpa_sm_key_request(wpa_s->wpa, 1, wpa_s->pending_mic_error_pairwise);
        wpa_s->pending_mic_error_report = 0;
 }
@@ -1550,8 +1786,8 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
                                sec = os_random() % 60;
                        else
                                sec = WPA_GET_BE32(rval) % 60;
-                       wpa_printf(MSG_DEBUG, "WPA: Delay MIC error report %d "
-                                  "seconds", sec);
+                       wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Delay MIC error "
+                               "report %d seconds", sec);
                        wpa_s->pending_mic_error_report = 1;
                        wpa_s->pending_mic_error_pairwise = pairwise;
                        eloop_cancel_timeout(
@@ -1598,18 +1834,22 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
                if (!wpa_s->interface_removed)
                        break;
                wpa_s->interface_removed = 0;
-               wpa_printf(MSG_DEBUG, "Configured interface was added.");
+               wpa_dbg(wpa_s, MSG_DEBUG, "Configured interface was added");
                if (wpa_supplicant_driver_init(wpa_s) < 0) {
-                       wpa_printf(MSG_INFO, "Failed to initialize the driver "
-                                  "after interface was added.");
+                       wpa_msg(wpa_s, MSG_INFO, "Failed to initialize the "
+                               "driver after interface was added");
                }
                break;
        case EVENT_INTERFACE_REMOVED:
-               wpa_printf(MSG_DEBUG, "Configured interface was removed.");
+               wpa_dbg(wpa_s, MSG_DEBUG, "Configured interface was removed");
                wpa_s->interface_removed = 1;
                wpa_supplicant_mark_disassoc(wpa_s);
                l2_packet_deinit(wpa_s->l2);
                wpa_s->l2 = NULL;
+#ifdef CONFIG_IBSS_RSN
+               ibss_rsn_deinit(wpa_s->ibss_rsn);
+               wpa_s->ibss_rsn = NULL;
+#endif /* CONFIG_IBSS_RSN */
 #ifdef CONFIG_TERMINATE_ONLASTIF
                /* check if last interface */
                if (!any_interfaces(wpa_s->global->ifaces))
@@ -1632,6 +1872,25 @@ wpa_supplicant_event_stkstart(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_PEERKEY */
 
 
+#ifdef CONFIG_TDLS
+static void wpa_supplicant_event_tdls(struct wpa_supplicant *wpa_s,
+                                     union wpa_event_data *data)
+{
+       if (data == NULL)
+               return;
+       switch (data->tdls.oper) {
+       case TDLS_REQUEST_SETUP:
+               wpa_tdls_start(wpa_s->wpa, data->tdls.peer);
+               break;
+       case TDLS_REQUEST_TEARDOWN:
+               wpa_tdls_send_teardown(wpa_s->wpa, data->tdls.peer,
+                                      data->tdls.reason_code);
+               break;
+       }
+}
+#endif /* CONFIG_TDLS */
+
+
 #ifdef CONFIG_IEEE80211R
 static void
 wpa_supplicant_event_ft_response(struct wpa_supplicant *wpa_s,
@@ -1656,8 +1915,17 @@ wpa_supplicant_event_ft_response(struct wpa_supplicant *wpa_s,
 static void wpa_supplicant_event_ibss_rsn_start(struct wpa_supplicant *wpa_s,
                                                union wpa_event_data *data)
 {
+       struct wpa_ssid *ssid;
+       if (wpa_s->wpa_state < WPA_ASSOCIATED)
+               return;
        if (data == NULL)
                return;
+       ssid = wpa_s->current_ssid;
+       if (ssid == NULL)
+               return;
+       if (ssid->mode != WPAS_MODE_IBSS || !wpa_key_mgmt_wpa(ssid->key_mgmt))
+               return;
+
        ibss_rsn_start(wpa_s->ibss_rsn, data->ibss_rsn_start.peer);
 }
 #endif /* CONFIG_IBSS_RSN */
@@ -1680,19 +1948,19 @@ static void ft_rx_action(struct wpa_supplicant *wpa_s, const u8 *data,
        sta_addr = data + 1;
        target_ap_addr = data + 1 + ETH_ALEN;
        status = WPA_GET_LE16(data + 1 + 2 * ETH_ALEN);
-       wpa_printf(MSG_DEBUG, "FT: Received FT Action Response: STA " MACSTR
-                  " TargetAP " MACSTR " status %u",
-                  MAC2STR(sta_addr), MAC2STR(target_ap_addr), status);
+       wpa_dbg(wpa_s, MSG_DEBUG, "FT: Received FT Action Response: STA "
+               MACSTR " TargetAP " MACSTR " status %u",
+               MAC2STR(sta_addr), MAC2STR(target_ap_addr), status);
 
        if (os_memcmp(sta_addr, wpa_s->own_addr, ETH_ALEN) != 0) {
-               wpa_printf(MSG_DEBUG, "FT: Foreign STA Address " MACSTR
-                          " in FT Action Response", MAC2STR(sta_addr));
+               wpa_dbg(wpa_s, MSG_DEBUG, "FT: Foreign STA Address " MACSTR
+                       " in FT Action Response", MAC2STR(sta_addr));
                return;
        }
 
        if (status) {
-               wpa_printf(MSG_DEBUG, "FT: FT Action Response indicates "
-                          "failure (status code %d)", status);
+               wpa_dbg(wpa_s, MSG_DEBUG, "FT: FT Action Response indicates "
+                       "failure (status code %d)", status);
                /* TODO: report error to FT code(?) */
                return;
        }
@@ -1717,12 +1985,111 @@ static void ft_rx_action(struct wpa_supplicant *wpa_s, const u8 *data,
 #endif /* CONFIG_IEEE80211R */
 
 
+static void wpa_supplicant_event_unprot_deauth(struct wpa_supplicant *wpa_s,
+                                              struct unprot_deauth *e)
+{
+#ifdef CONFIG_IEEE80211W
+       wpa_printf(MSG_DEBUG, "Unprotected Deauthentication frame "
+                  "dropped: " MACSTR " -> " MACSTR
+                  " (reason code %u)",
+                  MAC2STR(e->sa), MAC2STR(e->da), e->reason_code);
+       sme_event_unprot_disconnect(wpa_s, e->sa, e->da, e->reason_code);
+#endif /* CONFIG_IEEE80211W */
+}
+
+
+static void wpa_supplicant_event_unprot_disassoc(struct wpa_supplicant *wpa_s,
+                                                struct unprot_disassoc *e)
+{
+#ifdef CONFIG_IEEE80211W
+       wpa_printf(MSG_DEBUG, "Unprotected Disassociation frame "
+                  "dropped: " MACSTR " -> " MACSTR
+                  " (reason code %u)",
+                  MAC2STR(e->sa), MAC2STR(e->da), e->reason_code);
+       sme_event_unprot_disconnect(wpa_s, e->sa, e->da, e->reason_code);
+#endif /* CONFIG_IEEE80211W */
+}
+
+
+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;
 
+       if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED &&
+           event != EVENT_INTERFACE_ENABLED &&
+           event != EVENT_INTERFACE_STATUS) {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "Ignore event %s (%d) while interface is disabled",
+                       event_to_string(event), event);
+               return;
+       }
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+{
+       int level = MSG_DEBUG;
+
+       if (event == EVENT_RX_MGMT && data && data->rx_mgmt.frame &&
+           data->rx_mgmt.frame_len >= 24) {
+               const struct ieee80211_hdr *hdr;
+               u16 fc;
+               hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
+               fc = le_to_host16(hdr->frame_control);
+               if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+                   WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
+                       level = MSG_EXCESSIVE;
+       }
+
+       wpa_dbg(wpa_s, level, "Event %s (%d) received",
+               event_to_string(event), event);
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
        switch (event) {
        case EVENT_AUTH:
                sme_event_auth(wpa_s, data);
@@ -1731,14 +2098,15 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                wpa_supplicant_event_assoc(wpa_s, data);
                break;
        case EVENT_DISASSOC:
-               wpa_printf(MSG_DEBUG, "Disassociation notification");
-       /*
-        * Oct, 26th. 2011. TIZEN
-        * If wps is completed, broadcom 4330, 4329 driver send disassoc event.
-        * Therefore, wps association trying with credential is failed.
-        */
-               if (wpa_s->after_wps != 0)
-                       break;
+               wpa_dbg(wpa_s, MSG_DEBUG, "Disassociation notification");
+
+               if (data) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u",
+                               data->disassoc_info.reason_code);
+                       if (data->disassoc_info.addr)
+                               wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR,
+                                       MAC2STR(data->disassoc_info.addr));
+               }
 #ifdef CONFIG_AP
                if (wpa_s->ap_iface && data && data->disassoc_info.addr) {
                        hostapd_notif_disassoc(wpa_s->ap_iface->bss[0],
@@ -1746,16 +2114,47 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                        break;
                }
 #endif /* CONFIG_AP */
-               if (data)
-                       reason_code = data->deauth_info.reason_code;
+               if (data) {
+                       reason_code = data->disassoc_info.reason_code;
+                       wpa_hexdump(MSG_DEBUG, "Disassociation frame IE(s)",
+                                   data->disassoc_info.ie,
+                                   data->disassoc_info.ie_len);
+#ifdef CONFIG_P2P
+                       wpas_p2p_disassoc_notif(
+                               wpa_s, data->disassoc_info.addr, reason_code,
+                               data->disassoc_info.ie,
+                               data->disassoc_info.ie_len);
+#endif /* CONFIG_P2P */
+               }
                if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
                        sme_event_disassoc(wpa_s, data);
                /* fall through */
        case EVENT_DEAUTH:
                if (event == EVENT_DEAUTH) {
-                       wpa_printf(MSG_DEBUG, "Deauthentication notification");
-                       if (data)
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "Deauthentication notification");
+                       if (data) {
                                reason_code = data->deauth_info.reason_code;
+                               wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u",
+                                       data->deauth_info.reason_code);
+                               if (data->deauth_info.addr) {
+                                       wpa_dbg(wpa_s, MSG_DEBUG, " * address "
+                                               MACSTR,
+                                               MAC2STR(data->deauth_info.
+                                                       addr));
+                               }
+                               wpa_hexdump(MSG_DEBUG,
+                                           "Deauthentication frame IE(s)",
+                                           data->deauth_info.ie,
+                                           data->deauth_info.ie_len);
+#ifdef CONFIG_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 */
+                       }
                }
 #ifdef CONFIG_AP
                if (wpa_s->ap_iface && data && data->deauth_info.addr) {
@@ -1788,6 +2187,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                wpa_supplicant_event_stkstart(wpa_s, data);
                break;
 #endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_TDLS
+       case EVENT_TDLS:
+               wpa_supplicant_event_tdls(wpa_s, data);
+               break;
+#endif /* CONFIG_TDLS */
 #ifdef CONFIG_IEEE80211R
        case EVENT_FT_RESPONSE:
                wpa_supplicant_event_ft_response(wpa_s, data);
@@ -1799,18 +2203,69 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                break;
 #endif /* CONFIG_IBSS_RSN */
        case EVENT_ASSOC_REJECT:
-               sme_event_assoc_reject(wpa_s, data);
+               if (data->assoc_reject.bssid)
+                       wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
+                               "bssid=" MACSTR " status_code=%u",
+                               MAC2STR(data->assoc_reject.bssid),
+                               data->assoc_reject.status_code);
+               else
+                       wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
+                               "status_code=%u",
+                               data->assoc_reject.status_code);
+               if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+                       sme_event_assoc_reject(wpa_s, data);
                break;
        case EVENT_AUTH_TIMED_OUT:
-               sme_event_auth_timed_out(wpa_s, data);
+               if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+                       sme_event_auth_timed_out(wpa_s, data);
                break;
        case EVENT_ASSOC_TIMED_OUT:
-               sme_event_assoc_timed_out(wpa_s, data);
+               if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+                       sme_event_assoc_timed_out(wpa_s, data);
                break;
-#ifdef CONFIG_AP
        case EVENT_TX_STATUS:
-               if (wpa_s->ap_iface == NULL)
+               wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS dst=" MACSTR
+                       " type=%d stype=%d",
+                       MAC2STR(data->tx_status.dst),
+                       data->tx_status.type, data->tx_status.stype);
+#ifdef CONFIG_AP
+               if (wpa_s->ap_iface == NULL) {
+#ifdef CONFIG_OFFCHANNEL
+                       if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
+                           data->tx_status.stype == WLAN_FC_STYPE_ACTION)
+                               offchannel_send_action_tx_status(
+                                       wpa_s, data->tx_status.dst,
+                                       data->tx_status.data,
+                                       data->tx_status.data_len,
+                                       data->tx_status.ack ?
+                                       OFFCHANNEL_SEND_ACTION_SUCCESS :
+                                       OFFCHANNEL_SEND_ACTION_NO_ACK);
+#endif /* CONFIG_OFFCHANNEL */
+                       break;
+               }
+#endif /* CONFIG_AP */
+#ifdef CONFIG_OFFCHANNEL
+               wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS pending_dst="
+                       MACSTR, MAC2STR(wpa_s->parent->pending_action_dst));
+               /*
+                * Catch TX status events for Action frames we sent via group
+                * interface in GO mode.
+                */
+               if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
+                   data->tx_status.stype == WLAN_FC_STYPE_ACTION &&
+                   os_memcmp(wpa_s->parent->pending_action_dst,
+                             data->tx_status.dst, ETH_ALEN) == 0) {
+                       offchannel_send_action_tx_status(
+                               wpa_s->parent, data->tx_status.dst,
+                               data->tx_status.data,
+                               data->tx_status.data_len,
+                               data->tx_status.ack ?
+                               OFFCHANNEL_SEND_ACTION_SUCCESS :
+                               OFFCHANNEL_SEND_ACTION_NO_ACK);
                        break;
+               }
+#endif /* CONFIG_OFFCHANNEL */
+#ifdef CONFIG_AP
                switch (data->tx_status.type) {
                case WLAN_FC_TYPE_MGMT:
                        ap_mgmt_tx_cb(wpa_s, data->tx_status.data,
@@ -1825,25 +2280,58 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                     data->tx_status.ack);
                        break;
                }
+#endif /* CONFIG_AP */
+               break;
+#ifdef CONFIG_AP
+       case EVENT_EAPOL_TX_STATUS:
+               ap_eapol_tx_status(wpa_s, data->eapol_tx_status.dst,
+                                  data->eapol_tx_status.data,
+                                  data->eapol_tx_status.data_len,
+                                  data->eapol_tx_status.ack);
+               break;
+       case EVENT_DRIVER_CLIENT_POLL_OK:
+               ap_client_poll_ok(wpa_s, data->client_poll.addr);
                break;
        case EVENT_RX_FROM_UNKNOWN:
                if (wpa_s->ap_iface == NULL)
                        break;
-               ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.frame,
-                                      data->rx_from_unknown.len);
+               ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.addr,
+                                      data->rx_from_unknown.wds);
                break;
        case EVENT_RX_MGMT:
-               if (wpa_s->ap_iface == NULL)
+               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;
+                               const u8 *ie = mgmt->u.probe_req.variable;
+                               size_t ie_len = data->rx_mgmt.frame_len -
+                                       (mgmt->u.probe_req.variable -
+                                        data->rx_mgmt.frame);
+                               wpas_p2p_probe_req_rx(wpa_s, src, mgmt->da,
+                                                     mgmt->bssid, ie, ie_len);
+                               break;
+                       }
+#endif /* CONFIG_P2P */
+                       wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received "
+                               "management frame in non-AP mode");
                        break;
+               }
                ap_mgmt_rx(wpa_s, &data->rx_mgmt);
                break;
 #endif /* CONFIG_AP */
        case EVENT_RX_ACTION:
-               wpa_printf(MSG_DEBUG, "Received Action frame: SA=" MACSTR
-                          " Category=%u DataLen=%d freq=%d MHz",
-                          MAC2STR(data->rx_action.sa),
-                          data->rx_action.category, (int) data->rx_action.len,
-                          data->rx_action.freq);
+               wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR
+                       " Category=%u DataLen=%d freq=%d MHz",
+                       MAC2STR(data->rx_action.sa),
+                       data->rx_action.category, (int) data->rx_action.len,
+                       data->rx_action.freq);
 #ifdef CONFIG_IEEE80211R
                if (data->rx_action.category == WLAN_ACTION_FT) {
                        ft_rx_action(wpa_s, data->rx_action.data,
@@ -1851,19 +2339,157 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                        break;
                }
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+#ifdef CONFIG_SME
+               if (data->rx_action.category == WLAN_ACTION_SA_QUERY) {
+                       sme_sa_query_rx(wpa_s, data->rx_action.sa,
+                                       data->rx_action.data,
+                                       data->rx_action.len);
+                       break;
+               }
+#endif /* CONFIG_SME */
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_GAS
+               if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
+                   gas_query_rx(wpa_s->gas, data->rx_action.da,
+                                data->rx_action.sa, data->rx_action.bssid,
+                                data->rx_action.data, data->rx_action.len,
+                                data->rx_action.freq) == 0)
+                       break;
+#endif /* CONFIG_GAS */
+               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 &&
+                   data->rx_action.data[0] == WLAN_TDLS_DISCOVERY_RESPONSE) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "TDLS: Received Discovery "
+                               "Response from " MACSTR,
+                               MAC2STR(data->rx_action.sa));
+                       break;
+               }
+#endif /* CONFIG_TDLS */
+#ifdef CONFIG_P2P
+               wpas_p2p_rx_action(wpa_s, data->rx_action.da,
+                                  data->rx_action.sa,
+                                  data->rx_action.bssid,
+                                  data->rx_action.category,
+                                  data->rx_action.data,
+                                  data->rx_action.len, data->rx_action.freq);
+#endif /* CONFIG_P2P */
+               break;
+       case EVENT_RX_PROBE_REQ:
+               if (data->rx_probe_req.sa == NULL ||
+                   data->rx_probe_req.ie == NULL)
+                       break;
+#ifdef CONFIG_AP
+               if (wpa_s->ap_iface) {
+                       hostapd_probe_req_rx(wpa_s->ap_iface->bss[0],
+                                            data->rx_probe_req.sa,
+                                            data->rx_probe_req.da,
+                                            data->rx_probe_req.bssid,
+                                            data->rx_probe_req.ie,
+                                            data->rx_probe_req.ie_len);
+                       break;
+               }
+#endif /* CONFIG_AP */
+#ifdef CONFIG_P2P
+               wpas_p2p_probe_req_rx(wpa_s, data->rx_probe_req.sa,
+                                     data->rx_probe_req.da,
+                                     data->rx_probe_req.bssid,
+                                     data->rx_probe_req.ie,
+                                     data->rx_probe_req.ie_len);
+#endif /* CONFIG_P2P */
                break;
-#ifdef CONFIG_CLIENT_MLME
-       case EVENT_MLME_RX: {
-               struct ieee80211_rx_status rx_status;
-               os_memset(&rx_status, 0, sizeof(rx_status));
-               rx_status.freq = data->mlme_rx.freq;
-               rx_status.channel = data->mlme_rx.channel;
-               rx_status.ssi = data->mlme_rx.ssi;
-               ieee80211_sta_rx(wpa_s, data->mlme_rx.buf, data->mlme_rx.len,
-                                &rx_status);
+       case EVENT_REMAIN_ON_CHANNEL:
+#ifdef CONFIG_OFFCHANNEL
+               offchannel_remain_on_channel_cb(
+                       wpa_s, data->remain_on_channel.freq,
+                       data->remain_on_channel.duration);
+#endif /* CONFIG_OFFCHANNEL */
+#ifdef CONFIG_P2P
+               wpas_p2p_remain_on_channel_cb(
+                       wpa_s, data->remain_on_channel.freq,
+                       data->remain_on_channel.duration);
+#endif /* CONFIG_P2P */
                break;
-       }
-#endif /* CONFIG_CLIENT_MLME */
+       case EVENT_CANCEL_REMAIN_ON_CHANNEL:
+#ifdef CONFIG_OFFCHANNEL
+               offchannel_cancel_remain_on_channel_cb(
+                       wpa_s, data->remain_on_channel.freq);
+#endif /* CONFIG_OFFCHANNEL */
+#ifdef CONFIG_P2P
+               wpas_p2p_cancel_remain_on_channel_cb(
+                       wpa_s, data->remain_on_channel.freq);
+#endif /* CONFIG_P2P */
+               break;
+#ifdef CONFIG_P2P
+       case EVENT_P2P_DEV_FOUND: {
+               struct p2p_peer_info peer_info;
+
+               os_memset(&peer_info, 0, sizeof(peer_info));
+               if (data->p2p_dev_found.dev_addr)
+                       os_memcpy(peer_info.p2p_device_addr,
+                                 data->p2p_dev_found.dev_addr, ETH_ALEN);
+               if (data->p2p_dev_found.pri_dev_type)
+                       os_memcpy(peer_info.pri_dev_type,
+                                 data->p2p_dev_found.pri_dev_type,
+                                 sizeof(peer_info.pri_dev_type));
+               if (data->p2p_dev_found.dev_name)
+                       os_strlcpy(peer_info.device_name,
+                                  data->p2p_dev_found.dev_name,
+                                  sizeof(peer_info.device_name));
+               peer_info.config_methods = data->p2p_dev_found.config_methods;
+               peer_info.dev_capab = data->p2p_dev_found.dev_capab;
+               peer_info.group_capab = data->p2p_dev_found.group_capab;
+
+               /*
+                * FIX: new_device=1 is not necessarily correct. We should
+                * maintain a P2P peer database in wpa_supplicant and update
+                * this information based on whether the peer is truly new.
+                */
+               wpas_dev_found(wpa_s, data->p2p_dev_found.addr, &peer_info, 1);
+               break;
+               }
+       case EVENT_P2P_GO_NEG_REQ_RX:
+               wpas_go_neg_req_rx(wpa_s, data->p2p_go_neg_req_rx.src,
+                                  data->p2p_go_neg_req_rx.dev_passwd_id);
+               break;
+       case EVENT_P2P_GO_NEG_COMPLETED:
+               wpas_go_neg_completed(wpa_s, data->p2p_go_neg_completed.res);
+               break;
+       case EVENT_P2P_PROV_DISC_REQUEST:
+               wpas_prov_disc_req(wpa_s, data->p2p_prov_disc_req.peer,
+                                  data->p2p_prov_disc_req.config_methods,
+                                  data->p2p_prov_disc_req.dev_addr,
+                                  data->p2p_prov_disc_req.pri_dev_type,
+                                  data->p2p_prov_disc_req.dev_name,
+                                  data->p2p_prov_disc_req.supp_config_methods,
+                                  data->p2p_prov_disc_req.dev_capab,
+                                  data->p2p_prov_disc_req.group_capab,
+                                  NULL, 0);
+               break;
+       case EVENT_P2P_PROV_DISC_RESPONSE:
+               wpas_prov_disc_resp(wpa_s, data->p2p_prov_disc_resp.peer,
+                                   data->p2p_prov_disc_resp.config_methods);
+               break;
+       case EVENT_P2P_SD_REQUEST:
+               wpas_sd_request(wpa_s, data->p2p_sd_req.freq,
+                               data->p2p_sd_req.sa,
+                               data->p2p_sd_req.dialog_token,
+                               data->p2p_sd_req.update_indic,
+                               data->p2p_sd_req.tlvs,
+                               data->p2p_sd_req.tlvs_len);
+               break;
+       case EVENT_P2P_SD_RESPONSE:
+               wpas_sd_response(wpa_s, data->p2p_sd_resp.sa,
+                                data->p2p_sd_resp.update_indic,
+                                data->p2p_sd_resp.tlvs,
+                                data->p2p_sd_resp.tlvs_len);
+               break;
+#endif /* CONFIG_P2P */
        case EVENT_EAPOL_RX:
                wpa_supplicant_rx_eapol(wpa_s, data->eapol_rx.src,
                                        data->eapol_rx.data,
@@ -1871,10 +2497,111 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                break;
        case EVENT_SIGNAL_CHANGE:
                bgscan_notify_signal_change(
-                       wpa_s, data->signal_change.above_threshold);
+                       wpa_s, data->signal_change.above_threshold,
+                       data->signal_change.current_signal,
+                       data->signal_change.current_noise,
+                       data->signal_change.current_txrate);
+               break;
+       case EVENT_INTERFACE_ENABLED:
+               wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
+               if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+                       wpa_supplicant_update_mac_addr(wpa_s);
+#ifdef CONFIG_AP
+                       if (!wpa_s->ap_iface) {
+                               wpa_supplicant_set_state(wpa_s,
+                                                        WPA_DISCONNECTED);
+                               wpa_supplicant_req_scan(wpa_s, 0, 0);
+                       } else
+                               wpa_supplicant_set_state(wpa_s,
+                                                        WPA_COMPLETED);
+#else /* CONFIG_AP */
+                       wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+                       wpa_supplicant_req_scan(wpa_s, 0, 0);
+#endif /* CONFIG_AP */
+               }
+               break;
+       case EVENT_INTERFACE_DISABLED:
+               wpa_dbg(wpa_s, MSG_DEBUG, "Interface was disabled");
+               wpa_supplicant_mark_disassoc(wpa_s);
+               wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
+               break;
+       case EVENT_CHANNEL_LIST_CHANGED:
+               if (wpa_s->drv_priv == NULL)
+                       break; /* Ignore event during drv initialization */
+#ifdef CONFIG_P2P
+               wpas_p2p_update_channel_list(wpa_s);
+#endif /* CONFIG_P2P */
+               break;
+       case EVENT_INTERFACE_UNAVAILABLE:
+#ifdef CONFIG_P2P
+               wpas_p2p_interface_unavailable(wpa_s);
+#endif /* CONFIG_P2P */
+               break;
+       case EVENT_BEST_CHANNEL:
+               wpa_dbg(wpa_s, MSG_DEBUG, "Best channel event received "
+                       "(%d %d %d)",
+                       data->best_chan.freq_24, data->best_chan.freq_5,
+                       data->best_chan.freq_overall);
+               wpa_s->best_24_freq = data->best_chan.freq_24;
+               wpa_s->best_5_freq = data->best_chan.freq_5;
+               wpa_s->best_overall_freq = data->best_chan.freq_overall;
+#ifdef CONFIG_P2P
+               wpas_p2p_update_best_channels(wpa_s, data->best_chan.freq_24,
+                                             data->best_chan.freq_5,
+                                             data->best_chan.freq_overall);
+#endif /* CONFIG_P2P */
+               break;
+       case EVENT_UNPROT_DEAUTH:
+               wpa_supplicant_event_unprot_deauth(wpa_s,
+                                                  &data->unprot_deauth);
+               break;
+       case EVENT_UNPROT_DISASSOC:
+               wpa_supplicant_event_unprot_disassoc(wpa_s,
+                                                    &data->unprot_disassoc);
+               break;
+       case EVENT_STATION_LOW_ACK:
+#ifdef CONFIG_AP
+               if (wpa_s->ap_iface && data)
+                       hostapd_event_sta_low_ack(wpa_s->ap_iface->bss[0],
+                                                 data->low_ack.addr);
+#endif /* CONFIG_AP */
+#ifdef CONFIG_TDLS
+               if (data)
+                       wpa_tdls_disable_link(wpa_s->wpa, data->low_ack.addr);
+#endif /* CONFIG_TDLS */
+               break;
+       case EVENT_IBSS_PEER_LOST:
+#ifdef CONFIG_IBSS_RSN
+               ibss_rsn_stop(wpa_s->ibss_rsn, data->ibss_peer_lost.peer);
+#endif /* CONFIG_IBSS_RSN */
+               break;
+       case EVENT_DRIVER_GTK_REKEY:
+               if (os_memcmp(data->driver_gtk_rekey.bssid,
+                             wpa_s->bssid, ETH_ALEN))
+                       break;
+               if (!wpa_s->wpa)
+                       break;
+               wpa_sm_update_replay_ctr(wpa_s->wpa,
+                                        data->driver_gtk_rekey.replay_ctr);
+               break;
+       case EVENT_SCHED_SCAN_STOPPED:
+               wpa_s->sched_scanning = 0;
+               wpa_supplicant_notify_scanning(wpa_s, 0);
+
+               /*
+                * If we timed out, start a new sched scan to continue
+                * searching for more SSIDs.
+                */
+               if (wpa_s->sched_scan_timed_out)
+                       wpa_supplicant_req_sched_scan(wpa_s);
+               break;
+       case EVENT_WPS_BUTTON_PUSHED:
+#ifdef CONFIG_WPS
+               wpas_wps_start_pbc(wpa_s, NULL, 0);
+#endif /* CONFIG_WPS */
                break;
        default:
-               wpa_printf(MSG_INFO, "Unknown event %d", event);
+               wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
                break;
        }
 }
diff --git a/wpa_supplicant/examples/p2p-action-udhcp.sh b/wpa_supplicant/examples/p2p-action-udhcp.sh
new file mode 100755 (executable)
index 0000000..d7d0e79
--- /dev/null
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+IFNAME=$1
+CMD=$2
+
+kill_daemon() {
+    NAME=$1
+    PF=$2
+
+    if [ ! -r $PF ]; then
+       return
+    fi
+
+    PID=`cat $PF`
+    if [ $PID -gt 0 ]; then
+       if ps $PID | grep -q $NAME; then
+           kill $PID
+       fi
+    fi
+    rm $PF
+}
+
+if [ "$CMD" = "P2P-GROUP-STARTED" ]; then
+    GIFNAME=$3
+    if [ "$4" = "GO" ]; then
+       kill_daemon udhcpc /var/run/udhcpc-$GIFNAME.pid
+       ifconfig $GIFNAME 192.168.42.1 up
+       udhcpd /etc/udhcpd-p2p.conf
+    fi
+    if [ "$4" = "client" ]; then
+       kill_daemon udhcpc /var/run/udhcpc-$GIFNAME.pid
+       kill_daemon udhcpd /var/run/udhcpd-$GIFNAME.pid
+       udhcpc -i $GIFNAME -p /var/run/udhcpc-$GIFNAME.pid \
+               -s /etc/udhcpc.script
+    fi
+fi
+
+if [ "$CMD" = "P2P-GROUP-REMOVED" ]; then
+    GIFNAME=$3
+    if [ "$4" = "GO" ]; then
+       kill_daemon udhcpd /var/run/udhcpd-$GIFNAME.pid
+       ifconfig $GIFNAME 0.0.0.0
+    fi
+    if [ "$4" = "client" ]; then
+       kill_daemon udhcpc /var/run/udhcpc-$GIFNAME.pid
+       ifconfig $GIFNAME 0.0.0.0
+    fi
+fi
+
+if [ "$CMD" = "P2P-CROSS-CONNECT-ENABLE" ]; then
+    GIFNAME=$3
+    UPLINK=$4
+    # enable NAT/masquarade $GIFNAME -> $UPLINK
+    iptables -P FORWARD DROP
+    iptables -t nat -A POSTROUTING -o $UPLINK -j MASQUERADE
+    iptables -A FORWARD -i $UPLINK -o $GIFNAME -m state --state RELATED,ESTABLISHED -j ACCEPT
+    iptables -A FORWARD -i $GIFNAME -o $UPLINK -j ACCEPT
+    sysctl net.ipv4.ip_forward=1
+fi
+
+if [ "$CMD" = "P2P-CROSS-CONNECT-DISABLE" ]; then
+    GIFNAME=$3
+    UPLINK=$4
+    # disable NAT/masquarade $GIFNAME -> $UPLINK
+    sysctl net.ipv4.ip_forward=0
+    iptables -t nat -D POSTROUTING -o $UPLINK -j MASQUERADE
+    iptables -D FORWARD -i $UPLINK -o $GIFNAME -m state --state RELATED,ESTABLISHED -j ACCEPT
+    iptables -D FORWARD -i $GIFNAME -o $UPLINK -j ACCEPT
+fi
diff --git a/wpa_supplicant/examples/p2p-action.sh b/wpa_supplicant/examples/p2p-action.sh
new file mode 100755 (executable)
index 0000000..8759f54
--- /dev/null
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+IFNAME=$1
+CMD=$2
+
+kill_daemon() {
+    NAME=$1
+    PF=$2
+
+    if [ ! -r $PF ]; then
+       return
+    fi
+
+    PID=`cat $PF`
+    if [ $PID -gt 0 ]; then
+       if ps $PID | grep -q $NAME; then
+           kill $PID
+       fi
+    fi
+    rm $PF
+}
+
+if [ "$CMD" = "P2P-GROUP-STARTED" ]; then
+    GIFNAME=$3
+    if [ "$4" = "GO" ]; then
+       kill_daemon dhclient /var/run/dhclient-$GIFNAME.pid
+       rm /var/run/dhclient.leases-$GIFNAME
+       kill_daemon dnsmasq /var/run/dnsmasq.pid-$GIFNAME
+       ifconfig $GIFNAME 192.168.42.1 up
+       if ! dnsmasq -x /var/run/dnsmasq.pid-$GIFNAME \
+           -i $GIFNAME \
+           -F192.168.42.11,192.168.42.99; then
+           # another dnsmasq instance may be running and blocking us; try to
+           # start with -z to avoid that
+           dnsmasq -x /var/run/dnsmasq.pid-$GIFNAME \
+               -i $GIFNAME \
+               -F192.168.42.11,192.168.42.99 --listen-address 192.168.42.1 -z
+       fi
+    fi
+    if [ "$4" = "client" ]; then
+       kill_daemon dhclient /var/run/dhclient-$GIFNAME.pid
+       rm /var/run/dhclient.leases-$GIFNAME
+       kill_daemon dnsmasq /var/run/dnsmasq.pid-$GIFNAME
+       dhclient -pf /var/run/dhclient-$GIFNAME.pid \
+           -lf /var/run/dhclient.leases-$GIFNAME \
+           -nw \
+           $GIFNAME
+    fi
+fi
+
+if [ "$CMD" = "P2P-GROUP-REMOVED" ]; then
+    GIFNAME=$3
+    if [ "$4" = "GO" ]; then
+       kill_daemon dnsmasq /var/run/dnsmasq.pid-$GIFNAME
+       ifconfig $GIFNAME 0.0.0.0
+    fi
+    if [ "$4" = "client" ]; then
+       kill_daemon dhclient /var/run/dhclient-$GIFNAME.pid
+       rm /var/run/dhclient.leases-$GIFNAME
+       ifconfig $GIFNAME 0.0.0.0
+    fi
+fi
+
+if [ "$CMD" = "P2P-CROSS-CONNECT-ENABLE" ]; then
+    GIFNAME=$3
+    UPLINK=$4
+    # enable NAT/masquarade $GIFNAME -> $UPLINK
+    iptables -P FORWARD DROP
+    iptables -t nat -A POSTROUTING -o $UPLINK -j MASQUERADE
+    iptables -A FORWARD -i $UPLINK -o $GIFNAME -m state --state RELATED,ESTABLISHED -j ACCEPT
+    iptables -A FORWARD -i $GIFNAME -o $UPLINK -j ACCEPT
+    sysctl net.ipv4.ip_forward=1
+fi
+
+if [ "$CMD" = "P2P-CROSS-CONNECT-DISABLE" ]; then
+    GIFNAME=$3
+    UPLINK=$4
+    # disable NAT/masquarade $GIFNAME -> $UPLINK
+    sysctl net.ipv4.ip_forward=0
+    iptables -t nat -D POSTROUTING -o $UPLINK -j MASQUERADE
+    iptables -D FORWARD -i $UPLINK -o $GIFNAME -m state --state RELATED,ESTABLISHED -j ACCEPT
+    iptables -D FORWARD -i $GIFNAME -o $UPLINK -j ACCEPT
+fi
diff --git a/wpa_supplicant/examples/udhcpd-p2p.conf b/wpa_supplicant/examples/udhcpd-p2p.conf
new file mode 100644 (file)
index 0000000..df59094
--- /dev/null
@@ -0,0 +1,120 @@
+# Sample udhcpd configuration file (/etc/udhcpd.conf)
+
+# The start and end of the IP lease block
+
+start          192.168.42.20   #default: 192.168.0.20
+end            192.168.42.254  #default: 192.168.0.254
+
+
+# The interface that udhcpd will use
+
+interface      wlan2           #default: eth0
+
+
+# The maximim number of leases (includes addressesd reserved
+# by OFFER's, DECLINE's, and ARP conficts
+
+#max_leases    254             #default: 254
+
+
+# If remaining is true (default), udhcpd will store the time
+# remaining for each lease in the udhcpd leases file. This is
+# for embedded systems that cannot keep time between reboots.
+# If you set remaining to no, the absolute time that the lease
+# expires at will be stored in the dhcpd.leases file.
+
+#remaining     yes             #default: yes
+
+
+# The time period at which udhcpd will write out a dhcpd.leases
+# file. If this is 0, udhcpd will never automatically write a
+# lease file. (specified in seconds)
+
+#auto_time     7200            #default: 7200 (2 hours)
+
+
+# The amount of time that an IP will be reserved (leased) for if a
+# DHCP decline message is received (seconds).
+
+#decline_time  3600            #default: 3600 (1 hour)
+
+
+# The amount of time that an IP will be reserved (leased) for if an
+# ARP conflct occurs. (seconds
+
+#conflict_time 3600            #default: 3600 (1 hour)
+
+
+# How long an offered address is reserved (leased) in seconds
+
+#offer_time    60              #default: 60 (1 minute)
+
+# If a lease to be given is below this value, the full lease time is
+# instead used (seconds).
+
+#min_lease     60              #defult: 60
+
+
+# The location of the leases file
+
+#lease_file    /var/lib/misc/udhcpd.leases     #defualt: /var/lib/misc/udhcpd.leases
+
+# The location of the pid file
+pidfile        /var/run/udhcpd-wlan2.pid       #default: /var/run/udhcpd.pid
+
+# Every time udhcpd writes a leases file, the below script will be called.
+# Useful for writing the lease file to flash every few hours.
+
+#notify_file                           #default: (no script)
+
+#notify_file   dumpleases      # <--- useful for debugging
+
+# The following are bootp specific options, setable by udhcpd.
+
+#siaddr                192.168.0.22            #default: 0.0.0.0
+
+#sname         zorak                   #default: (none)
+
+#boot_file     /var/nfs_root           #default: (none)
+
+# The remainer of options are DHCP options and can be specifed with the
+# keyword 'opt' or 'option'. If an option can take multiple items, such
+# as the dns option, they can be listed on the same line, or multiple
+# lines. The only option with a default is 'lease'.
+
+#Examles
+opt    dns     192.168.2.1
+option subnet  255.255.255.0
+option domain  atherosowl.com
+option lease   864000          # 10 days of seconds
+
+
+# Currently supported options, for more info, see options.c
+#opt subnet
+#opt timezone
+#opt router
+#opt timesvr
+#opt namesvr
+#opt dns
+#opt logsvr
+#opt cookiesvr
+#opt lprsvr
+#opt bootsize
+#opt domain
+#opt swapsvr
+#opt rootpath
+#opt ipttl
+#opt mtu
+#opt broadcast
+#opt wins
+#opt lease
+#opt ntpsrv
+#opt tftp
+#opt bootfile
+
+
+# Static leases map
+#static_lease 00:60:08:11:CE:4E 192.168.0.54
+#static_lease 00:60:08:11:CE:3E 192.168.0.44
+
+
diff --git a/wpa_supplicant/examples/wps-ap-cli b/wpa_supplicant/examples/wps-ap-cli
new file mode 100755 (executable)
index 0000000..7c6b0aa
--- /dev/null
@@ -0,0 +1,78 @@
+#!/bin/sh
+
+CLI=wpa_cli
+
+pbc()
+{
+       echo "Starting PBC mode"
+       echo "Push button on the station within two minutes"
+       if ! $CLI wps_pbc | grep -q OK; then
+               echo "Failed to enable PBC mode"
+       fi
+}
+
+enter_pin()
+{
+       echo "Enter a PIN from a station to be enrolled to the network."
+       read -p "Enrollee PIN: " pin
+       cpin=`$CLI wps_check_pin "$pin" | tail -1`
+       if [ "$cpin" = "FAIL-CHECKSUM" ]; then
+               echo "Checksum digit is not valid"
+               read -p "Do you want to use this PIN (y/n)? " resp
+               case "$resp" in
+                       y*)
+                               cpin=`echo "$pin" | sed "s/[^1234567890]//g"`
+                               ;;
+                       *)
+                               return 1
+                               ;;
+               esac
+       fi
+       if [ "$cpin" = "FAIL" ]; then
+               echo "Invalid PIN: $pin"
+               return 1
+       fi
+       echo "Enabling Enrollee PIN: $cpin"
+       $CLI wps_pin any "$cpin"
+}
+
+show_config()
+{
+       $CLI status wps
+}
+
+main_menu()
+{
+       echo "WPS AP"
+       echo "------"
+       echo "1: Push button (activate PBC)"
+       echo "2: Enter Enrollee PIN"
+       echo "3: Show current configuration"
+       echo "0: Exit wps-ap-cli"
+
+       read -p "Command: " cmd
+
+       case "$cmd" in
+               1)
+                       pbc
+                       ;;
+               2)
+                       enter_pin
+                       ;;
+               3)
+                       show_config
+                       ;;
+               0)
+                       exit 0
+                       ;;
+               *)
+                       echo "Unknown command: $cmd"
+                       ;;
+       esac
+
+       echo
+       main_menu
+}
+
+
+main_menu
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
new file mode 100644 (file)
index 0000000..3b736da
--- /dev/null
@@ -0,0 +1,481 @@
+/*
+ * Generic advertisement service (GAS) query
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "offchannel.h"
+#include "gas_query.h"
+
+
+#define GAS_QUERY_TIMEOUT 5
+
+
+struct gas_query_pending {
+       struct dl_list list;
+       u8 addr[ETH_ALEN];
+       u8 dialog_token;
+       u8 next_frag_id;
+       unsigned int wait_comeback:1;
+       unsigned int offchannel_tx_started:1;
+       int freq;
+       u16 status_code;
+       struct wpabuf *adv_proto;
+       struct wpabuf *resp;
+       void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
+                  enum gas_query_result result,
+                  const struct wpabuf *adv_proto,
+                  const struct wpabuf *resp, u16 status_code);
+       void *ctx;
+};
+
+struct gas_query {
+       struct wpa_supplicant *wpa_s;
+       struct dl_list pending; /* struct gas_query_pending */
+};
+
+
+static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx);
+static void gas_query_timeout(void *eloop_data, void *user_ctx);
+
+
+struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s)
+{
+       struct gas_query *gas;
+
+       gas = os_zalloc(sizeof(*gas));
+       if (gas == NULL)
+               return NULL;
+
+       gas->wpa_s = wpa_s;
+       dl_list_init(&gas->pending);
+
+       return gas;
+}
+
+
+static void gas_query_done(struct gas_query *gas,
+                          struct gas_query_pending *query,
+                          enum gas_query_result result)
+{
+       if (query->offchannel_tx_started)
+               offchannel_send_action_done(gas->wpa_s);
+       eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
+       eloop_cancel_timeout(gas_query_timeout, gas, query);
+       dl_list_del(&query->list);
+       query->cb(query->ctx, query->addr, query->dialog_token, result,
+                 query->adv_proto, query->resp, query->status_code);
+       wpabuf_free(query->adv_proto);
+       wpabuf_free(query->resp);
+       os_free(query);
+}
+
+
+void gas_query_deinit(struct gas_query *gas)
+{
+       struct gas_query_pending *query, *next;
+
+       if (gas == NULL)
+               return;
+
+       dl_list_for_each_safe(query, next, &gas->pending,
+                             struct gas_query_pending, list)
+               gas_query_done(gas, query, GAS_QUERY_DELETED_AT_DEINIT);
+
+       os_free(gas);
+}
+
+
+static struct gas_query_pending *
+gas_query_get_pending(struct gas_query *gas, const u8 *addr, u8 dialog_token)
+{
+       struct gas_query_pending *q;
+       dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) {
+               if (os_memcmp(q->addr, addr, ETH_ALEN) == 0 &&
+                   q->dialog_token == dialog_token)
+                       return q;
+       }
+       return NULL;
+}
+
+
+static int gas_query_append(struct gas_query_pending *query, const u8 *data,
+                           size_t len)
+{
+       if (wpabuf_resize(&query->resp, len) < 0) {
+               wpa_printf(MSG_DEBUG, "GAS: No memory to store the response");
+               return -1;
+       }
+       wpabuf_put_data(query->resp, data, len);
+       return 0;
+}
+
+
+static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query,
+                       struct wpabuf *req)
+{
+       int res;
+       wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u "
+                  "freq=%d", MAC2STR(query->addr),
+                  (unsigned int) wpabuf_len(req), query->freq);
+       res = offchannel_send_action(gas->wpa_s, query->freq, query->addr,
+                                    gas->wpa_s->own_addr, query->addr,
+                                    wpabuf_head(req), wpabuf_len(req), 1000,
+                                    NULL, 0);
+       if (res == 0)
+               query->offchannel_tx_started = 1;
+       return res;
+}
+
+
+static void gas_query_tx_comeback_req(struct gas_query *gas,
+                                     struct gas_query_pending *query)
+{
+       struct wpabuf *req;
+
+       req = gas_build_comeback_req(query->dialog_token);
+       if (req == NULL) {
+               gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
+               return;
+       }
+
+       if (gas_query_tx(gas, query, req) < 0) {
+               wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
+                          MACSTR, MAC2STR(query->addr));
+               gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
+       }
+
+       wpabuf_free(req);
+}
+
+
+static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx)
+{
+       struct gas_query *gas = eloop_data;
+       struct gas_query_pending *query = user_ctx;
+
+       wpa_printf(MSG_DEBUG, "GAS: Comeback timeout for request to " MACSTR,
+                  MAC2STR(query->addr));
+       gas_query_tx_comeback_req(gas, query);
+}
+
+
+static void gas_query_tx_comeback_req_delay(struct gas_query *gas,
+                                           struct gas_query_pending *query,
+                                           u16 comeback_delay)
+{
+       unsigned int secs, usecs;
+
+       secs = (comeback_delay * 1024) / 1000000;
+       usecs = comeback_delay * 1024 - secs * 1000000;
+       wpa_printf(MSG_DEBUG, "GAS: Send comeback request to " MACSTR
+                  " in %u secs %u usecs", MAC2STR(query->addr), secs, usecs);
+       eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
+       eloop_register_timeout(secs, usecs, gas_query_tx_comeback_timeout,
+                              gas, query);
+}
+
+
+static void gas_query_rx_initial(struct gas_query *gas,
+                                struct gas_query_pending *query,
+                                const u8 *adv_proto, const u8 *resp,
+                                size_t len, u16 comeback_delay)
+{
+       wpa_printf(MSG_DEBUG, "GAS: Received initial response from "
+                  MACSTR " (dialog_token=%u comeback_delay=%u)",
+                  MAC2STR(query->addr), query->dialog_token, comeback_delay);
+
+       query->adv_proto = wpabuf_alloc_copy(adv_proto, 2 + adv_proto[1]);
+       if (query->adv_proto == NULL) {
+               gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
+               return;
+       }
+
+       if (comeback_delay) {
+               query->wait_comeback = 1;
+               gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
+               return;
+       }
+
+       /* Query was completed without comeback mechanism */
+       if (gas_query_append(query, resp, len) < 0) {
+               gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
+               return;
+       }
+
+       gas_query_done(gas, query, GAS_QUERY_SUCCESS);
+}
+
+
+static void gas_query_rx_comeback(struct gas_query *gas,
+                                 struct gas_query_pending *query,
+                                 const u8 *adv_proto, const u8 *resp,
+                                 size_t len, u8 frag_id, u8 more_frags,
+                                 u16 comeback_delay)
+{
+       wpa_printf(MSG_DEBUG, "GAS: Received comeback response from "
+                  MACSTR " (dialog_token=%u frag_id=%u more_frags=%u "
+                  "comeback_delay=%u)",
+                  MAC2STR(query->addr), query->dialog_token, frag_id,
+                  more_frags, comeback_delay);
+
+       if ((size_t) 2 + adv_proto[1] != wpabuf_len(query->adv_proto) ||
+           os_memcmp(adv_proto, wpabuf_head(query->adv_proto),
+                     wpabuf_len(query->adv_proto)) != 0) {
+               wpa_printf(MSG_DEBUG, "GAS: Advertisement Protocol changed "
+                          "between initial and comeback response from "
+                          MACSTR, MAC2STR(query->addr));
+               gas_query_done(gas, query, GAS_QUERY_PEER_ERROR);
+               return;
+       }
+
+       if (comeback_delay) {
+               if (frag_id) {
+                       wpa_printf(MSG_DEBUG, "GAS: Invalid comeback response "
+                                  "with non-zero frag_id and comeback_delay "
+                                  "from " MACSTR, MAC2STR(query->addr));
+                       gas_query_done(gas, query, GAS_QUERY_PEER_ERROR);
+                       return;
+               }
+               gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
+               return;
+       }
+
+       if (frag_id != query->next_frag_id) {
+               wpa_printf(MSG_DEBUG, "GAS: Unexpected frag_id in response "
+                          "from " MACSTR, MAC2STR(query->addr));
+               gas_query_done(gas, query, GAS_QUERY_PEER_ERROR);
+               return;
+       }
+       query->next_frag_id++;
+
+       if (gas_query_append(query, resp, len) < 0) {
+               gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
+               return;
+       }
+
+       if (more_frags) {
+               gas_query_tx_comeback_req(gas, query);
+               return;
+       }
+
+       gas_query_done(gas, query, GAS_QUERY_SUCCESS);
+}
+
+
+int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
+                const u8 *bssid, const u8 *data, size_t len, int freq)
+{
+       struct gas_query_pending *query;
+       u8 action, dialog_token, frag_id = 0, more_frags = 0;
+       u16 comeback_delay, resp_len;
+       const u8 *pos, *adv_proto;
+
+       if (gas == NULL || len < 4)
+               return -1;
+
+       pos = data;
+       action = *pos++;
+       dialog_token = *pos++;
+
+       if (action != WLAN_PA_GAS_INITIAL_RESP &&
+           action != WLAN_PA_GAS_COMEBACK_RESP)
+               return -1; /* Not a GAS response */
+
+       query = gas_query_get_pending(gas, sa, dialog_token);
+       if (query == NULL) {
+               wpa_printf(MSG_DEBUG, "GAS: No pending query found for " MACSTR
+                          " dialog token %u", MAC2STR(sa), dialog_token);
+               return -1;
+       }
+
+       if (query->wait_comeback && action == WLAN_PA_GAS_INITIAL_RESP) {
+               wpa_printf(MSG_DEBUG, "GAS: Unexpected initial response from "
+                          MACSTR " dialog token %u when waiting for comeback "
+                          "response", MAC2STR(sa), dialog_token);
+               return 0;
+       }
+
+       if (!query->wait_comeback && action == WLAN_PA_GAS_COMEBACK_RESP) {
+               wpa_printf(MSG_DEBUG, "GAS: Unexpected comeback response from "
+                          MACSTR " dialog token %u when waiting for initial "
+                          "response", MAC2STR(sa), dialog_token);
+               return 0;
+       }
+
+       query->status_code = WPA_GET_LE16(pos);
+       pos += 2;
+
+       if (query->status_code != WLAN_STATUS_SUCCESS) {
+               wpa_printf(MSG_DEBUG, "GAS: Query to " MACSTR " dialog token "
+                          "%u failed - status code %u",
+                          MAC2STR(sa), dialog_token, query->status_code);
+               gas_query_done(gas, query, GAS_QUERY_FAILURE);
+               return 0;
+       }
+
+       if (action == WLAN_PA_GAS_COMEBACK_RESP) {
+               if (pos + 1 > data + len)
+                       return 0;
+               frag_id = *pos & 0x7f;
+               more_frags = (*pos & 0x80) >> 7;
+               pos++;
+       }
+
+       /* Comeback Delay */
+       if (pos + 2 > data + len)
+               return 0;
+       comeback_delay = WPA_GET_LE16(pos);
+       pos += 2;
+
+       /* Advertisement Protocol element */
+       if (pos + 2 > data + len || pos + 2 + pos[1] > data + len) {
+               wpa_printf(MSG_DEBUG, "GAS: No room for Advertisement "
+                          "Protocol element in the response from " MACSTR,
+                          MAC2STR(sa));
+               return 0;
+       }
+
+       if (*pos != WLAN_EID_ADV_PROTO) {
+               wpa_printf(MSG_DEBUG, "GAS: Unexpected Advertisement "
+                          "Protocol element ID %u in response from " MACSTR,
+                          *pos, MAC2STR(sa));
+               return 0;
+       }
+
+       adv_proto = pos;
+       pos += 2 + pos[1];
+
+       /* Query Response Length */
+       if (pos + 2 > data + len) {
+               wpa_printf(MSG_DEBUG, "GAS: No room for GAS Response Length");
+               return 0;
+       }
+       resp_len = WPA_GET_LE16(pos);
+       pos += 2;
+
+       if (pos + resp_len > data + len) {
+               wpa_printf(MSG_DEBUG, "GAS: Truncated Query Response in "
+                          "response from " MACSTR, MAC2STR(sa));
+               return 0;
+       }
+
+       if (pos + resp_len < data + len) {
+               wpa_printf(MSG_DEBUG, "GAS: Ignore %u octets of extra data "
+                          "after Query Response from " MACSTR,
+                          (unsigned int) (data + len - pos - resp_len),
+                          MAC2STR(sa));
+       }
+
+       if (action == WLAN_PA_GAS_COMEBACK_RESP)
+               gas_query_rx_comeback(gas, query, adv_proto, pos, resp_len,
+                                     frag_id, more_frags, comeback_delay);
+       else
+               gas_query_rx_initial(gas, query, adv_proto, pos, resp_len,
+                                    comeback_delay);
+
+       return 0;
+}
+
+
+static void gas_query_timeout(void *eloop_data, void *user_ctx)
+{
+       struct gas_query *gas = eloop_data;
+       struct gas_query_pending *query = user_ctx;
+
+       wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR,
+                  MAC2STR(query->addr));
+       gas_query_done(gas, query, GAS_QUERY_TIMEOUT);
+}
+
+
+static int gas_query_dialog_token_available(struct gas_query *gas,
+                                           const u8 *dst, u8 dialog_token)
+{
+       struct gas_query_pending *q;
+       dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) {
+               if (os_memcmp(dst, q->addr, ETH_ALEN) == 0 &&
+                   dialog_token == q->dialog_token)
+                       return 0;
+       }
+
+       return 1;
+}
+
+
+int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
+                 struct wpabuf *req,
+                 void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
+                            enum gas_query_result result,
+                            const struct wpabuf *adv_proto,
+                            const struct wpabuf *resp, u16 status_code),
+                 void *ctx)
+{
+       struct gas_query_pending *query;
+       int dialog_token;
+
+       if (wpabuf_len(req) < 3)
+               return -1;
+
+       for (dialog_token = 0; dialog_token < 256; dialog_token++) {
+               if (gas_query_dialog_token_available(gas, dst, dialog_token))
+                       break;
+       }
+       if (dialog_token == 256)
+               return -1; /* Too many pending queries */
+
+       query = os_zalloc(sizeof(*query));
+       if (query == NULL)
+               return -1;
+
+       os_memcpy(query->addr, dst, ETH_ALEN);
+       query->dialog_token = dialog_token;
+       query->freq = freq;
+       query->cb = cb;
+       query->ctx = ctx;
+       dl_list_add(&gas->pending, &query->list);
+
+       *(wpabuf_mhead_u8(req) + 2) = dialog_token;
+
+       wpa_printf(MSG_DEBUG, "GAS: Starting request for " MACSTR
+                  " dialog_token %u", MAC2STR(dst), dialog_token);
+       if (gas_query_tx(gas, query, req) < 0) {
+               wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
+                          MACSTR, MAC2STR(query->addr));
+               os_free(query);
+               return -1;
+       }
+
+       eloop_register_timeout(GAS_QUERY_TIMEOUT, 0, gas_query_timeout,
+                              gas, query);
+
+       return dialog_token;
+}
+
+
+void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token)
+{
+       struct gas_query_pending *query;
+
+       query = gas_query_get_pending(gas, dst, dialog_token);
+       if (query)
+               gas_query_done(gas, query, GAS_QUERY_CANCELLED);
+
+}
diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h
new file mode 100644 (file)
index 0000000..64c3825
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Generic advertisement service (GAS) query
+ * 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.
+ */
+
+#ifndef GAS_QUERY_H
+#define GAS_QUERY_H
+
+struct gas_query;
+
+#ifdef CONFIG_GAS
+
+struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s);
+void gas_query_deinit(struct gas_query *gas);
+int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
+                const u8 *bssid, const u8 *data, size_t len, int freq);
+
+enum gas_query_result {
+       GAS_QUERY_SUCCESS,
+       GAS_QUERY_FAILURE,
+       GAS_QUERY_TIMEOUT,
+       GAS_QUERY_PEER_ERROR,
+       GAS_QUERY_INTERNAL_ERROR,
+       GAS_QUERY_CANCELLED,
+       GAS_QUERY_DELETED_AT_DEINIT
+};
+
+int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
+                 struct wpabuf *req,
+                 void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
+                            enum gas_query_result result,
+                            const struct wpabuf *adv_proto,
+                            const struct wpabuf *resp, u16 status_code),
+                 void *ctx);
+void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token);
+
+#else /* CONFIG_GAS */
+
+static inline struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s)
+{
+       return (void *) 1;
+}
+
+static inline void gas_query_deinit(struct gas_query *gas)
+{
+}
+
+#endif /* CONFIG_GAS */
+
+
+#endif /* GAS_QUERY_H */
index 0e33253..d4fa39d 100644 (file)
@@ -39,6 +39,13 @@ static void supp_set_state(void *ctx, enum wpa_states state)
 }
 
 
+static enum wpa_states supp_get_state(void *ctx)
+{
+       struct ibss_rsn_peer *peer = ctx;
+       return peer->supp_state;
+}
+
+
 static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
                           size_t len)
 {
@@ -125,6 +132,8 @@ static int supp_set_key(void *ctx, enum wpa_alg alg,
                }
        }
 
+       if (is_broadcast_ether_addr(addr))
+               addr = peer->addr;
        return wpa_drv_set_key(peer->ibss_rsn->wpa_s, alg, addr, key_idx,
                               set_tx, seq, seq_len, key, key_len);
 }
@@ -153,8 +162,14 @@ static void supp_cancel_auth_timeout(void *ctx)
 }
 
 
-int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
-                      const u8 *psk)
+static void supp_deauthenticate(void * ctx, int reason_code)
+{
+       wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__);
+}
+
+
+static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
+                             const u8 *psk)
 {
        struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx));
        if (ctx == NULL)
@@ -163,6 +178,7 @@ int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
        ctx->ctx = peer;
        ctx->msg_ctx = peer->ibss_rsn->wpa_s;
        ctx->set_state = supp_set_state;
+       ctx->get_state = supp_get_state;
        ctx->ether_send = supp_ether_send;
        ctx->get_beacon_ie = supp_get_beacon_ie;
        ctx->alloc_eapol = supp_alloc_eapol;
@@ -170,6 +186,7 @@ int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
        ctx->get_network_ctx = supp_get_network_ctx;
        ctx->mlme_setprotection = supp_mlme_setprotection;
        ctx->cancel_auth_timeout = supp_cancel_auth_timeout;
+       ctx->deauthenticate = supp_deauthenticate;
        peer->supp = wpa_sm_init(ctx);
        if (peer->supp == NULL) {
                wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
@@ -273,6 +290,24 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
 }
 
 
+static int auth_for_each_sta(void *ctx, int (*cb)(struct wpa_state_machine *sm,
+                                                 void *ctx),
+                            void *cb_ctx)
+{
+       struct ibss_rsn *ibss_rsn = ctx;
+       struct ibss_rsn_peer *peer;
+
+       wpa_printf(MSG_DEBUG, "AUTH: for_each_sta");
+
+       for (peer = ibss_rsn->peers; peer; peer = peer->next) {
+               if (peer->auth && cb(peer->auth, cb_ctx))
+                       return 1;
+       }
+
+       return 0;
+}
+
+
 static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
                                    const u8 *own_addr)
 {
@@ -288,6 +323,7 @@ static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
        conf.rsn_pairwise = WPA_CIPHER_CCMP;
        conf.wpa_group = WPA_CIPHER_CCMP;
        conf.eapol_version = 2;
+       conf.wpa_group_rekey = 600;
 
        os_memset(&cb, 0, sizeof(cb));
        cb.ctx = ibss_rsn;
@@ -295,6 +331,7 @@ static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
        cb.send_eapol = auth_send_eapol;
        cb.get_psk = auth_get_psk;
        cb.set_key = auth_set_key;
+       cb.for_each_sta = auth_for_each_sta;
 
        ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb);
        if (ibss_rsn->auth_group == NULL) {
@@ -302,6 +339,8 @@ static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
                return -1;
        }
 
+       wpa_init_keys(ibss_rsn->auth_group);
+
        return 0;
 }
 
@@ -341,6 +380,18 @@ int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
 {
        struct ibss_rsn_peer *peer;
 
+       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;
+               }
+       }
+
        wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator and "
                   "Supplicant for peer " MACSTR, MAC2STR(addr));
 
@@ -369,6 +420,46 @@ int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
 }
 
 
+void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac)
+{
+       struct ibss_rsn_peer *peer, *prev;
+
+       if (ibss_rsn == NULL)
+               return;
+
+       if (peermac == NULL) {
+               /* remove all peers */
+               wpa_printf(MSG_DEBUG, "%s: Remove all peers", __func__);
+               peer = ibss_rsn->peers;
+               while (peer) {
+                       prev = peer;
+                       peer = peer->next;
+                       ibss_rsn_free(prev);
+                       ibss_rsn->peers = peer;
+               }
+       } else {
+               /* remove specific peer */
+               wpa_printf(MSG_DEBUG, "%s: Remove specific peer " MACSTR,
+                          __func__, MAC2STR(peermac));
+
+               for (prev = NULL, peer = ibss_rsn->peers; peer != NULL;
+                    prev = peer, peer = peer->next) {
+                       if (os_memcmp(peermac, peer->addr, ETH_ALEN) == 0) {
+                               if (prev == NULL)
+                                       ibss_rsn->peers = peer->next;
+                               else
+                                       prev->next = peer->next;
+                               ibss_rsn_free(peer);
+                               wpa_printf(MSG_DEBUG, "%s: Successfully "
+                                          "removed a specific peer",
+                                          __func__);
+                               break;
+                       }
+               }
+       }
+}
+
+
 struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s)
 {
        struct ibss_rsn *ibss_rsn;
@@ -483,6 +574,9 @@ int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
 {
        struct ibss_rsn_peer *peer;
 
+       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,
@@ -506,5 +600,7 @@ int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
 
 void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk)
 {
+       if (ibss_rsn == NULL)
+               return;
        os_memcpy(ibss_rsn->psk, psk, PMK_LEN);
 }
index 11e63ad..dbc889f 100644 (file)
@@ -42,6 +42,7 @@ struct ibss_rsn {
 struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s);
 void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn);
 int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr);
+void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac);
 int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
                      const u8 *buf, size_t len);
 void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk);
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
new file mode 100644 (file)
index 0000000..d42aa40
--- /dev/null
@@ -0,0 +1,1138 @@
+/*
+ * Interworking (IEEE 802.11u)
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
+#include "common/wpa_ctrl.h"
+#include "drivers/driver.h"
+#include "eap_common/eap_defs.h"
+#include "eap_peer/eap_methods.h"
+#include "wpa_supplicant_i.h"
+#include "config.h"
+#include "bss.h"
+#include "scan.h"
+#include "notify.h"
+#include "gas_query.h"
+#include "interworking.h"
+
+
+#if defined(EAP_SIM) | defined(EAP_SIM_DYNAMIC)
+#define INTERWORKING_3GPP
+#else
+#if defined(EAP_AKA) | defined(EAP_AKA_DYNAMIC)
+#define INTERWORKING_3GPP
+#else
+#if defined(EAP_AKA_PRIME) | defined(EAP_AKA_PRIME_DYNAMIC)
+#define INTERWORKING_3GPP
+#endif
+#endif
+#endif
+
+static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s);
+
+
+static struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids,
+                                     struct wpabuf *extra)
+{
+       struct wpabuf *buf;
+       size_t i;
+       u8 *len_pos;
+
+       buf = gas_anqp_build_initial_req(0, 4 + num_ids * 2 +
+                                        (extra ? wpabuf_len(extra) : 0));
+       if (buf == NULL)
+               return NULL;
+
+       len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST);
+       for (i = 0; i < num_ids; i++)
+               wpabuf_put_le16(buf, info_ids[i]);
+       gas_anqp_set_element_len(buf, len_pos);
+       if (extra)
+               wpabuf_put_buf(buf, extra);
+
+       gas_anqp_set_len(buf);
+
+       return buf;
+}
+
+
+static void interworking_anqp_resp_cb(void *ctx, const u8 *dst,
+                                     u8 dialog_token,
+                                     enum gas_query_result result,
+                                     const struct wpabuf *adv_proto,
+                                     const struct wpabuf *resp,
+                                     u16 status_code)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       anqp_resp_cb(wpa_s, dst, dialog_token, result, adv_proto, resp,
+                    status_code);
+       interworking_next_anqp_fetch(wpa_s);
+}
+
+
+static int 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
+       };
+       struct wpabuf *extra = NULL;
+
+       wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
+                  MAC2STR(bss->bssid));
+
+       buf = anqp_build_req(info_ids, sizeof(info_ids) / sizeof(info_ids[0]),
+                            extra);
+       wpabuf_free(extra);
+       if (buf == NULL)
+               return -1;
+
+       res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf,
+                           interworking_anqp_resp_cb, wpa_s);
+       if (res < 0) {
+               wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+               ret = -1;
+       } else
+               wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
+                          "%u", res);
+
+       wpabuf_free(buf);
+       return ret;
+}
+
+
+struct nai_realm_eap {
+       u8 method;
+       u8 inner_method;
+       enum nai_realm_eap_auth_inner_non_eap inner_non_eap;
+       u8 cred_type;
+       u8 tunneled_cred_type;
+};
+
+struct nai_realm {
+       u8 encoding;
+       char *realm;
+       u8 eap_count;
+       struct nai_realm_eap *eap;
+};
+
+
+static void nai_realm_free(struct nai_realm *realms, u16 count)
+{
+       u16 i;
+
+       if (realms == NULL)
+               return;
+       for (i = 0; i < count; i++) {
+               os_free(realms[i].eap);
+               os_free(realms[i].realm);
+       }
+       os_free(realms);
+}
+
+
+static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos,
+                                     const u8 *end)
+{
+       u8 elen, auth_count, a;
+       const u8 *e_end;
+
+       if (pos + 3 > end) {
+               wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields");
+               return NULL;
+       }
+
+       elen = *pos++;
+       if (pos + elen > end || elen < 2) {
+               wpa_printf(MSG_DEBUG, "No room for EAP Method subfield");
+               return NULL;
+       }
+       e_end = pos + elen;
+       e->method = *pos++;
+       auth_count = *pos++;
+       wpa_printf(MSG_DEBUG, "EAP Method: len=%u method=%u auth_count=%u",
+                  elen, e->method, auth_count);
+
+       for (a = 0; a < auth_count; a++) {
+               u8 id, len;
+
+               if (pos + 2 > end || pos + 2 + pos[1] > end) {
+                       wpa_printf(MSG_DEBUG, "No room for Authentication "
+                                  "Parameter subfield");
+                       return NULL;
+               }
+
+               id = *pos++;
+               len = *pos++;
+
+               switch (id) {
+               case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH:
+                       if (len < 1)
+                               break;
+                       e->inner_non_eap = *pos;
+                       if (e->method != EAP_TYPE_TTLS)
+                               break;
+                       switch (*pos) {
+                       case NAI_REALM_INNER_NON_EAP_PAP:
+                               wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP");
+                               break;
+                       case NAI_REALM_INNER_NON_EAP_CHAP:
+                               wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP");
+                               break;
+                       case NAI_REALM_INNER_NON_EAP_MSCHAP:
+                               wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP");
+                               break;
+                       case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
+                               wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2");
+                               break;
+                       }
+                       break;
+               case NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD:
+                       if (len < 1)
+                               break;
+                       e->inner_method = *pos;
+                       wpa_printf(MSG_DEBUG, "Inner EAP method: %u",
+                                  e->inner_method);
+                       break;
+               case NAI_REALM_EAP_AUTH_CRED_TYPE:
+                       if (len < 1)
+                               break;
+                       e->cred_type = *pos;
+                       wpa_printf(MSG_DEBUG, "Credential Type: %u",
+                                  e->cred_type);
+                       break;
+               case NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE:
+                       if (len < 1)
+                               break;
+                       e->tunneled_cred_type = *pos;
+                       wpa_printf(MSG_DEBUG, "Tunneled EAP Method Credential "
+                                  "Type: %u", e->tunneled_cred_type);
+                       break;
+               default:
+                       wpa_printf(MSG_DEBUG, "Unsupported Authentication "
+                                  "Parameter: id=%u len=%u", id, len);
+                       wpa_hexdump(MSG_DEBUG, "Authentication Parameter "
+                                   "Value", pos, len);
+                       break;
+               }
+
+               pos += len;
+       }
+
+       return e_end;
+}
+
+
+static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
+                                       const u8 *end)
+{
+       u16 len;
+       const u8 *f_end;
+       u8 realm_len, e;
+
+       if (end - pos < 4) {
+               wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
+                          "fixed fields");
+               return NULL;
+       }
+
+       len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */
+       pos += 2;
+       if (pos + len > end || len < 3) {
+               wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
+                          "(len=%u; left=%u)",
+                          len, (unsigned int) (end - pos));
+               return NULL;
+       }
+       f_end = pos + len;
+
+       r->encoding = *pos++;
+       realm_len = *pos++;
+       if (pos + realm_len > f_end) {
+               wpa_printf(MSG_DEBUG, "No room for NAI Realm "
+                          "(len=%u; left=%u)",
+                          realm_len, (unsigned int) (f_end - pos));
+               return NULL;
+       }
+       wpa_hexdump_ascii(MSG_DEBUG, "NAI Realm", pos, realm_len);
+       r->realm = os_malloc(realm_len + 1);
+       if (r->realm == NULL)
+               return NULL;
+       os_memcpy(r->realm, pos, realm_len);
+       r->realm[realm_len] = '\0';
+       pos += realm_len;
+
+       if (pos + 1 > f_end) {
+               wpa_printf(MSG_DEBUG, "No room for EAP Method Count");
+               return NULL;
+       }
+       r->eap_count = *pos++;
+       wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count);
+       if (pos + r->eap_count * 3 > f_end) {
+               wpa_printf(MSG_DEBUG, "No room for EAP Methods");
+               return NULL;
+       }
+       r->eap = os_zalloc(r->eap_count * sizeof(struct nai_realm_eap));
+       if (r->eap == NULL)
+               return NULL;
+
+       for (e = 0; e < r->eap_count; e++) {
+               pos = nai_realm_parse_eap(&r->eap[e], pos, f_end);
+               if (pos == NULL)
+                       return NULL;
+       }
+
+       return f_end;
+}
+
+
+static struct nai_realm * nai_realm_parse(struct wpabuf *anqp, u16 *count)
+{
+       struct nai_realm *realm;
+       const u8 *pos, *end;
+       u16 i, num;
+
+       if (anqp == NULL || wpabuf_len(anqp) < 2)
+               return NULL;
+
+       pos = wpabuf_head_u8(anqp);
+       end = pos + wpabuf_len(anqp);
+       num = WPA_GET_LE16(pos);
+       wpa_printf(MSG_DEBUG, "NAI Realm Count: %u", num);
+       pos += 2;
+
+       if (num * 5 > end - pos) {
+               wpa_printf(MSG_DEBUG, "Invalid NAI Realm Count %u - not "
+                          "enough data (%u octets) for that many realms",
+                          num, (unsigned int) (end - pos));
+               return NULL;
+       }
+
+       realm = os_zalloc(num * sizeof(struct nai_realm));
+       if (realm == NULL)
+               return NULL;
+
+       for (i = 0; i < num; i++) {
+               pos = nai_realm_parse_realm(&realm[i], pos, end);
+               if (pos == NULL) {
+                       nai_realm_free(realm, num);
+                       return NULL;
+               }
+       }
+
+       *count = num;
+       return realm;
+}
+
+
+static int nai_realm_match(struct nai_realm *realm, const char *home_realm)
+{
+       char *tmp, *pos, *end;
+       int match = 0;
+
+       if (realm->realm == NULL || home_realm == NULL)
+               return 0;
+
+       if (os_strchr(realm->realm, ';') == NULL)
+               return os_strcasecmp(realm->realm, home_realm) == 0;
+
+       tmp = os_strdup(realm->realm);
+       if (tmp == NULL)
+               return 0;
+
+       pos = tmp;
+       while (*pos) {
+               end = os_strchr(pos, ';');
+               if (end)
+                       *end = '\0';
+               if (os_strcasecmp(pos, home_realm) == 0) {
+                       match = 1;
+                       break;
+               }
+               if (end == NULL)
+                       break;
+               pos = end + 1;
+       }
+
+       os_free(tmp);
+
+       return match;
+}
+
+
+static int nai_realm_cred_username(struct nai_realm_eap *eap)
+{
+       if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
+               return 0; /* method not supported */
+
+       if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP) {
+               /* Only tunneled methods with username/password supported */
+               return 0;
+       }
+
+       if (eap->method == EAP_TYPE_PEAP &&
+           eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
+               return 0;
+
+       if (eap->method == EAP_TYPE_TTLS) {
+               if (eap->inner_method == 0 && eap->inner_non_eap == 0)
+                       return 0;
+               if (eap->inner_method &&
+                   eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
+                       return 0;
+               if (eap->inner_non_eap &&
+                   eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_PAP &&
+                   eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_CHAP &&
+                   eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAP &&
+                   eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2)
+                       return 0;
+       }
+
+       if (eap->inner_method &&
+           eap->inner_method != EAP_TYPE_GTC &&
+           eap->inner_method != EAP_TYPE_MSCHAPV2)
+               return 0;
+
+       return 1;
+}
+
+
+static struct nai_realm_eap * nai_realm_find_eap(struct wpa_supplicant *wpa_s,
+                                                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')
+               return NULL;
+
+       for (e = 0; e < realm->eap_count; e++) {
+               struct nai_realm_eap *eap = &realm->eap[e];
+               if (nai_realm_cred_username(eap))
+                       return eap;
+       }
+
+       return NULL;
+}
+
+
+#ifdef INTERWORKING_3GPP
+
+static int plmn_id_match(struct wpabuf *anqp, const char *imsi)
+{
+       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)
+               plmn[1] |= (imsi[5] - '0') << 4;
+       else
+               plmn[1] |= 0xf0;
+       plmn[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
+
+       if (anqp == NULL)
+               return 0;
+       pos = wpabuf_head_u8(anqp);
+       end = pos + wpabuf_len(anqp);
+       if (pos + 2 > end)
+               return 0;
+       if (*pos != 0) {
+               wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos);
+               return 0;
+       }
+       pos++;
+       udhl = *pos++;
+       if (pos + udhl > end) {
+               wpa_printf(MSG_DEBUG, "Invalid UDHL");
+               return 0;
+       }
+       end = pos + udhl;
+
+       while (pos + 2 <= end) {
+               u8 iei, len;
+               const u8 *l_end;
+               iei = *pos++;
+               len = *pos++ & 0x7f;
+               if (pos + len > end)
+                       break;
+               l_end = pos + len;
+
+               if (iei == 0 && len > 0) {
+                       /* PLMN List */
+                       u8 num, i;
+                       num = *pos++;
+                       for (i = 0; i < num; i++) {
+                               if (pos + 3 > end)
+                                       break;
+                               if (os_memcmp(pos, plmn, 3) == 0)
+                                       return 1; /* Found matching PLMN */
+                       }
+               }
+
+               pos = l_end;
+       }
+
+       return 0;
+}
+
+
+static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
+{
+       const char *sep, *msin;
+       char nai[100], *end, *pos;
+       size_t msin_len, plmn_len;
+
+       /*
+        * TS 23.003, Clause 14 (3GPP to WLAN Interworking)
+        * Root NAI:
+        * <aka:0|sim:1><IMSI>@wlan.mnc<MNC>.mcc<MCC>.3gppnetwork.org
+        * <MNC> is zero-padded to three digits in case two-digit MNC is used
+        */
+
+       if (imsi == NULL || os_strlen(imsi) > 16) {
+               wpa_printf(MSG_DEBUG, "No valid IMSI available");
+               return -1;
+       }
+       sep = os_strchr(imsi, '-');
+       if (sep == NULL)
+               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;
+       os_memcpy(pos, imsi, plmn_len);
+       pos += plmn_len;
+       os_memcpy(pos, msin, msin_len);
+       pos += msin_len;
+       pos += os_snprintf(pos, end - pos, "@wlan.mnc");
+       if (plmn_len == 5) {
+               *pos++ = '0';
+               *pos++ = imsi[3];
+               *pos++ = imsi[4];
+       } else {
+               *pos++ = imsi[3];
+               *pos++ = imsi[4];
+               *pos++ = imsi[5];
+       }
+       pos += os_snprintf(pos, end - pos, ".mcc%c%c%c.3gppnetwork.org",
+                          imsi[0], imsi[1], imsi[2]);
+
+       return wpa_config_set_quoted(ssid, "identity", nai);
+}
+
+#endif /* INTERWORKING_3GPP */
+
+
+static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
+                                    struct wpa_bss *bss)
+{
+#ifdef INTERWORKING_3GPP
+       struct wpa_ssid *ssid;
+       const u8 *ie;
+
+       ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
+       if (ie == NULL)
+               return -1;
+       wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)",
+                  MAC2STR(bss->bssid));
+
+       ssid = wpa_config_add_network(wpa_s->conf);
+       if (ssid == NULL)
+               return -1;
+
+       wpas_notify_network_added(wpa_s, ssid);
+       wpa_config_set_network_defaults(ssid);
+       ssid->temporary = 1;
+       ssid->ssid = os_zalloc(ie[1] + 1);
+       if (ssid->ssid == NULL)
+               goto fail;
+       os_memcpy(ssid->ssid, ie + 2, ie[1]);
+       ssid->ssid_len = ie[1];
+
+       /* 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");
+               goto fail;
+       }
+       if (set_root_nai(ssid, wpa_s->conf->home_imsi, '1') < 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 (wpa_config_set_quoted(ssid, "password",
+                                         wpa_s->conf->home_milenage) < 0)
+                       goto fail;
+       } else {
+               /* TODO: PIN */
+               if (wpa_config_set_quoted(ssid, "pcsc", "") < 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)
+               goto fail;
+
+       wpa_supplicant_select_network(wpa_s, ssid);
+
+       return 0;
+
+fail:
+       wpas_notify_network_removed(wpa_s, ssid);
+       wpa_config_remove_network(wpa_s->conf, ssid->id);
+#endif /* INTERWORKING_3GPP */
+       return -1;
+}
+
+
+int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+       struct wpa_ssid *ssid;
+       struct nai_realm *realm;
+       struct nai_realm_eap *eap = NULL;
+       u16 count, i;
+       char buf[100];
+       const u8 *ie;
+
+       if (bss == NULL)
+               return -1;
+       ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
+       if (ie == NULL || ie[1] == 0) {
+               wpa_printf(MSG_DEBUG, "Interworking: No SSID known for "
+                          MACSTR, MAC2STR(bss->bssid));
+               return -1;
+       }
+
+       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));
+               count = 0;
+       }
+
+       for (i = 0; i < count; i++) {
+               if (!nai_realm_match(&realm[i], wpa_s->conf->home_realm))
+                       continue;
+               eap = nai_realm_find_eap(wpa_s, &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));
+               nai_realm_free(realm, count);
+               return -1;
+       }
+
+       wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR,
+                  MAC2STR(bss->bssid));
+
+       ssid = wpa_config_add_network(wpa_s->conf);
+       if (ssid == NULL) {
+               nai_realm_free(realm, count);
+               return -1;
+       }
+       wpas_notify_network_added(wpa_s, ssid);
+       wpa_config_set_network_defaults(ssid);
+       ssid->temporary = 1;
+       ssid->ssid = os_zalloc(ie[1] + 1);
+       if (ssid->ssid == NULL)
+               goto fail;
+       os_memcpy(ssid->ssid, ie + 2, ie[1]);
+       ssid->ssid_len = ie[1];
+
+       if (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)
+               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)
+               goto fail;
+
+       switch (eap->method) {
+       case EAP_TYPE_TTLS:
+               if (eap->inner_method) {
+                       os_snprintf(buf, sizeof(buf), "\"autheap=%s\"",
+                                   eap_get_name(EAP_VENDOR_IETF,
+                                                eap->inner_method));
+                       if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
+                               goto fail;
+                       break;
+               }
+               switch (eap->inner_non_eap) {
+               case NAI_REALM_INNER_NON_EAP_PAP:
+                       if (wpa_config_set(ssid, "phase2", "\"auth=PAP\"", 0) <
+                           0)
+                               goto fail;
+                       break;
+               case NAI_REALM_INNER_NON_EAP_CHAP:
+                       if (wpa_config_set(ssid, "phase2", "\"auth=CHAP\"", 0)
+                           < 0)
+                               goto fail;
+                       break;
+               case NAI_REALM_INNER_NON_EAP_MSCHAP:
+                       if (wpa_config_set(ssid, "phase2", "\"auth=CHAP\"", 0)
+                           < 0)
+                               goto fail;
+                       break;
+               case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
+                       if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"",
+                                          0) < 0)
+                               goto fail;
+                       break;
+               }
+               break;
+       case EAP_TYPE_PEAP:
+               os_snprintf(buf, sizeof(buf), "\"auth=%s\"",
+                           eap_get_name(EAP_VENDOR_IETF, eap->inner_method));
+               if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
+                       goto fail;
+               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)
+               goto fail;
+
+       nai_realm_free(realm, count);
+
+       wpa_supplicant_select_network(wpa_s, ssid);
+
+       return 0;
+
+fail:
+       wpas_notify_network_removed(wpa_s, ssid);
+       wpa_config_remove_network(wpa_s->conf, ssid->id);
+       nai_realm_free(realm, count);
+       return -1;
+}
+
+
+static int interworking_credentials_available_3gpp(
+       struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+       int ret = 0;
+
+#ifdef INTERWORKING_3GPP
+       if (bss->anqp_3gpp == NULL)
+               return 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;
+
+       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 ");
+#endif /* INTERWORKING_3GPP */
+       return ret;
+}
+
+
+static int interworking_credentials_available_realm(
+       struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+       struct nai_realm *realm;
+       u16 count, i;
+       int found = 0;
+
+       if (bss->anqp_nai_realm == NULL)
+               return 0;
+
+       if (wpa_s->conf->home_realm == NULL)
+               return 0;
+
+       wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
+                  MACSTR, MAC2STR(bss->bssid));
+       realm = nai_realm_parse(bss->anqp_nai_realm, &count);
+       if (realm == NULL) {
+               wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
+                          "Realm list from " MACSTR, MAC2STR(bss->bssid));
+               return 0;
+       }
+
+       for (i = 0; i < count; i++) {
+               if (!nai_realm_match(&realm[i], wpa_s->conf->home_realm))
+                       continue;
+               if (nai_realm_find_eap(wpa_s, &realm[i])) {
+                       found++;
+                       break;
+               }
+       }
+
+       nai_realm_free(realm, count);
+
+       return found;
+}
+
+
+static int interworking_credentials_available(struct wpa_supplicant *wpa_s,
+                                             struct wpa_bss *bss)
+{
+       return interworking_credentials_available_realm(wpa_s, bss) ||
+               interworking_credentials_available_3gpp(wpa_s, bss);
+}
+
+
+static void interworking_select_network(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_bss *bss, *selected = NULL;
+       unsigned int count = 0;
+
+       wpa_s->network_select = 0;
+
+       dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+               if (!interworking_credentials_available(wpa_s, bss))
+                       continue;
+               count++;
+               wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR,
+                       MAC2STR(bss->bssid));
+               if (selected == NULL && wpa_s->auto_select)
+                       selected = bss;
+       }
+
+       if (count == 0) {
+               wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network "
+                       "with matching credentials found");
+       }
+
+       if (selected)
+               interworking_connect(wpa_s, selected);
+}
+
+
+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)
+               return;
+
+       dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+               if (!(bss->caps & IEEE80211_CAP_ESS))
+                       continue;
+               ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
+               if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80))
+                       continue; /* AP does not support Interworking */
+
+               if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) {
+                       found++;
+                       bss->flags |= WPA_BSS_ANQP_FETCH_TRIED;
+                       wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for "
+                               MACSTR, MAC2STR(bss->bssid));
+                       interworking_anqp_send_req(wpa_s, bss);
+                       break;
+               }
+       }
+
+       if (found == 0) {
+               wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed");
+               wpa_s->fetch_anqp_in_progress = 0;
+               if (wpa_s->network_select)
+                       interworking_select_network(wpa_s);
+       }
+}
+
+
+static void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_bss *bss;
+
+       dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list)
+               bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED;
+
+       wpa_s->fetch_anqp_in_progress = 1;
+       interworking_next_anqp_fetch(wpa_s);
+}
+
+
+int interworking_fetch_anqp(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select)
+               return 0;
+
+       wpa_s->network_select = 0;
+
+       interworking_start_fetch_anqp(wpa_s);
+
+       return 0;
+}
+
+
+void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s->fetch_anqp_in_progress)
+               return;
+
+       wpa_s->fetch_anqp_in_progress = 0;
+}
+
+
+int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
+                 u16 info_ids[], size_t num_ids)
+{
+       struct wpabuf *buf;
+       int ret = 0;
+       int freq;
+       struct wpa_bss *bss;
+       int res;
+
+       freq = wpa_s->assoc_freq;
+       bss = wpa_bss_get_bssid(wpa_s, dst);
+       if (bss)
+               freq = bss->freq;
+       if (freq <= 0)
+               return -1;
+
+       wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)",
+                  MAC2STR(dst), (unsigned int) num_ids);
+
+       buf = anqp_build_req(info_ids, num_ids, NULL);
+       if (buf == NULL)
+               return -1;
+
+       res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
+       if (res < 0) {
+               wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+               ret = -1;
+       } else
+               wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
+                          "%u", res);
+
+       wpabuf_free(buf);
+       return ret;
+}
+
+
+static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
+                                           const u8 *sa, u16 info_id,
+                                           const u8 *data, size_t slen)
+{
+       const u8 *pos = data;
+       struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
+
+       switch (info_id) {
+       case ANQP_CAPABILITY_LIST:
+               wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+                       " ANQP Capability list", MAC2STR(sa));
+               break;
+       case ANQP_VENUE_NAME:
+               wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+                       " Venue Name", MAC2STR(sa));
+               wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
+               if (bss) {
+                       wpabuf_free(bss->anqp_venue_name);
+                       bss->anqp_venue_name = wpabuf_alloc_copy(pos, slen);
+               }
+               break;
+       case ANQP_NETWORK_AUTH_TYPE:
+               wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+                       " Network Authentication Type information",
+                       MAC2STR(sa));
+               wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
+                                 "Type", pos, slen);
+               if (bss) {
+                       wpabuf_free(bss->anqp_network_auth_type);
+                       bss->anqp_network_auth_type =
+                               wpabuf_alloc_copy(pos, slen);
+               }
+               break;
+       case ANQP_ROAMING_CONSORTIUM:
+               wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+                       " Roaming Consortium list", MAC2STR(sa));
+               wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
+                                 pos, slen);
+               if (bss) {
+                       wpabuf_free(bss->anqp_roaming_consortium);
+                       bss->anqp_roaming_consortium =
+                               wpabuf_alloc_copy(pos, slen);
+               }
+               break;
+       case ANQP_IP_ADDR_TYPE_AVAILABILITY:
+               wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+                       " IP Address Type Availability information",
+                       MAC2STR(sa));
+               wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
+                           pos, slen);
+               if (bss) {
+                       wpabuf_free(bss->anqp_ip_addr_type_availability);
+                       bss->anqp_ip_addr_type_availability =
+                               wpabuf_alloc_copy(pos, slen);
+               }
+               break;
+       case ANQP_NAI_REALM:
+               wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+                       " NAI Realm list", MAC2STR(sa));
+               wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen);
+               if (bss) {
+                       wpabuf_free(bss->anqp_nai_realm);
+                       bss->anqp_nai_realm = wpabuf_alloc_copy(pos, slen);
+               }
+               break;
+       case ANQP_3GPP_CELLULAR_NETWORK:
+               wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+                       " 3GPP Cellular Network information", MAC2STR(sa));
+               wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
+                                 pos, slen);
+               if (bss) {
+                       wpabuf_free(bss->anqp_3gpp);
+                       bss->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);
+               }
+               break;
+       case ANQP_VENDOR_SPECIFIC:
+               if (slen < 3)
+                       return;
+
+               switch (WPA_GET_BE24(pos)) {
+               default:
+                       wpa_printf(MSG_DEBUG, "Interworking: Unsupported "
+                                  "vendor-specific ANQP OUI %06x",
+                                  WPA_GET_BE24(pos));
+                       return;
+               }
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "Interworking: Unsupported ANQP Info ID "
+                          "%u", info_id);
+               break;
+       }
+}
+
+
+void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
+                 enum gas_query_result result,
+                 const struct wpabuf *adv_proto,
+                 const struct wpabuf *resp, u16 status_code)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       const u8 *pos;
+       const u8 *end;
+       u16 info_id;
+       u16 slen;
+
+       if (result != GAS_QUERY_SUCCESS)
+               return;
+
+       pos = wpabuf_head(adv_proto);
+       if (wpabuf_len(adv_proto) < 4 || pos[0] != WLAN_EID_ADV_PROTO ||
+           pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) {
+               wpa_printf(MSG_DEBUG, "ANQP: Unexpected Advertisement "
+                          "Protocol in response");
+               return;
+       }
+
+       pos = wpabuf_head(resp);
+       end = pos + wpabuf_len(resp);
+
+       while (pos < end) {
+               if (pos + 4 > end) {
+                       wpa_printf(MSG_DEBUG, "ANQP: Invalid element");
+                       break;
+               }
+               info_id = WPA_GET_LE16(pos);
+               pos += 2;
+               slen = WPA_GET_LE16(pos);
+               pos += 2;
+               if (pos + slen > end) {
+                       wpa_printf(MSG_DEBUG, "ANQP: Invalid element length "
+                                  "for Info ID %u", info_id);
+                       break;
+               }
+               interworking_parse_rx_anqp_resp(wpa_s, dst, info_id, pos,
+                                               slen);
+               pos += slen;
+       }
+}
+
+
+static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s,
+                                         struct wpa_scan_results *scan_res)
+{
+       wpa_printf(MSG_DEBUG, "Interworking: Scan results available - start "
+                  "ANQP fetch");
+       interworking_start_fetch_anqp(wpa_s);
+}
+
+
+int interworking_select(struct wpa_supplicant *wpa_s, int auto_select)
+{
+       interworking_stop_fetch_anqp(wpa_s);
+       wpa_s->network_select = 1;
+       wpa_s->auto_select = !!auto_select;
+       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_supplicant_req_scan(wpa_s, 0, 0);
+
+       return 0;
+}
diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h
new file mode 100644 (file)
index 0000000..247df30
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Interworking (IEEE 802.11u)
+ * 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.
+ */
+
+#ifndef INTERWORKING_H
+#define INTERWORKING_H
+
+enum gas_query_result;
+
+int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
+                 u16 info_ids[], size_t num_ids);
+void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
+                 enum gas_query_result result,
+                 const struct wpabuf *adv_proto,
+                 const struct wpabuf *resp, u16 status_code);
+int 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);
+
+#endif /* INTERWORKING_H */
index c0aa59c..e196f3c 100644 (file)
@@ -33,7 +33,8 @@ static void usage(void)
               "[-g<global ctrl>] \\\n"
               "        -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] "
               "[-p<driver_param>] \\\n"
-              "        [-b<br_ifname>] [-f<debug file>] \\\n"
+              "        [-b<br_ifname>] [-f<debug file>] [-e<entropy file>] "
+              "\\\n"
               "        [-o<override driver>] [-O<override ctrl>] \\\n"
               "        [-N -i<ifname> -c<conf> [-C<ctrl>] "
               "[-D<driver>] \\\n"
@@ -56,7 +57,8 @@ static void usage(void)
               "  -C = ctrl_interface parameter (only used if -c is not)\n"
               "  -i = interface name\n"
               "  -d = increase debugging verbosity (-dd even more)\n"
-              "  -D = driver name (can be multiple drivers: nl80211,wext)\n");
+              "  -D = driver name (can be multiple drivers: nl80211,wext)\n"
+              "  -e = entropy file\n");
 #ifdef CONFIG_DEBUG_FILE
        printf("  -f = log output to debug file instead of stdout\n");
 #endif /* CONFIG_DEBUG_FILE */
@@ -143,7 +145,7 @@ int main(int argc, char *argv[])
        wpa_supplicant_fd_workaround();
 
        for (;;) {
-               c = getopt(argc, argv, "b:Bc:C:D:df:g:hi:KLNo:O:p:P:qstuvW");
+               c = getopt(argc, argv, "b:Bc:C:D:de:f:g:hi:KLNo:O:p:P:qstuvW");
                if (c < 0)
                        break;
                switch (c) {
@@ -172,6 +174,9 @@ int main(int argc, char *argv[])
                        params.wpa_debug_level--;
                        break;
 #endif /* CONFIG_NO_STDOUT_DEBUG */
+               case 'e':
+                       params.entropy_file = optarg;
+                       break;
 #ifdef CONFIG_DEBUG_FILE
                case 'f':
                        params.wpa_debug_file_path = optarg;
diff --git a/wpa_supplicant/mlme.c b/wpa_supplicant/mlme.c
deleted file mode 100644 (file)
index eb60ac5..0000000
+++ /dev/null
@@ -1,3198 +0,0 @@
-/*
- * WPA Supplicant - Client mode MLME
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004, Instant802 Networks, Inc.
- * Copyright (c) 2005-2006, Devicescape Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eloop.h"
-#include "config_ssid.h"
-#include "wpa_supplicant_i.h"
-#include "notify.h"
-#include "driver_i.h"
-#include "rsn_supp/wpa.h"
-#include "common/ieee802_11_defs.h"
-#include "common/ieee802_11_common.h"
-#include "mlme.h"
-
-
-/* Timeouts and intervals in milliseconds */
-#define IEEE80211_AUTH_TIMEOUT (200)
-#define IEEE80211_AUTH_MAX_TRIES 3
-#define IEEE80211_ASSOC_TIMEOUT (200)
-#define IEEE80211_ASSOC_MAX_TRIES 3
-#define IEEE80211_MONITORING_INTERVAL (2000)
-#define IEEE80211_PROBE_INTERVAL (60000)
-#define IEEE80211_RETRY_AUTH_INTERVAL (1000)
-#define IEEE80211_SCAN_INTERVAL (2000)
-#define IEEE80211_SCAN_INTERVAL_SLOW (15000)
-#define IEEE80211_IBSS_JOIN_TIMEOUT (20000)
-
-#define IEEE80211_PROBE_DELAY (33)
-#define IEEE80211_CHANNEL_TIME (33)
-#define IEEE80211_PASSIVE_CHANNEL_TIME (200)
-#define IEEE80211_SCAN_RESULT_EXPIRE (10000)
-#define IEEE80211_IBSS_MERGE_INTERVAL (30000)
-#define IEEE80211_IBSS_INACTIVITY_LIMIT (60000)
-
-#define IEEE80211_IBSS_MAX_STA_ENTRIES 128
-
-
-#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4))
-
-
-struct ieee80211_sta_bss {
-       struct ieee80211_sta_bss *next;
-       struct ieee80211_sta_bss *hnext;
-
-       u8 bssid[ETH_ALEN];
-       u8 ssid[MAX_SSID_LEN];
-       size_t ssid_len;
-       u16 capability; /* host byte order */
-       int hw_mode;
-       int channel;
-       int freq;
-       int rssi;
-       u8 *ie;
-       size_t ie_len;
-       u8 *wpa_ie;
-       size_t wpa_ie_len;
-       u8 *rsn_ie;
-       size_t rsn_ie_len;
-       u8 *wmm_ie;
-       size_t wmm_ie_len;
-       u8 *mdie;
-       size_t mdie_len;
-#define IEEE80211_MAX_SUPP_RATES 32
-       u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
-       size_t supp_rates_len;
-       int beacon_int;
-       u64 timestamp;
-
-       int probe_resp;
-       struct os_time last_update;
-};
-
-
-static void ieee80211_send_probe_req(struct wpa_supplicant *wpa_s,
-                                    const u8 *dst,
-                                    const u8 *ssid, size_t ssid_len);
-static struct ieee80211_sta_bss *
-ieee80211_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid);
-static int ieee80211_sta_find_ibss(struct wpa_supplicant *wpa_s);
-static int ieee80211_sta_wep_configured(struct wpa_supplicant *wpa_s);
-static void ieee80211_sta_timer(void *eloop_ctx, void *timeout_ctx);
-static void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx);
-static void ieee80211_build_tspec(struct wpabuf *buf);
-static int ieee80211_sta_set_probe_req_ie(struct wpa_supplicant *wpa_s,
-                                         const u8 *ies, size_t ies_len);
-
-
-static int ieee80211_sta_set_channel(struct wpa_supplicant *wpa_s,
-                                    enum hostapd_hw_mode phymode, int chan,
-                                    int freq)
-{
-       size_t i;
-       struct hostapd_hw_modes *mode;
-
-       for (i = 0; i < wpa_s->mlme.num_modes; i++) {
-               mode = &wpa_s->mlme.modes[i];
-               if (mode->mode == phymode) {
-                       wpa_s->mlme.curr_rates = mode->rates;
-                       wpa_s->mlme.num_curr_rates = mode->num_rates;
-                       break;
-               }
-       }
-
-       return wpa_drv_set_channel(wpa_s, phymode, chan, freq);
-}
-
-
-static int ecw2cw(int ecw)
-{
-       int cw = 1;
-       while (ecw > 0) {
-               cw <<= 1;
-               ecw--;
-       }
-       return cw - 1;
-}
-
-
-static void ieee80211_sta_wmm_params(struct wpa_supplicant *wpa_s,
-                                    const u8 *wmm_param, size_t wmm_param_len)
-{
-       size_t left;
-       int count;
-       const u8 *pos;
-       u8 wmm_acm;
-
-       if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
-               return;
-       count = wmm_param[6] & 0x0f;
-       if (count == wpa_s->mlme.wmm_last_param_set)
-               return;
-       wpa_s->mlme.wmm_last_param_set = count;
-
-       pos = wmm_param + 8;
-       left = wmm_param_len - 8;
-
-       wmm_acm = 0;
-       for (; left >= 4; left -= 4, pos += 4) {
-               int aci = (pos[0] >> 5) & 0x03;
-               int acm = (pos[0] >> 4) & 0x01;
-               int aifs, cw_max, cw_min, burst_time;
-
-               switch (aci) {
-               case 1: /* AC_BK */
-                       if (acm)
-                               wmm_acm |= BIT(1) | BIT(2); /* BK/- */
-                       break;
-               case 2: /* AC_VI */
-                       if (acm)
-                               wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
-                       break;
-               case 3: /* AC_VO */
-                       if (acm)
-                               wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
-                       break;
-               case 0: /* AC_BE */
-               default:
-                       if (acm)
-                               wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
-                       break;
-               }
-
-               aifs = pos[0] & 0x0f;
-               cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
-               cw_min = ecw2cw(pos[1] & 0x0f);
-               /* TXOP is in units of 32 usec; burst_time in 0.1 ms */
-               burst_time = (pos[2] | (pos[3] << 8)) * 32 / 100;
-               wpa_printf(MSG_DEBUG, "MLME: WMM aci=%d acm=%d aifs=%d "
-                          "cWmin=%d cWmax=%d burst=%d",
-                          aci, acm, aifs, cw_min, cw_max, burst_time);
-               /* TODO: driver configuration */
-       }
-}
-
-
-static void ieee80211_set_associated(struct wpa_supplicant *wpa_s, int assoc)
-{
-       if (wpa_s->mlme.associated == assoc && !assoc)
-               return;
-
-       wpa_s->mlme.associated = assoc;
-
-       if (assoc) {
-               union wpa_event_data data;
-               os_memset(&data, 0, sizeof(data));
-               wpa_s->mlme.prev_bssid_set = 1;
-               os_memcpy(wpa_s->mlme.prev_bssid, wpa_s->bssid, ETH_ALEN);
-               data.assoc_info.req_ies = wpa_s->mlme.assocreq_ies;
-               data.assoc_info.req_ies_len = wpa_s->mlme.assocreq_ies_len;
-               data.assoc_info.resp_ies = wpa_s->mlme.assocresp_ies;
-               data.assoc_info.resp_ies_len = wpa_s->mlme.assocresp_ies_len;
-               data.assoc_info.freq = wpa_s->mlme.freq;
-               wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data);
-       } else {
-               wpa_supplicant_event(wpa_s, EVENT_DISASSOC, NULL);
-       }
-       os_get_time(&wpa_s->mlme.last_probe);
-}
-
-
-static int ieee80211_sta_tx(struct wpa_supplicant *wpa_s, const u8 *buf,
-                           size_t len)
-{
-       return wpa_drv_send_mlme(wpa_s, buf, len);
-}
-
-
-static void ieee80211_send_auth(struct wpa_supplicant *wpa_s,
-                               int transaction, const u8 *extra,
-                               size_t extra_len, int encrypt)
-{
-       u8 *buf;
-       size_t len;
-       struct ieee80211_mgmt *mgmt;
-
-       buf = os_malloc(sizeof(*mgmt) + 6 + extra_len);
-       if (buf == NULL) {
-               wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
-                          "auth frame");
-               return;
-       }
-
-       mgmt = (struct ieee80211_mgmt *) buf;
-       len = 24 + 6;
-       os_memset(mgmt, 0, 24 + 6);
-       mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-                                          WLAN_FC_STYPE_AUTH);
-       if (encrypt)
-               mgmt->frame_control |= host_to_le16(WLAN_FC_ISWEP);
-       os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
-       os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-       os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-       mgmt->u.auth.auth_alg = host_to_le16(wpa_s->mlme.auth_alg);
-       mgmt->u.auth.auth_transaction = host_to_le16(transaction);
-       wpa_s->mlme.auth_transaction = transaction + 1;
-       mgmt->u.auth.status_code = host_to_le16(0);
-       if (extra) {
-               os_memcpy(buf + len, extra, extra_len);
-               len += extra_len;
-       }
-
-       ieee80211_sta_tx(wpa_s, buf, len);
-       os_free(buf);
-}
-
-
-static void ieee80211_reschedule_timer(struct wpa_supplicant *wpa_s, int ms)
-{
-       eloop_cancel_timeout(ieee80211_sta_timer, wpa_s, NULL);
-       eloop_register_timeout(ms / 1000, 1000 * (ms % 1000),
-                              ieee80211_sta_timer, wpa_s, NULL);
-}
-
-
-static void ieee80211_authenticate(struct wpa_supplicant *wpa_s)
-{
-       u8 *extra;
-       size_t extra_len;
-
-       wpa_s->mlme.auth_tries++;
-       if (wpa_s->mlme.auth_tries > IEEE80211_AUTH_MAX_TRIES) {
-               wpa_printf(MSG_DEBUG, "MLME: authentication with AP " MACSTR
-                          " timed out", MAC2STR(wpa_s->bssid));
-               return;
-       }
-
-       wpa_s->mlme.state = IEEE80211_AUTHENTICATE;
-       wpa_printf(MSG_DEBUG, "MLME: authenticate with AP " MACSTR,
-                  MAC2STR(wpa_s->bssid));
-
-       extra = NULL;
-       extra_len = 0;
-
-#ifdef CONFIG_IEEE80211R
-       if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X ||
-            wpa_s->mlme.key_mgmt == KEY_MGMT_FT_PSK) &&
-           wpa_s->mlme.ft_ies) {
-               struct ieee80211_sta_bss *bss;
-               struct rsn_mdie *mdie = NULL;
-               bss = ieee80211_bss_get(wpa_s, wpa_s->bssid);
-               if (bss && bss->mdie_len >= 2 + sizeof(*mdie))
-                       mdie = (struct rsn_mdie *) (bss->mdie + 2);
-               if (mdie &&
-                   os_memcmp(mdie->mobility_domain, wpa_s->mlme.current_md,
-                             MOBILITY_DOMAIN_ID_LEN) == 0) {
-                       wpa_printf(MSG_DEBUG, "MLME: Trying to use FT "
-                                  "over-the-air");
-                       wpa_s->mlme.auth_alg = WLAN_AUTH_FT;
-                       extra = wpa_s->mlme.ft_ies;
-                       extra_len = wpa_s->mlme.ft_ies_len;
-               }
-       }
-#endif /* CONFIG_IEEE80211R */
-
-       ieee80211_send_auth(wpa_s, 1, extra, extra_len, 0);
-
-       ieee80211_reschedule_timer(wpa_s, IEEE80211_AUTH_TIMEOUT);
-}
-
-
-static void ieee80211_send_assoc(struct wpa_supplicant *wpa_s)
-{
-       struct ieee80211_mgmt *mgmt;
-       u8 *pos, *ies, *buf;
-       int i, len;
-       u16 capab;
-       struct ieee80211_sta_bss *bss;
-       int wmm = 0;
-       size_t blen, buflen;
-
-       if (wpa_s->mlme.curr_rates == NULL) {
-               wpa_printf(MSG_DEBUG, "MLME: curr_rates not set for assoc");
-               return;
-       }
-
-       buflen = sizeof(*mgmt) + 200 + wpa_s->mlme.extra_ie_len +
-               wpa_s->mlme.ssid_len;
-#ifdef CONFIG_IEEE80211R
-       if (wpa_s->mlme.ft_ies)
-               buflen += wpa_s->mlme.ft_ies_len;
-#endif /* CONFIG_IEEE80211R */
-       buf = os_malloc(buflen);
-       if (buf == NULL) {
-               wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
-                          "assoc frame");
-               return;
-       }
-       blen = 0;
-
-       capab = wpa_s->mlme.capab;
-       if (wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211G) {
-               capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME |
-                       WLAN_CAPABILITY_SHORT_PREAMBLE;
-       }
-       bss = ieee80211_bss_get(wpa_s, wpa_s->bssid);
-       if (bss) {
-               if (bss->capability & WLAN_CAPABILITY_PRIVACY)
-                       capab |= WLAN_CAPABILITY_PRIVACY;
-               if (bss->wmm_ie) {
-                       wmm = 1;
-               }
-       }
-
-       mgmt = (struct ieee80211_mgmt *) buf;
-       blen += 24;
-       os_memset(mgmt, 0, 24);
-       os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
-       os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-       os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-
-       if (wpa_s->mlme.prev_bssid_set) {
-               blen += 10;
-               mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-                                                  WLAN_FC_STYPE_REASSOC_REQ);
-               mgmt->u.reassoc_req.capab_info = host_to_le16(capab);
-               mgmt->u.reassoc_req.listen_interval = host_to_le16(1);
-               os_memcpy(mgmt->u.reassoc_req.current_ap,
-                         wpa_s->mlme.prev_bssid,
-                         ETH_ALEN);
-       } else {
-               blen += 4;
-               mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-                                                  WLAN_FC_STYPE_ASSOC_REQ);
-               mgmt->u.assoc_req.capab_info = host_to_le16(capab);
-               mgmt->u.assoc_req.listen_interval = host_to_le16(1);
-       }
-
-       /* SSID */
-       ies = pos = buf + blen;
-       blen += 2 + wpa_s->mlme.ssid_len;
-       *pos++ = WLAN_EID_SSID;
-       *pos++ = wpa_s->mlme.ssid_len;
-       os_memcpy(pos, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len);
-
-       len = wpa_s->mlme.num_curr_rates;
-       if (len > 8)
-               len = 8;
-       pos = buf + blen;
-       blen += len + 2;
-       *pos++ = WLAN_EID_SUPP_RATES;
-       *pos++ = len;
-       for (i = 0; i < len; i++)
-               *pos++ = (u8) (wpa_s->mlme.curr_rates[i] / 5);
-
-       if (wpa_s->mlme.num_curr_rates > len) {
-               pos = buf + blen;
-               blen += wpa_s->mlme.num_curr_rates - len + 2;
-               *pos++ = WLAN_EID_EXT_SUPP_RATES;
-               *pos++ = wpa_s->mlme.num_curr_rates - len;
-               for (i = len; i < wpa_s->mlme.num_curr_rates; i++)
-                       *pos++ = (u8) (wpa_s->mlme.curr_rates[i] / 5);
-       }
-
-       if (wpa_s->mlme.extra_ie && wpa_s->mlme.auth_alg != WLAN_AUTH_FT) {
-               pos = buf + blen;
-               blen += wpa_s->mlme.extra_ie_len;
-               os_memcpy(pos, wpa_s->mlme.extra_ie, wpa_s->mlme.extra_ie_len);
-       }
-
-#ifdef CONFIG_IEEE80211R
-       if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X ||
-            wpa_s->mlme.key_mgmt == KEY_MGMT_FT_PSK) &&
-           wpa_s->mlme.auth_alg != WLAN_AUTH_FT &&
-           bss && bss->mdie &&
-           bss->mdie_len >= 2 + sizeof(struct rsn_mdie) &&
-           bss->mdie[1] >= sizeof(struct rsn_mdie)) {
-               pos = buf + blen;
-               blen += 2 + sizeof(struct rsn_mdie);
-               *pos++ = WLAN_EID_MOBILITY_DOMAIN;
-               *pos++ = sizeof(struct rsn_mdie);
-               os_memcpy(pos, bss->mdie + 2, MOBILITY_DOMAIN_ID_LEN);
-               pos += MOBILITY_DOMAIN_ID_LEN;
-               *pos++ = 0; /* FIX: copy from the target AP's MDIE */
-       }
-
-       if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X ||
-            wpa_s->mlme.key_mgmt == KEY_MGMT_FT_PSK) &&
-           wpa_s->mlme.auth_alg == WLAN_AUTH_FT && wpa_s->mlme.ft_ies) {
-               pos = buf + blen;
-               os_memcpy(pos, wpa_s->mlme.ft_ies, wpa_s->mlme.ft_ies_len);
-               pos += wpa_s->mlme.ft_ies_len;
-               blen += wpa_s->mlme.ft_ies_len;
-       }
-#endif /* CONFIG_IEEE80211R */
-
-       if (wmm && wpa_s->mlme.wmm_enabled) {
-               pos = buf + blen;
-               blen += 9;
-               *pos++ = WLAN_EID_VENDOR_SPECIFIC;
-               *pos++ = 7; /* len */
-               *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
-               *pos++ = 0x50;
-               *pos++ = 0xf2;
-               *pos++ = 2; /* WMM */
-               *pos++ = 0; /* WMM info */
-               *pos++ = 1; /* WMM ver */
-               *pos++ = 0;
-       }
-
-       os_free(wpa_s->mlme.assocreq_ies);
-       wpa_s->mlme.assocreq_ies_len = (buf + blen) - ies;
-       wpa_s->mlme.assocreq_ies = os_malloc(wpa_s->mlme.assocreq_ies_len);
-       if (wpa_s->mlme.assocreq_ies) {
-               os_memcpy(wpa_s->mlme.assocreq_ies, ies,
-                         wpa_s->mlme.assocreq_ies_len);
-       }
-
-       ieee80211_sta_tx(wpa_s, buf, blen);
-       os_free(buf);
-}
-
-
-static void ieee80211_send_deauth(struct wpa_supplicant *wpa_s, u16 reason)
-{
-       u8 *buf;
-       size_t len;
-       struct ieee80211_mgmt *mgmt;
-
-       buf = os_zalloc(sizeof(*mgmt));
-       if (buf == NULL) {
-               wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
-                          "deauth frame");
-               return;
-       }
-
-       mgmt = (struct ieee80211_mgmt *) buf;
-       len = 24;
-       os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
-       os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-       os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-       mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-                                          WLAN_FC_STYPE_DEAUTH);
-       len += 2;
-       mgmt->u.deauth.reason_code = host_to_le16(reason);
-
-       ieee80211_sta_tx(wpa_s, buf, len);
-       os_free(buf);
-}
-
-
-static void ieee80211_send_disassoc(struct wpa_supplicant *wpa_s, u16 reason)
-{
-       u8 *buf;
-       size_t len;
-       struct ieee80211_mgmt *mgmt;
-
-       buf = os_zalloc(sizeof(*mgmt));
-       if (buf == NULL) {
-               wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
-                          "disassoc frame");
-               return;
-       }
-
-       mgmt = (struct ieee80211_mgmt *) buf;
-       len = 24;
-       os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
-       os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-       os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-       mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-                                          WLAN_FC_STYPE_DISASSOC);
-       len += 2;
-       mgmt->u.disassoc.reason_code = host_to_le16(reason);
-
-       ieee80211_sta_tx(wpa_s, buf, len);
-       os_free(buf);
-}
-
-
-static int ieee80211_privacy_mismatch(struct wpa_supplicant *wpa_s)
-{
-       struct ieee80211_sta_bss *bss;
-       int res = 0;
-
-       if (wpa_s->mlme.mixed_cell ||
-           wpa_s->mlme.key_mgmt != KEY_MGMT_NONE)
-               return 0;
-
-       bss = ieee80211_bss_get(wpa_s, wpa_s->bssid);
-       if (bss == NULL)
-               return 0;
-
-       if (ieee80211_sta_wep_configured(wpa_s) !=
-           !!(bss->capability & WLAN_CAPABILITY_PRIVACY))
-               res = 1;
-
-       return res;
-}
-
-
-static void ieee80211_associate(struct wpa_supplicant *wpa_s)
-{
-       wpa_s->mlme.assoc_tries++;
-       if (wpa_s->mlme.assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {
-               wpa_printf(MSG_DEBUG, "MLME: association with AP " MACSTR
-                          " timed out", MAC2STR(wpa_s->bssid));
-               return;
-       }
-
-       wpa_s->mlme.state = IEEE80211_ASSOCIATE;
-       wpa_printf(MSG_DEBUG, "MLME: associate with AP " MACSTR,
-                  MAC2STR(wpa_s->bssid));
-       if (ieee80211_privacy_mismatch(wpa_s)) {
-               wpa_printf(MSG_DEBUG, "MLME: mismatch in privacy "
-                          "configuration and mixed-cell disabled - abort "
-                          "association");
-               return;
-       }
-
-       ieee80211_send_assoc(wpa_s);
-
-       ieee80211_reschedule_timer(wpa_s, IEEE80211_ASSOC_TIMEOUT);
-}
-
-
-static void ieee80211_associated(struct wpa_supplicant *wpa_s)
-{
-       int disassoc;
-
-       /* TODO: start monitoring current AP signal quality and number of
-        * missed beacons. Scan other channels every now and then and search
-        * for better APs. */
-       /* TODO: remove expired BSSes */
-
-       wpa_s->mlme.state = IEEE80211_ASSOCIATED;
-
-#if 0 /* FIX */
-       sta = sta_info_get(local, wpa_s->bssid);
-       if (sta == NULL) {
-               wpa_printf(MSG_DEBUG "MLME: No STA entry for own AP " MACSTR,
-                          MAC2STR(wpa_s->bssid));
-               disassoc = 1;
-       } else {
-               disassoc = 0;
-               if (time_after(jiffies,
-                              sta->last_rx + IEEE80211_MONITORING_INTERVAL)) {
-                       if (wpa_s->mlme.probereq_poll) {
-                               wpa_printf(MSG_DEBUG "MLME: No ProbeResp from "
-                                          "current AP " MACSTR " - assume "
-                                          "out of range",
-                                          MAC2STR(wpa_s->bssid));
-                               disassoc = 1;
-                       } else {
-                               ieee80211_send_probe_req(
-                                       wpa_s->bssid,
-                                       wpa_s->mlme.scan_ssid,
-                                       wpa_s->mlme.scan_ssid_len);
-                               wpa_s->mlme.probereq_poll = 1;
-                       }
-               } else {
-                       wpa_s->mlme.probereq_poll = 0;
-                       if (time_after(jiffies, wpa_s->mlme.last_probe +
-                                      IEEE80211_PROBE_INTERVAL)) {
-                               wpa_s->mlme.last_probe = jiffies;
-                               ieee80211_send_probe_req(wpa_s->bssid,
-                                                        wpa_s->mlme.ssid,
-                                                        wpa_s->mlme.ssid_len);
-                       }
-               }
-               sta_info_release(local, sta);
-       }
-#else
-       disassoc = 0;
-#endif
-       if (disassoc) {
-               wpa_supplicant_event(wpa_s, EVENT_DISASSOC, NULL);
-               ieee80211_reschedule_timer(wpa_s,
-                                          IEEE80211_MONITORING_INTERVAL +
-                                          30000);
-       } else {
-               ieee80211_reschedule_timer(wpa_s,
-                                          IEEE80211_MONITORING_INTERVAL);
-       }
-}
-
-
-static void ieee80211_send_probe_req(struct wpa_supplicant *wpa_s,
-                                    const u8 *dst,
-                                    const u8 *ssid, size_t ssid_len)
-{
-       u8 *buf;
-       size_t len;
-       struct ieee80211_mgmt *mgmt;
-       u8 *pos, *supp_rates;
-       u8 *esupp_rates = NULL;
-       int i;
-
-       buf = os_malloc(sizeof(*mgmt) + 200 + wpa_s->mlme.extra_probe_ie_len);
-       if (buf == NULL) {
-               wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
-                          "probe request");
-               return;
-       }
-
-       mgmt = (struct ieee80211_mgmt *) buf;
-       len = 24;
-       os_memset(mgmt, 0, 24);
-       mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-                                          WLAN_FC_STYPE_PROBE_REQ);
-       os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-       if (dst) {
-               os_memcpy(mgmt->da, dst, ETH_ALEN);
-               os_memcpy(mgmt->bssid, dst, ETH_ALEN);
-       } else {
-               os_memset(mgmt->da, 0xff, ETH_ALEN);
-               os_memset(mgmt->bssid, 0xff, ETH_ALEN);
-       }
-       pos = buf + len;
-       len += 2 + ssid_len;
-       *pos++ = WLAN_EID_SSID;
-       *pos++ = ssid_len;
-       os_memcpy(pos, ssid, ssid_len);
-
-       supp_rates = buf + len;
-       len += 2;
-       supp_rates[0] = WLAN_EID_SUPP_RATES;
-       supp_rates[1] = 0;
-       for (i = 0; i < wpa_s->mlme.num_curr_rates; i++) {
-               if (esupp_rates) {
-                       pos = buf + len;
-                       len++;
-                       esupp_rates[1]++;
-               } else if (supp_rates[1] == 8) {
-                       esupp_rates = pos;
-                       esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES;
-                       esupp_rates[1] = 1;
-                       pos = &esupp_rates[2];
-                       len += 3;
-               } else {
-                       pos = buf + len;
-                       len++;
-                       supp_rates[1]++;
-               }
-               *pos++ = wpa_s->mlme.curr_rates[i] / 5;
-       }
-
-       if (wpa_s->mlme.extra_probe_ie) {
-               os_memcpy(pos, wpa_s->mlme.extra_probe_ie,
-                         wpa_s->mlme.extra_probe_ie_len);
-               len += wpa_s->mlme.extra_probe_ie_len;
-       }
-
-       ieee80211_sta_tx(wpa_s, buf, len);
-       os_free(buf);
-}
-
-
-static int ieee80211_sta_wep_configured(struct wpa_supplicant *wpa_s)
-{
-#if 0 /* FIX */
-       if (sdata == NULL || sdata->default_key == NULL ||
-           sdata->default_key->alg != ALG_WEP)
-               return 0;
-       return 1;
-#else
-       return 0;
-#endif
-}
-
-
-static void ieee80211_auth_completed(struct wpa_supplicant *wpa_s)
-{
-       wpa_printf(MSG_DEBUG, "MLME: authenticated");
-       wpa_s->mlme.authenticated = 1;
-       ieee80211_associate(wpa_s);
-}
-
-
-static void ieee80211_auth_challenge(struct wpa_supplicant *wpa_s,
-                                    struct ieee80211_mgmt *mgmt,
-                                    size_t len,
-                                    struct ieee80211_rx_status *rx_status)
-{
-       u8 *pos;
-       struct ieee802_11_elems elems;
-
-       wpa_printf(MSG_DEBUG, "MLME: replying to auth challenge");
-       pos = mgmt->u.auth.variable;
-       if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems, 0)
-           == ParseFailed) {
-               wpa_printf(MSG_DEBUG, "MLME: failed to parse Auth(challenge)");
-               return;
-       }
-       if (elems.challenge == NULL) {
-               wpa_printf(MSG_DEBUG, "MLME: no challenge IE in shared key "
-                          "auth frame");
-               return;
-       }
-       ieee80211_send_auth(wpa_s, 3, elems.challenge - 2,
-                           elems.challenge_len + 2, 1);
-}
-
-
-static void ieee80211_rx_mgmt_auth(struct wpa_supplicant *wpa_s,
-                                  struct ieee80211_mgmt *mgmt,
-                                  size_t len,
-                                  struct ieee80211_rx_status *rx_status)
-{
-       struct wpa_ssid *ssid = wpa_s->current_ssid;
-       u16 auth_alg, auth_transaction, status_code;
-       int adhoc;
-
-       adhoc = ssid && ssid->mode == WPAS_MODE_IBSS;
-
-       if (wpa_s->mlme.state != IEEE80211_AUTHENTICATE && !adhoc) {
-               wpa_printf(MSG_DEBUG, "MLME: authentication frame received "
-                          "from " MACSTR ", but not in authenticate state - "
-                          "ignored", MAC2STR(mgmt->sa));
-               return;
-       }
-
-       if (len < 24 + 6) {
-               wpa_printf(MSG_DEBUG, "MLME: too short (%lu) authentication "
-                          "frame received from " MACSTR " - ignored",
-                          (unsigned long) len, MAC2STR(mgmt->sa));
-               return;
-       }
-
-       if (!adhoc && os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) {
-               wpa_printf(MSG_DEBUG, "MLME: authentication frame received "
-                          "from unknown AP (SA=" MACSTR " BSSID=" MACSTR
-                          ") - ignored",
-                          MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
-               return;
-       }
-
-       if (adhoc && os_memcmp(wpa_s->bssid, mgmt->bssid, ETH_ALEN) != 0) {
-               wpa_printf(MSG_DEBUG, "MLME: authentication frame received "
-                          "from unknown BSSID (SA=" MACSTR " BSSID=" MACSTR
-                          ") - ignored",
-                          MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
-               return;
-       }
-
-       auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
-       auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
-       status_code = le_to_host16(mgmt->u.auth.status_code);
-
-       wpa_printf(MSG_DEBUG, "MLME: RX authentication from " MACSTR
-                  " (alg=%d transaction=%d status=%d)",
-                  MAC2STR(mgmt->sa), auth_alg, auth_transaction, status_code);
-
-       if (adhoc) {
-               /* IEEE 802.11 standard does not require authentication in IBSS
-                * networks and most implementations do not seem to use it.
-                * However, try to reply to authentication attempts if someone
-                * has actually implemented this.
-                * TODO: Could implement shared key authentication. */
-               if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) {
-                       wpa_printf(MSG_DEBUG, "MLME: unexpected IBSS "
-                                  "authentication frame (alg=%d "
-                                  "transaction=%d)",
-                                  auth_alg, auth_transaction);
-                       return;
-               }
-               ieee80211_send_auth(wpa_s, 2, NULL, 0, 0);
-       }
-
-       if (auth_alg != wpa_s->mlme.auth_alg ||
-           auth_transaction != wpa_s->mlme.auth_transaction) {
-               wpa_printf(MSG_DEBUG, "MLME: unexpected authentication frame "
-                          "(alg=%d transaction=%d)",
-                          auth_alg, auth_transaction);
-               return;
-       }
-
-       if (status_code != WLAN_STATUS_SUCCESS) {
-               wpa_printf(MSG_DEBUG, "MLME: AP denied authentication "
-                          "(auth_alg=%d code=%d)", wpa_s->mlme.auth_alg,
-                          status_code);
-               if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) {
-                       const int num_algs = 3;
-                       u8 algs[num_algs];
-                       int i, pos;
-                       algs[0] = algs[1] = algs[2] = 0xff;
-                       if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_OPEN)
-                               algs[0] = WLAN_AUTH_OPEN;
-                       if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_SHARED)
-                               algs[1] = WLAN_AUTH_SHARED_KEY;
-                       if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_LEAP)
-                               algs[2] = WLAN_AUTH_LEAP;
-                       if (wpa_s->mlme.auth_alg == WLAN_AUTH_OPEN)
-                               pos = 0;
-                       else if (wpa_s->mlme.auth_alg == WLAN_AUTH_SHARED_KEY)
-                               pos = 1;
-                       else
-                               pos = 2;
-                       for (i = 0; i < num_algs; i++) {
-                               pos++;
-                               if (pos >= num_algs)
-                                       pos = 0;
-                               if (algs[pos] == wpa_s->mlme.auth_alg ||
-                                   algs[pos] == 0xff)
-                                       continue;
-                               if (algs[pos] == WLAN_AUTH_SHARED_KEY &&
-                                   !ieee80211_sta_wep_configured(wpa_s))
-                                       continue;
-                               wpa_s->mlme.auth_alg = algs[pos];
-                               wpa_printf(MSG_DEBUG, "MLME: set auth_alg=%d "
-                                          "for next try",
-                                          wpa_s->mlme.auth_alg);
-                               break;
-                       }
-               }
-               return;
-       }
-
-       switch (wpa_s->mlme.auth_alg) {
-       case WLAN_AUTH_OPEN:
-       case WLAN_AUTH_LEAP:
-               ieee80211_auth_completed(wpa_s);
-               break;
-       case WLAN_AUTH_SHARED_KEY:
-               if (wpa_s->mlme.auth_transaction == 4)
-                       ieee80211_auth_completed(wpa_s);
-               else
-                       ieee80211_auth_challenge(wpa_s, mgmt, len,
-                                                rx_status);
-               break;
-#ifdef CONFIG_IEEE80211R
-       case WLAN_AUTH_FT:
-       {
-               union wpa_event_data data;
-               struct wpabuf *ric = NULL;
-               os_memset(&data, 0, sizeof(data));
-               data.ft_ies.ies = mgmt->u.auth.variable;
-               data.ft_ies.ies_len = len -
-                       (mgmt->u.auth.variable - (u8 *) mgmt);
-               os_memcpy(data.ft_ies.target_ap, wpa_s->bssid, ETH_ALEN);
-               if (os_strcmp(wpa_s->driver->name, "test") == 0 &&
-                   wpa_s->mlme.wmm_enabled) {
-                       ric = wpabuf_alloc(200);
-                       if (ric) {
-                               /* Build simple RIC-Request: RDIE | TSPEC */
-
-                               /* RIC Data (RDIE) */
-                               wpabuf_put_u8(ric, WLAN_EID_RIC_DATA);
-                               wpabuf_put_u8(ric, 4);
-                               wpabuf_put_u8(ric, 0); /* RDIE Identifier */
-                               wpabuf_put_u8(ric, 1); /* Resource Descriptor
-                                                       * Count */
-                               wpabuf_put_le16(ric, 0); /* Status Code */
-
-                               /* WMM TSPEC */
-                               ieee80211_build_tspec(ric);
-
-                               data.ft_ies.ric_ies = wpabuf_head(ric);
-                               data.ft_ies.ric_ies_len = wpabuf_len(ric);
-                       }
-               }
-
-               wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &data);
-               wpabuf_free(ric);
-               ieee80211_auth_completed(wpa_s);
-               break;
-       }
-#endif /* CONFIG_IEEE80211R */
-       }
-}
-
-
-static void ieee80211_rx_mgmt_deauth(struct wpa_supplicant *wpa_s,
-                                    struct ieee80211_mgmt *mgmt,
-                                    size_t len,
-                                    struct ieee80211_rx_status *rx_status)
-{
-       u16 reason_code;
-
-       if (len < 24 + 2) {
-               wpa_printf(MSG_DEBUG, "MLME: too short (%lu) deauthentication "
-                          "frame received from " MACSTR " - ignored",
-                          (unsigned long) len, MAC2STR(mgmt->sa));
-               return;
-       }
-
-       if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) {
-               wpa_printf(MSG_DEBUG, "MLME: deauthentication frame received "
-                          "from unknown AP (SA=" MACSTR " BSSID=" MACSTR
-                          ") - ignored",
-                          MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
-               return;
-       }
-
-       reason_code = le_to_host16(mgmt->u.deauth.reason_code);
-
-       wpa_printf(MSG_DEBUG, "MLME: RX deauthentication from " MACSTR
-                  " (reason=%d)", MAC2STR(mgmt->sa), reason_code);
-
-       if (wpa_s->mlme.authenticated)
-               wpa_printf(MSG_DEBUG, "MLME: deauthenticated");
-
-       if (wpa_s->mlme.state == IEEE80211_AUTHENTICATE ||
-           wpa_s->mlme.state == IEEE80211_ASSOCIATE ||
-           wpa_s->mlme.state == IEEE80211_ASSOCIATED) {
-               wpa_s->mlme.state = IEEE80211_AUTHENTICATE;
-               ieee80211_reschedule_timer(wpa_s,
-                                          IEEE80211_RETRY_AUTH_INTERVAL);
-       }
-
-       ieee80211_set_associated(wpa_s, 0);
-       wpa_s->mlme.authenticated = 0;
-}
-
-
-static void ieee80211_rx_mgmt_disassoc(struct wpa_supplicant *wpa_s,
-                                      struct ieee80211_mgmt *mgmt,
-                                      size_t len,
-                                      struct ieee80211_rx_status *rx_status)
-{
-       u16 reason_code;
-
-       if (len < 24 + 2) {
-               wpa_printf(MSG_DEBUG, "MLME: too short (%lu) disassociation "
-                          "frame received from " MACSTR " - ignored",
-                          (unsigned long) len, MAC2STR(mgmt->sa));
-               return;
-       }
-
-       if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) {
-               wpa_printf(MSG_DEBUG, "MLME: disassociation frame received "
-                          "from unknown AP (SA=" MACSTR " BSSID=" MACSTR
-                          ") - ignored",
-                          MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
-               return;
-       }
-
-       reason_code = le_to_host16(mgmt->u.disassoc.reason_code);
-
-       wpa_printf(MSG_DEBUG, "MLME: RX disassociation from " MACSTR
-                  " (reason=%d)", MAC2STR(mgmt->sa), reason_code);
-
-       if (wpa_s->mlme.associated)
-               wpa_printf(MSG_DEBUG, "MLME: disassociated");
-
-       if (wpa_s->mlme.state == IEEE80211_ASSOCIATED) {
-               wpa_s->mlme.state = IEEE80211_ASSOCIATE;
-               ieee80211_reschedule_timer(wpa_s,
-                                          IEEE80211_RETRY_AUTH_INTERVAL);
-       }
-
-       ieee80211_set_associated(wpa_s, 0);
-}
-
-
-static void ieee80211_build_tspec(struct wpabuf *buf)
-{
-       struct wmm_tspec_element *tspec;
-       int tid, up;
-
-       tspec = wpabuf_put(buf, sizeof(*tspec));
-       tspec->eid = WLAN_EID_VENDOR_SPECIFIC;
-       tspec->length = sizeof(*tspec) - 2;
-       tspec->oui[0] = 0x00;
-       tspec->oui[1] = 0x50;
-       tspec->oui[2] = 0xf2;
-       tspec->oui_type = 2;
-       tspec->oui_subtype = 2;
-       tspec->version = 1;
-
-       tid = 1;
-       up = 6; /* Voice */
-       tspec->ts_info[0] = (tid << 1) |
-               (WMM_TSPEC_DIRECTION_BI_DIRECTIONAL << 5) |
-               BIT(7);
-       tspec->ts_info[1] = up << 3;
-       tspec->nominal_msdu_size = host_to_le16(1530);
-       tspec->mean_data_rate = host_to_le32(128000); /* bits per second */
-       tspec->minimum_phy_rate = host_to_le32(6000000);
-       tspec->surplus_bandwidth_allowance = host_to_le16(0x3000); /* 150% */
-}
-
-
-static void ieee80211_tx_addts(struct wpa_supplicant *wpa_s)
-{
-       struct wpabuf *buf;
-       struct ieee80211_mgmt *mgmt;
-       size_t alen;
-
-       wpa_printf(MSG_DEBUG, "MLME: Send ADDTS Request for Voice TSPEC");
-       mgmt = NULL;
-       alen = mgmt->u.action.u.wmm_action.variable - (u8 *) mgmt;
-
-       buf = wpabuf_alloc(alen + sizeof(struct wmm_tspec_element));
-       if (buf == NULL)
-               return;
-
-       mgmt = wpabuf_put(buf, alen);
-       os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
-       os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-       os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-       mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-                                          WLAN_FC_STYPE_ACTION);
-       mgmt->u.action.category = WLAN_ACTION_WMM;
-       mgmt->u.action.u.wmm_action.action_code = WMM_ACTION_CODE_ADDTS_REQ;
-       mgmt->u.action.u.wmm_action.dialog_token = 1;
-       mgmt->u.action.u.wmm_action.status_code = 0;
-
-       ieee80211_build_tspec(buf);
-
-       ieee80211_sta_tx(wpa_s, wpabuf_head(buf), wpabuf_len(buf));
-       wpabuf_free(buf);
-}
-
-
-static void ieee80211_rx_mgmt_assoc_resp(struct wpa_supplicant *wpa_s,
-                                        struct ieee80211_mgmt *mgmt,
-                                        size_t len,
-                                        struct ieee80211_rx_status *rx_status,
-                                        int reassoc)
-{
-       u8 rates[32];
-       size_t rates_len;
-       u16 capab_info, status_code, aid;
-       struct ieee802_11_elems elems;
-       u8 *pos;
-
-       /* AssocResp and ReassocResp have identical structure, so process both
-        * of them in this function. */
-
-       if (wpa_s->mlme.state != IEEE80211_ASSOCIATE) {
-               wpa_printf(MSG_DEBUG, "MLME: association frame received from "
-                          MACSTR ", but not in associate state - ignored",
-                          MAC2STR(mgmt->sa));
-               return;
-       }
-
-       if (len < 24 + 6) {
-               wpa_printf(MSG_DEBUG, "MLME: too short (%lu) association "
-                          "frame received from " MACSTR " - ignored",
-                          (unsigned long) len, MAC2STR(mgmt->sa));
-               return;
-       }
-
-       if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) {
-               wpa_printf(MSG_DEBUG, "MLME: association frame received from "
-                          "unknown AP (SA=" MACSTR " BSSID=" MACSTR ") - "
-                          "ignored", MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
-               return;
-       }
-
-       capab_info = le_to_host16(mgmt->u.assoc_resp.capab_info);
-       status_code = le_to_host16(mgmt->u.assoc_resp.status_code);
-       aid = le_to_host16(mgmt->u.assoc_resp.aid);
-       if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
-               wpa_printf(MSG_DEBUG, "MLME: invalid aid value %d; bits 15:14 "
-                          "not set", aid);
-       aid &= ~(BIT(15) | BIT(14));
-
-       wpa_printf(MSG_DEBUG, "MLME: RX %sssocResp from " MACSTR
-                  " (capab=0x%x status=%d aid=%d)",
-                  reassoc ? "Rea" : "A", MAC2STR(mgmt->sa),
-                  capab_info, status_code, aid);
-
-       pos = mgmt->u.assoc_resp.variable;
-       if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems, 0)
-           == ParseFailed) {
-               wpa_printf(MSG_DEBUG, "MLME: failed to parse AssocResp");
-               return;
-       }
-
-       if (status_code != WLAN_STATUS_SUCCESS) {
-               wpa_printf(MSG_DEBUG, "MLME: AP denied association (code=%d)",
-                          status_code);
-#ifdef CONFIG_IEEE80211W
-               if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
-                   elems.timeout_int && elems.timeout_int_len == 5 &&
-                   elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) {
-                       u32 tu, ms;
-                       tu = WPA_GET_LE32(elems.timeout_int + 1);
-                       ms = tu * 1024 / 1000;
-                       wpa_printf(MSG_DEBUG, "MLME: AP rejected association "
-                                  "temporarily; comeback duration %u TU "
-                                  "(%u ms)", tu, ms);
-                       if (ms > IEEE80211_ASSOC_TIMEOUT) {
-                               wpa_printf(MSG_DEBUG, "MLME: Update timer "
-                                          "based on comeback duration");
-                               ieee80211_reschedule_timer(wpa_s, ms);
-                       }
-               }
-#endif /* CONFIG_IEEE80211W */
-               return;
-       }
-
-       if (elems.supp_rates == NULL) {
-               wpa_printf(MSG_DEBUG, "MLME: no SuppRates element in "
-                          "AssocResp");
-               return;
-       }
-
-       if (wpa_s->mlme.auth_alg == WLAN_AUTH_FT) {
-               if (!reassoc) {
-                       wpa_printf(MSG_DEBUG, "MLME: AP tried to use "
-                                  "association, not reassociation, response "
-                                  "with FT");
-                       return;
-               }
-               if (wpa_ft_validate_reassoc_resp(
-                           wpa_s->wpa, pos, len - (pos - (u8 *) mgmt),
-                           mgmt->sa) < 0) {
-                       wpa_printf(MSG_DEBUG, "MLME: FT validation of Reassoc"
-                                  "Resp failed");
-                       return;
-               }
-       } else if (wpa_sm_set_ft_params(wpa_s->wpa, pos,
-                                       len - (pos - (u8 *) mgmt)) < 0)
-               return;
-
-       wpa_printf(MSG_DEBUG, "MLME: associated");
-       wpa_s->mlme.aid = aid;
-       wpa_s->mlme.ap_capab = capab_info;
-
-       os_free(wpa_s->mlme.assocresp_ies);
-       wpa_s->mlme.assocresp_ies_len = len - (pos - (u8 *) mgmt);
-       wpa_s->mlme.assocresp_ies = os_malloc(wpa_s->mlme.assocresp_ies_len);
-       if (wpa_s->mlme.assocresp_ies) {
-               os_memcpy(wpa_s->mlme.assocresp_ies, pos,
-                         wpa_s->mlme.assocresp_ies_len);
-       }
-
-       ieee80211_set_associated(wpa_s, 1);
-
-       rates_len = elems.supp_rates_len;
-       if (rates_len > sizeof(rates))
-               rates_len = sizeof(rates);
-       os_memcpy(rates, elems.supp_rates, rates_len);
-       if (elems.ext_supp_rates) {
-               size_t _len = elems.ext_supp_rates_len;
-               if (_len > sizeof(rates) - rates_len)
-                       _len = sizeof(rates) - rates_len;
-               os_memcpy(rates + rates_len, elems.ext_supp_rates, _len);
-               rates_len += _len;
-       }
-
-       if (wpa_drv_set_bssid(wpa_s, wpa_s->bssid) < 0) {
-               wpa_printf(MSG_DEBUG, "MLME: failed to set BSSID for the "
-                          "netstack");
-       }
-       if (wpa_drv_set_ssid(wpa_s, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len) <
-           0) {
-               wpa_printf(MSG_DEBUG, "MLME: failed to set SSID for the "
-                          "netstack");
-       }
-
-       /* Remove STA entry before adding a new one just in case to avoid
-        * problems with existing configuration (e.g., keys). */
-       wpa_drv_mlme_remove_sta(wpa_s, wpa_s->bssid);
-       if (wpa_drv_mlme_add_sta(wpa_s, wpa_s->bssid, rates, rates_len) < 0) {
-               wpa_printf(MSG_DEBUG, "MLME: failed to add STA entry to the "
-                          "netstack");
-       }
-
-       if (elems.wmm && wpa_s->mlme.wmm_enabled)
-               ieee80211_sta_wmm_params(wpa_s, elems.wmm, elems.wmm_len);
-
-       ieee80211_associated(wpa_s);
-
-       if (wpa_s->mlme.auth_alg != WLAN_AUTH_FT &&
-           os_strcmp(wpa_s->driver->name, "test") == 0 &&
-           elems.wmm && wpa_s->mlme.wmm_enabled) {
-               /* Test WMM-AC - send ADDTS for WMM TSPEC */
-               ieee80211_tx_addts(wpa_s);
-       }
-}
-
-
-/* Caller must hold local->sta_bss_lock */
-static void __ieee80211_bss_hash_add(struct wpa_supplicant *wpa_s,
-                                    struct ieee80211_sta_bss *bss)
-{
-       bss->hnext = wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)];
-       wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)] = bss;
-}
-
-
-/* Caller must hold local->sta_bss_lock */
-static void __ieee80211_bss_hash_del(struct wpa_supplicant *wpa_s,
-                                    struct ieee80211_sta_bss *bss)
-{
-       struct ieee80211_sta_bss *b, *prev = NULL;
-       b = wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)];
-       while (b) {
-               if (b == bss) {
-                       if (prev == NULL) {
-                               wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)]
-                                       = bss->hnext;
-                       } else {
-                               prev->hnext = bss->hnext;
-                       }
-                       break;
-               }
-               prev = b;
-               b = b->hnext;
-       }
-}
-
-
-static struct ieee80211_sta_bss *
-ieee80211_bss_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
-{
-       struct ieee80211_sta_bss *bss;
-
-       bss = os_zalloc(sizeof(*bss));
-       if (bss == NULL)
-               return NULL;
-       os_memcpy(bss->bssid, bssid, ETH_ALEN);
-
-       /* TODO: order by RSSI? */
-       bss->next = wpa_s->mlme.sta_bss_list;
-       wpa_s->mlme.sta_bss_list = bss;
-       __ieee80211_bss_hash_add(wpa_s, bss);
-       return bss;
-}
-
-
-static struct ieee80211_sta_bss *
-ieee80211_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid)
-{
-       struct ieee80211_sta_bss *bss;
-
-       bss = wpa_s->mlme.sta_bss_hash[STA_HASH(bssid)];
-       while (bss) {
-               if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
-                       break;
-               bss = bss->hnext;
-       }
-       return bss;
-}
-
-
-static void ieee80211_bss_free(struct wpa_supplicant *wpa_s,
-                              struct ieee80211_sta_bss *bss)
-{
-       __ieee80211_bss_hash_del(wpa_s, bss);
-       os_free(bss->ie);
-       os_free(bss->wpa_ie);
-       os_free(bss->rsn_ie);
-       os_free(bss->wmm_ie);
-       os_free(bss->mdie);
-       os_free(bss);
-}
-
-
-static void ieee80211_bss_list_deinit(struct wpa_supplicant *wpa_s)
-{
-       struct ieee80211_sta_bss *bss, *prev;
-
-       bss = wpa_s->mlme.sta_bss_list;
-       wpa_s->mlme.sta_bss_list = NULL;
-       while (bss) {
-               prev = bss;
-               bss = bss->next;
-               ieee80211_bss_free(wpa_s, prev);
-       }
-}
-
-
-static void ieee80211_bss_info(struct wpa_supplicant *wpa_s,
-                              struct ieee80211_mgmt *mgmt,
-                              size_t len,
-                              struct ieee80211_rx_status *rx_status,
-                              int beacon)
-{
-       struct ieee802_11_elems elems;
-       size_t baselen;
-       int channel, invalid = 0, clen;
-       struct ieee80211_sta_bss *bss;
-       u64 timestamp;
-       u8 *pos, *ie_pos;
-       size_t ie_len;
-
-       if (!beacon && os_memcmp(mgmt->da, wpa_s->own_addr, ETH_ALEN))
-               return; /* ignore ProbeResp to foreign address */
-
-#if 0
-       wpa_printf(MSG_MSGDUMP, "MLME: RX %s from " MACSTR " to " MACSTR,
-                  beacon ? "Beacon" : "Probe Response",
-                  MAC2STR(mgmt->sa), MAC2STR(mgmt->da));
-#endif
-
-       baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
-       if (baselen > len)
-               return;
-
-       pos = mgmt->u.beacon.timestamp;
-       timestamp = WPA_GET_LE64(pos);
-
-#if 0 /* FIX */
-       if (local->conf.mode == IW_MODE_ADHOC && beacon &&
-           os_memcmp(mgmt->bssid, local->bssid, ETH_ALEN) == 0) {
-#ifdef IEEE80211_IBSS_DEBUG
-               static unsigned long last_tsf_debug = 0;
-               u64 tsf;
-               if (local->hw->get_tsf)
-                       tsf = local->hw->get_tsf(local->mdev);
-               else
-                       tsf = -1LLU;
-               if (time_after(jiffies, last_tsf_debug + 5 * HZ)) {
-                       wpa_printf(MSG_DEBUG, "RX beacon SA=" MACSTR " BSSID="
-                                  MACSTR " TSF=0x%llx BCN=0x%llx diff=%lld "
-                                  "@%ld",
-                                  MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid),
-                                  tsf, timestamp, tsf - timestamp, jiffies);
-                       last_tsf_debug = jiffies;
-               }
-#endif /* IEEE80211_IBSS_DEBUG */
-       }
-#endif
-
-       ie_pos = mgmt->u.beacon.variable;
-       ie_len = len - baselen;
-       if (ieee802_11_parse_elems(ie_pos, ie_len, &elems, 0) == ParseFailed)
-               invalid = 1;
-
-#if 0 /* FIX */
-       if (local->conf.mode == IW_MODE_ADHOC && elems.supp_rates &&
-           os_memcmp(mgmt->bssid, local->bssid, ETH_ALEN) == 0 &&
-           (sta = sta_info_get(local, mgmt->sa))) {
-               struct ieee80211_rate *rates;
-               size_t num_rates;
-               u32 supp_rates, prev_rates;
-               int i, j, oper_mode;
-
-               rates = local->curr_rates;
-               num_rates = local->num_curr_rates;
-               oper_mode = wpa_s->mlme.sta_scanning ?
-                       local->scan_oper_phymode : local->conf.phymode;
-               for (i = 0; i < local->hw->num_modes; i++) {
-                       struct ieee80211_hw_modes *mode = &local->hw->modes[i];
-                       if (oper_mode == mode->mode) {
-                               rates = mode->rates;
-                               num_rates = mode->num_rates;
-                               break;
-                       }
-               }
-
-               supp_rates = 0;
-               for (i = 0; i < elems.supp_rates_len +
-                            elems.ext_supp_rates_len; i++) {
-                       u8 rate = 0;
-                       int own_rate;
-                       if (i < elems.supp_rates_len)
-                               rate = elems.supp_rates[i];
-                       else if (elems.ext_supp_rates)
-                               rate = elems.ext_supp_rates
-                                       [i - elems.supp_rates_len];
-                       own_rate = 5 * (rate & 0x7f);
-                       if (oper_mode == MODE_ATHEROS_TURBO)
-                               own_rate *= 2;
-                       for (j = 0; j < num_rates; j++)
-                               if (rates[j].rate == own_rate)
-                                       supp_rates |= BIT(j);
-               }
-
-               prev_rates = sta->supp_rates;
-               sta->supp_rates &= supp_rates;
-               if (sta->supp_rates == 0) {
-                       /* No matching rates - this should not really happen.
-                        * Make sure that at least one rate is marked
-                        * supported to avoid issues with TX rate ctrl. */
-                       sta->supp_rates = wpa_s->mlme.supp_rates_bits;
-               }
-               if (sta->supp_rates != prev_rates) {
-                       wpa_printf(MSG_DEBUG, "MLME: updated supp_rates set "
-                                  "for " MACSTR " based on beacon info "
-                                  "(0x%x & 0x%x -> 0x%x)",
-                                  MAC2STR(sta->addr), prev_rates,
-                                  supp_rates, sta->supp_rates);
-               }
-               sta_info_release(local, sta);
-       }
-#endif
-
-       if (elems.ssid == NULL)
-               return;
-
-       if (elems.ds_params && elems.ds_params_len == 1)
-               channel = elems.ds_params[0];
-       else
-               channel = rx_status->channel;
-
-       bss = ieee80211_bss_get(wpa_s, mgmt->bssid);
-       if (bss == NULL) {
-               bss = ieee80211_bss_add(wpa_s, mgmt->bssid);
-               if (bss == NULL)
-                       return;
-       } else {
-#if 0
-               /* TODO: order by RSSI? */
-               spin_lock_bh(&local->sta_bss_lock);
-               list_move_tail(&bss->list, &local->sta_bss_list);
-               spin_unlock_bh(&local->sta_bss_lock);
-#endif
-       }
-
-       if (bss->probe_resp && beacon) {
-               /* Do not allow beacon to override data from Probe Response. */
-               return;
-       }
-
-       bss->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
-       bss->capability = le_to_host16(mgmt->u.beacon.capab_info);
-
-       if (bss->ie == NULL || bss->ie_len < ie_len) {
-               os_free(bss->ie);
-               bss->ie = os_malloc(ie_len);
-       }
-       if (bss->ie) {
-               os_memcpy(bss->ie, ie_pos, ie_len);
-               bss->ie_len = ie_len;
-       }
-
-       if (elems.ssid && elems.ssid_len <= MAX_SSID_LEN) {
-               os_memcpy(bss->ssid, elems.ssid, elems.ssid_len);
-               bss->ssid_len = elems.ssid_len;
-       }
-
-       bss->supp_rates_len = 0;
-       if (elems.supp_rates) {
-               clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
-               if (clen > elems.supp_rates_len)
-                       clen = elems.supp_rates_len;
-               os_memcpy(&bss->supp_rates[bss->supp_rates_len],
-                         elems.supp_rates, clen);
-               bss->supp_rates_len += clen;
-       }
-       if (elems.ext_supp_rates) {
-               clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
-               if (clen > elems.ext_supp_rates_len)
-                       clen = elems.ext_supp_rates_len;
-               os_memcpy(&bss->supp_rates[bss->supp_rates_len],
-                         elems.ext_supp_rates, clen);
-               bss->supp_rates_len += clen;
-       }
-
-       if (elems.wpa_ie &&
-           (bss->wpa_ie == NULL || bss->wpa_ie_len != elems.wpa_ie_len ||
-            os_memcmp(bss->wpa_ie, elems.wpa_ie, elems.wpa_ie_len))) {
-               os_free(bss->wpa_ie);
-               bss->wpa_ie = os_malloc(elems.wpa_ie_len + 2);
-               if (bss->wpa_ie) {
-                       os_memcpy(bss->wpa_ie, elems.wpa_ie - 2,
-                                 elems.wpa_ie_len + 2);
-                       bss->wpa_ie_len = elems.wpa_ie_len + 2;
-               } else
-                       bss->wpa_ie_len = 0;
-       } else if (!elems.wpa_ie && bss->wpa_ie) {
-               os_free(bss->wpa_ie);
-               bss->wpa_ie = NULL;
-               bss->wpa_ie_len = 0;
-       }
-
-       if (elems.rsn_ie &&
-           (bss->rsn_ie == NULL || bss->rsn_ie_len != elems.rsn_ie_len ||
-            os_memcmp(bss->rsn_ie, elems.rsn_ie, elems.rsn_ie_len))) {
-               os_free(bss->rsn_ie);
-               bss->rsn_ie = os_malloc(elems.rsn_ie_len + 2);
-               if (bss->rsn_ie) {
-                       os_memcpy(bss->rsn_ie, elems.rsn_ie - 2,
-                                 elems.rsn_ie_len + 2);
-                       bss->rsn_ie_len = elems.rsn_ie_len + 2;
-               } else
-                       bss->rsn_ie_len = 0;
-       } else if (!elems.rsn_ie && bss->rsn_ie) {
-               os_free(bss->rsn_ie);
-               bss->rsn_ie = NULL;
-               bss->rsn_ie_len = 0;
-       }
-
-       if (elems.wmm &&
-           (bss->wmm_ie == NULL || bss->wmm_ie_len != elems.wmm_len ||
-            os_memcmp(bss->wmm_ie, elems.wmm, elems.wmm_len))) {
-               os_free(bss->wmm_ie);
-               bss->wmm_ie = os_malloc(elems.wmm_len + 2);
-               if (bss->wmm_ie) {
-                       os_memcpy(bss->wmm_ie, elems.wmm - 2,
-                                 elems.wmm_len + 2);
-                       bss->wmm_ie_len = elems.wmm_len + 2;
-               } else
-                       bss->wmm_ie_len = 0;
-       } else if (!elems.wmm && bss->wmm_ie) {
-               os_free(bss->wmm_ie);
-               bss->wmm_ie = NULL;
-               bss->wmm_ie_len = 0;
-       }
-
-#ifdef CONFIG_IEEE80211R
-       if (elems.mdie &&
-           (bss->mdie == NULL || bss->mdie_len != elems.mdie_len ||
-            os_memcmp(bss->mdie, elems.mdie, elems.mdie_len))) {
-               os_free(bss->mdie);
-               bss->mdie = os_malloc(elems.mdie_len + 2);
-               if (bss->mdie) {
-                       os_memcpy(bss->mdie, elems.mdie - 2,
-                                 elems.mdie_len + 2);
-                       bss->mdie_len = elems.mdie_len + 2;
-               } else
-                       bss->mdie_len = 0;
-       } else if (!elems.mdie && bss->mdie) {
-               os_free(bss->mdie);
-               bss->mdie = NULL;
-               bss->mdie_len = 0;
-       }
-#endif /* CONFIG_IEEE80211R */
-
-       bss->hw_mode = wpa_s->mlme.phymode;
-       bss->channel = channel;
-       bss->freq = wpa_s->mlme.freq;
-       if (channel != wpa_s->mlme.channel &&
-           (wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211G ||
-            wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211B) &&
-           channel >= 1 && channel <= 14) {
-               static const int freq_list[] = {
-                       2412, 2417, 2422, 2427, 2432, 2437, 2442,
-                       2447, 2452, 2457, 2462, 2467, 2472, 2484
-               };
-               /* IEEE 802.11g/b mode can receive packets from neighboring
-                * channels, so map the channel into frequency. */
-               bss->freq = freq_list[channel - 1];
-       }
-       bss->timestamp = timestamp;
-       os_get_time(&bss->last_update);
-       bss->rssi = rx_status->ssi;
-       if (!beacon)
-               bss->probe_resp++;
-}
-
-
-static void ieee80211_rx_mgmt_probe_resp(struct wpa_supplicant *wpa_s,
-                                        struct ieee80211_mgmt *mgmt,
-                                        size_t len,
-                                        struct ieee80211_rx_status *rx_status)
-{
-       ieee80211_bss_info(wpa_s, mgmt, len, rx_status, 0);
-}
-
-
-static void ieee80211_rx_mgmt_beacon(struct wpa_supplicant *wpa_s,
-                                    struct ieee80211_mgmt *mgmt,
-                                    size_t len,
-                                    struct ieee80211_rx_status *rx_status)
-{
-       int use_protection;
-       size_t baselen;
-       struct ieee802_11_elems elems;
-
-       ieee80211_bss_info(wpa_s, mgmt, len, rx_status, 1);
-
-       if (!wpa_s->mlme.associated ||
-           os_memcmp(wpa_s->bssid, mgmt->bssid, ETH_ALEN) != 0)
-               return;
-
-       /* Process beacon from the current BSS */
-       baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
-       if (baselen > len)
-               return;
-
-       if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
-                                  &elems, 0) == ParseFailed)
-               return;
-
-       use_protection = 0;
-       if (elems.erp_info && elems.erp_info_len >= 1) {
-               use_protection =
-                       (elems.erp_info[0] & ERP_INFO_USE_PROTECTION) != 0;
-       }
-
-       if (use_protection != !!wpa_s->mlme.use_protection) {
-               wpa_printf(MSG_DEBUG, "MLME: CTS protection %s (BSSID=" MACSTR
-                          ")",
-                          use_protection ? "enabled" : "disabled",
-                          MAC2STR(wpa_s->bssid));
-               wpa_s->mlme.use_protection = use_protection ? 1 : 0;
-               wpa_s->mlme.cts_protect_erp_frames = use_protection;
-       }
-
-       if (elems.wmm && wpa_s->mlme.wmm_enabled) {
-               ieee80211_sta_wmm_params(wpa_s, elems.wmm,
-                                        elems.wmm_len);
-       }
-}
-
-
-static void ieee80211_rx_mgmt_probe_req(struct wpa_supplicant *wpa_s,
-                                       struct ieee80211_mgmt *mgmt,
-                                       size_t len,
-                                       struct ieee80211_rx_status *rx_status)
-{
-       int tx_last_beacon, adhoc;
-#if 0 /* FIX */
-       struct ieee80211_mgmt *resp;
-#endif
-       u8 *pos, *end;
-       struct wpa_ssid *ssid = wpa_s->current_ssid;
-
-       adhoc = ssid && ssid->mode == WPAS_MODE_IBSS;
-
-       if (!adhoc || wpa_s->mlme.state != IEEE80211_IBSS_JOINED ||
-           len < 24 + 2 || wpa_s->mlme.probe_resp == NULL)
-               return;
-
-#if 0 /* FIX */
-       if (local->hw->tx_last_beacon)
-               tx_last_beacon = local->hw->tx_last_beacon(local->mdev);
-       else
-#endif
-               tx_last_beacon = 1;
-
-#ifdef IEEE80211_IBSS_DEBUG
-       wpa_printf(MSG_DEBUG, "MLME: RX ProbeReq SA=" MACSTR " DA=" MACSTR
-                  " BSSID=" MACSTR " (tx_last_beacon=%d)",
-                  MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
-                  MAC2STR(mgmt->bssid), tx_last_beacon);
-#endif /* IEEE80211_IBSS_DEBUG */
-
-       if (!tx_last_beacon)
-               return;
-
-       if (os_memcmp(mgmt->bssid, wpa_s->bssid, ETH_ALEN) != 0 &&
-           os_memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)
-               return;
-
-       end = ((u8 *) mgmt) + len;
-       pos = mgmt->u.probe_req.variable;
-       if (pos[0] != WLAN_EID_SSID ||
-           pos + 2 + pos[1] > end) {
-               wpa_printf(MSG_DEBUG, "MLME: Invalid SSID IE in ProbeReq from "
-                          MACSTR, MAC2STR(mgmt->sa));
-               return;
-       }
-       if (pos[1] != 0 &&
-           (pos[1] != wpa_s->mlme.ssid_len ||
-            os_memcmp(pos + 2, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len) != 0))
-       {
-               /* Ignore ProbeReq for foreign SSID */
-               return;
-       }
-
-#if 0 /* FIX */
-       /* Reply with ProbeResp */
-       skb = skb_copy(wpa_s->mlme.probe_resp, GFP_ATOMIC);
-       if (skb == NULL)
-               return;
-
-       resp = (struct ieee80211_mgmt *) skb->data;
-       os_memcpy(resp->da, mgmt->sa, ETH_ALEN);
-#ifdef IEEE80211_IBSS_DEBUG
-       wpa_printf(MSG_DEBUG, "MLME: Sending ProbeResp to " MACSTR,
-                  MAC2STR(resp->da));
-#endif /* IEEE80211_IBSS_DEBUG */
-       ieee80211_sta_tx(wpa_s, skb, 0, 1);
-#endif
-}
-
-
-#ifdef CONFIG_IEEE80211R
-static void ieee80211_rx_mgmt_ft_action(struct wpa_supplicant *wpa_s,
-                                       struct ieee80211_mgmt *mgmt,
-                                       size_t len,
-                                       struct ieee80211_rx_status *rx_status)
-{
-       union wpa_event_data data;
-       u16 status;
-       u8 *sta_addr, *target_ap_addr;
-
-       if (len < 24 + 1 + sizeof(mgmt->u.action.u.ft_action_resp)) {
-               wpa_printf(MSG_DEBUG, "MLME: Too short FT Action frame");
-               return;
-       }
-
-       /*
-        * Only FT Action Response is needed for now since reservation
-        * protocol is not supported.
-        */
-       if (mgmt->u.action.u.ft_action_resp.action != 2) {
-               wpa_printf(MSG_DEBUG, "MLME: Unexpected FT Action %d",
-                          mgmt->u.action.u.ft_action_resp.action);
-               return;
-       }
-
-       status = le_to_host16(mgmt->u.action.u.ft_action_resp.status_code);
-       sta_addr = mgmt->u.action.u.ft_action_resp.sta_addr;
-       target_ap_addr = mgmt->u.action.u.ft_action_resp.target_ap_addr;
-       wpa_printf(MSG_DEBUG, "MLME: Received FT Action Response: STA " MACSTR
-                  " TargetAP " MACSTR " Status Code %d",
-                  MAC2STR(sta_addr), MAC2STR(target_ap_addr), status);
-       if (os_memcmp(sta_addr, wpa_s->own_addr, ETH_ALEN) != 0) {
-               wpa_printf(MSG_DEBUG, "MLME: Foreign STA Address " MACSTR
-                          " in FT Action Response", MAC2STR(sta_addr));
-               return;
-       }
-
-       if (status) {
-               wpa_printf(MSG_DEBUG, "MLME: FT Action Response indicates "
-                          "failure (status code %d)", status);
-               /* TODO: report error to FT code(?) */
-               return;
-       }
-
-       os_memset(&data, 0, sizeof(data));
-       data.ft_ies.ies = mgmt->u.action.u.ft_action_resp.variable;
-       data.ft_ies.ies_len = len - (mgmt->u.action.u.ft_action_resp.variable -
-                                    (u8 *) mgmt);
-       data.ft_ies.ft_action = 1;
-       os_memcpy(data.ft_ies.target_ap, target_ap_addr, ETH_ALEN);
-       wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &data);
-       /* TODO: should only re-associate, if EVENT_FT_RESPONSE was processed
-        * successfully */
-       wpa_s->mlme.prev_bssid_set = 1;
-       wpa_s->mlme.auth_alg = WLAN_AUTH_FT;
-       os_memcpy(wpa_s->mlme.prev_bssid, wpa_s->bssid, ETH_ALEN);
-       os_memcpy(wpa_s->bssid, target_ap_addr, ETH_ALEN);
-       ieee80211_associate(wpa_s);
-}
-#endif /* CONFIG_IEEE80211R */
-
-
-#ifdef CONFIG_IEEE80211W
-
-/* MLME-SAQuery.response */
-static int ieee80211_sta_send_sa_query_resp(struct wpa_supplicant *wpa_s,
-                                           const u8 *addr, const u8 *trans_id)
-{
-       struct ieee80211_mgmt *mgmt;
-       int res;
-       size_t len;
-
-       mgmt = os_zalloc(sizeof(*mgmt));
-       if (mgmt == NULL) {
-               wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
-                          "SA Query action frame");
-               return -1;
-       }
-
-       len = 24;
-       os_memcpy(mgmt->da, addr, ETH_ALEN);
-       os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-       os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-       mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-                                          WLAN_FC_STYPE_ACTION);
-       mgmt->u.action.category = WLAN_ACTION_SA_QUERY;
-       mgmt->u.action.u.sa_query_resp.action = WLAN_SA_QUERY_RESPONSE;
-       os_memcpy(mgmt->u.action.u.sa_query_resp.trans_id, trans_id,
-                 WLAN_SA_QUERY_TR_ID_LEN);
-       len += 1 + sizeof(mgmt->u.action.u.sa_query_resp);
-
-       res = ieee80211_sta_tx(wpa_s, (u8 *) mgmt, len);
-       os_free(mgmt);
-
-       return res;
-}
-
-
-static void ieee80211_rx_mgmt_sa_query_action(
-       struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
-       struct ieee80211_rx_status *rx_status)
-{
-       if (len < 24 + 1 + sizeof(mgmt->u.action.u.sa_query_req)) {
-               wpa_printf(MSG_DEBUG, "MLME: Too short SA Query Action frame");
-               return;
-       }
-
-       if (mgmt->u.action.u.sa_query_req.action != WLAN_SA_QUERY_REQUEST) {
-               wpa_printf(MSG_DEBUG, "MLME: Unexpected SA Query Action %d",
-                          mgmt->u.action.u.sa_query_req.action);
-               return;
-       }
-
-       if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) {
-               wpa_printf(MSG_DEBUG, "MLME: Ignore SA Query from unknown "
-                          "source " MACSTR, MAC2STR(mgmt->sa));
-               return;
-       }
-
-       if (wpa_s->mlme.state == IEEE80211_ASSOCIATE) {
-               wpa_printf(MSG_DEBUG, "MLME: Ignore SA query request during "
-                          "association process");
-               return;
-       }
-
-       wpa_printf(MSG_DEBUG, "MLME: Replying to SA Query request");
-       ieee80211_sta_send_sa_query_resp(wpa_s, mgmt->sa, mgmt->u.action.u.
-                                        sa_query_req.trans_id);
-}
-
-#endif /* CONFIG_IEEE80211W */
-
-
-static void dump_tspec(struct wmm_tspec_element *tspec)
-{
-       int up, psb, dir, tid;
-       u16 val;
-
-       up = (tspec->ts_info[1] >> 3) & 0x07;
-       psb = (tspec->ts_info[1] >> 2) & 0x01;
-       dir = (tspec->ts_info[0] >> 5) & 0x03;
-       tid = (tspec->ts_info[0] >> 1) & 0x0f;
-       wpa_printf(MSG_DEBUG, "WMM: TS Info: UP=%d PSB=%d Direction=%d TID=%d",
-                  up, psb, dir, tid);
-       val = le_to_host16(tspec->nominal_msdu_size);
-       wpa_printf(MSG_DEBUG, "WMM: Nominal MSDU Size: %d%s",
-                  val & 0x7fff, val & 0x8000 ? " (fixed)" : "");
-       wpa_printf(MSG_DEBUG, "WMM: Mean Data Rate: %u bps",
-                  le_to_host32(tspec->mean_data_rate));
-       wpa_printf(MSG_DEBUG, "WMM: Minimum PHY Rate: %u bps",
-                  le_to_host32(tspec->minimum_phy_rate));
-       val = le_to_host16(tspec->surplus_bandwidth_allowance);
-       wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance: %u.%04u",
-                  val >> 13, 10000 * (val & 0x1fff) / 0x2000);
-       val = le_to_host16(tspec->medium_time);
-       wpa_printf(MSG_DEBUG, "WMM: Medium Time: %u (= %u usec/sec)",
-                  val, 32 * val);
-}
-
-
-static int is_wmm_tspec(const u8 *ie, size_t len)
-{
-       const struct wmm_tspec_element *tspec;
-
-       if (len < sizeof(*tspec))
-               return 0;
-
-       tspec = (const struct wmm_tspec_element *) ie;
-       if (tspec->eid != WLAN_EID_VENDOR_SPECIFIC ||
-           tspec->length < sizeof(*tspec) - 2 ||
-           tspec->oui[0] != 0x00 || tspec->oui[1] != 0x50 ||
-           tspec->oui[2] != 0xf2 || tspec->oui_type != 2 ||
-           tspec->oui_subtype != 2 || tspec->version != 1)
-               return 0;
-
-       return 1;
-}
-
-
-static void ieee80211_rx_addts_resp(
-       struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
-       size_t var_len)
-{
-       struct wmm_tspec_element *tspec;
-
-       wpa_printf(MSG_DEBUG, "WMM: Received ADDTS Response");
-       wpa_hexdump(MSG_MSGDUMP, "WMM: ADDTS Response IE(s)",
-                   mgmt->u.action.u.wmm_action.variable, var_len);
-       if (!is_wmm_tspec(mgmt->u.action.u.wmm_action.variable, var_len))
-               return;
-       tspec = (struct wmm_tspec_element *)
-               mgmt->u.action.u.wmm_action.variable;
-       dump_tspec(tspec);
-}
-
-
-static void ieee80211_rx_delts(
-       struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
-       size_t var_len)
-{
-       struct wmm_tspec_element *tspec;
-
-       wpa_printf(MSG_DEBUG, "WMM: Received DELTS");
-       wpa_hexdump(MSG_MSGDUMP, "WMM: DELTS IE(s)",
-                   mgmt->u.action.u.wmm_action.variable, var_len);
-       if (!is_wmm_tspec(mgmt->u.action.u.wmm_action.variable, var_len))
-               return;
-       tspec = (struct wmm_tspec_element *)
-               mgmt->u.action.u.wmm_action.variable;
-       dump_tspec(tspec);
-}
-
-
-static void ieee80211_rx_mgmt_wmm_action(
-       struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
-       struct ieee80211_rx_status *rx_status)
-{
-       size_t alen;
-
-       alen = mgmt->u.action.u.wmm_action.variable - (u8 *) mgmt;
-       if (len < alen) {
-               wpa_printf(MSG_DEBUG, "WMM: Received Action frame too short");
-               return;
-       }
-
-       wpa_printf(MSG_DEBUG, "WMM: Received Action frame: Action Code %d, "
-                  "Dialog Token %d, Status Code %d",
-                  mgmt->u.action.u.wmm_action.action_code,
-                  mgmt->u.action.u.wmm_action.dialog_token,
-                  mgmt->u.action.u.wmm_action.status_code);
-
-       switch (mgmt->u.action.u.wmm_action.action_code) {
-       case WMM_ACTION_CODE_ADDTS_RESP:
-               ieee80211_rx_addts_resp(wpa_s, mgmt, len, len - alen);
-               break;
-       case WMM_ACTION_CODE_DELTS:
-               ieee80211_rx_delts(wpa_s, mgmt, len, len - alen);
-               break;
-       default:
-               wpa_printf(MSG_DEBUG, "WMM: Unsupported Action Code %d",
-                          mgmt->u.action.u.wmm_action.action_code);
-               break;
-       }
-}
-
-
-static void ieee80211_rx_mgmt_action(struct wpa_supplicant *wpa_s,
-                                    struct ieee80211_mgmt *mgmt,
-                                    size_t len,
-                                    struct ieee80211_rx_status *rx_status)
-{
-       wpa_printf(MSG_DEBUG, "MLME: received Action frame");
-
-       if (len < 25)
-               return;
-
-       switch (mgmt->u.action.category) {
-#ifdef CONFIG_IEEE80211R
-       case WLAN_ACTION_FT:
-               ieee80211_rx_mgmt_ft_action(wpa_s, mgmt, len, rx_status);
-               break;
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
-       case WLAN_ACTION_SA_QUERY:
-               ieee80211_rx_mgmt_sa_query_action(wpa_s, mgmt, len, rx_status);
-               break;
-#endif /* CONFIG_IEEE80211W */
-       case WLAN_ACTION_WMM:
-               ieee80211_rx_mgmt_wmm_action(wpa_s, mgmt, len, rx_status);
-               break;
-       case WLAN_ACTION_PUBLIC:
-               if (wpa_s->mlme.public_action_cb) {
-                       wpa_s->mlme.public_action_cb(
-                               wpa_s->mlme.public_action_cb_ctx,
-                               (u8 *) mgmt, len, rx_status->freq);
-                       return;
-               }
-               break;
-       default:
-               wpa_printf(MSG_DEBUG, "MLME: unknown Action Category %d",
-                          mgmt->u.action.category);
-               break;
-       }
-}
-
-
-static void ieee80211_sta_rx_mgmt(struct wpa_supplicant *wpa_s,
-                                 const u8 *buf, size_t len,
-                                 struct ieee80211_rx_status *rx_status)
-{
-       struct ieee80211_mgmt *mgmt;
-       u16 fc;
-
-       if (len < 24)
-               return;
-
-       mgmt = (struct ieee80211_mgmt *) buf;
-       fc = le_to_host16(mgmt->frame_control);
-
-       switch (WLAN_FC_GET_STYPE(fc)) {
-       case WLAN_FC_STYPE_PROBE_REQ:
-               ieee80211_rx_mgmt_probe_req(wpa_s, mgmt, len, rx_status);
-               break;
-       case WLAN_FC_STYPE_PROBE_RESP:
-               ieee80211_rx_mgmt_probe_resp(wpa_s, mgmt, len, rx_status);
-               break;
-       case WLAN_FC_STYPE_BEACON:
-               ieee80211_rx_mgmt_beacon(wpa_s, mgmt, len, rx_status);
-               break;
-       case WLAN_FC_STYPE_AUTH:
-               ieee80211_rx_mgmt_auth(wpa_s, mgmt, len, rx_status);
-               break;
-       case WLAN_FC_STYPE_ASSOC_RESP:
-               ieee80211_rx_mgmt_assoc_resp(wpa_s, mgmt, len, rx_status, 0);
-               break;
-       case WLAN_FC_STYPE_REASSOC_RESP:
-               ieee80211_rx_mgmt_assoc_resp(wpa_s, mgmt, len, rx_status, 1);
-               break;
-       case WLAN_FC_STYPE_DEAUTH:
-               ieee80211_rx_mgmt_deauth(wpa_s, mgmt, len, rx_status);
-               break;
-       case WLAN_FC_STYPE_DISASSOC:
-               ieee80211_rx_mgmt_disassoc(wpa_s, mgmt, len, rx_status);
-               break;
-       case WLAN_FC_STYPE_ACTION:
-               ieee80211_rx_mgmt_action(wpa_s, mgmt, len, rx_status);
-               break;
-       default:
-               wpa_printf(MSG_DEBUG, "MLME: received unknown management "
-                          "frame - stype=%d", WLAN_FC_GET_STYPE(fc));
-               break;
-       }
-}
-
-
-static void ieee80211_sta_rx_scan(struct wpa_supplicant *wpa_s,
-                                 const u8 *buf, size_t len,
-                                 struct ieee80211_rx_status *rx_status)
-{
-       struct ieee80211_mgmt *mgmt;
-       u16 fc;
-
-       if (len < 24)
-               return;
-
-       mgmt = (struct ieee80211_mgmt *) buf;
-       fc = le_to_host16(mgmt->frame_control);
-
-       if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT) {
-               if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
-                       ieee80211_rx_mgmt_probe_resp(wpa_s, mgmt,
-                                                    len, rx_status);
-               } else if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) {
-                       ieee80211_rx_mgmt_beacon(wpa_s, mgmt, len, rx_status);
-               }
-       }
-}
-
-
-static int ieee80211_sta_active_ibss(struct wpa_supplicant *wpa_s)
-{
-       int active = 0;
-
-#if 0 /* FIX */
-       list_for_each(ptr, &local->sta_list) {
-               sta = list_entry(ptr, struct sta_info, list);
-               if (sta->dev == dev &&
-                   time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
-                              jiffies)) {
-                       active++;
-                       break;
-               }
-       }
-#endif
-
-       return active;
-}
-
-
-static void ieee80211_sta_expire(struct wpa_supplicant *wpa_s)
-{
-#if 0 /* FIX */
-       list_for_each_safe(ptr, n, &local->sta_list) {
-               sta = list_entry(ptr, struct sta_info, list);
-               if (time_after(jiffies, sta->last_rx +
-                              IEEE80211_IBSS_INACTIVITY_LIMIT)) {
-                       wpa_printf(MSG_DEBUG, "MLME: expiring inactive STA "
-                                  MACSTR, MAC2STR(sta->addr));
-                       sta_info_free(local, sta, 1);
-               }
-       }
-#endif
-}
-
-
-static void ieee80211_sta_merge_ibss(struct wpa_supplicant *wpa_s)
-{
-       struct wpa_driver_scan_params params;
-
-       ieee80211_reschedule_timer(wpa_s, IEEE80211_IBSS_MERGE_INTERVAL);
-
-       ieee80211_sta_expire(wpa_s);
-       if (ieee80211_sta_active_ibss(wpa_s))
-               return;
-
-       wpa_printf(MSG_DEBUG, "MLME: No active IBSS STAs - trying to scan for "
-                  "other IBSS networks with same SSID (merge)");
-       os_memset(&params, 0, sizeof(params));
-       params.ssids[0].ssid = wpa_s->mlme.ssid;
-       params.ssids[0].ssid_len = wpa_s->mlme.ssid_len;
-       params.num_ssids = wpa_s->mlme.ssid_len ? 1 : 0;
-       ieee80211_sta_req_scan(wpa_s, &params);
-}
-
-
-static void ieee80211_sta_timer(void *eloop_ctx, void *timeout_ctx)
-{
-       struct wpa_supplicant *wpa_s = eloop_ctx;
-
-       switch (wpa_s->mlme.state) {
-       case IEEE80211_DISABLED:
-               break;
-       case IEEE80211_AUTHENTICATE:
-               ieee80211_authenticate(wpa_s);
-               break;
-       case IEEE80211_ASSOCIATE:
-               ieee80211_associate(wpa_s);
-               break;
-       case IEEE80211_ASSOCIATED:
-               ieee80211_associated(wpa_s);
-               break;
-       case IEEE80211_IBSS_SEARCH:
-               ieee80211_sta_find_ibss(wpa_s);
-               break;
-       case IEEE80211_IBSS_JOINED:
-               ieee80211_sta_merge_ibss(wpa_s);
-               break;
-       default:
-               wpa_printf(MSG_DEBUG, "ieee80211_sta_timer: Unknown state %d",
-                          wpa_s->mlme.state);
-               break;
-       }
-
-       if (ieee80211_privacy_mismatch(wpa_s)) {
-               wpa_printf(MSG_DEBUG, "MLME: privacy configuration mismatch "
-                          "and mixed-cell disabled - disassociate");
-
-               ieee80211_send_disassoc(wpa_s, WLAN_REASON_UNSPECIFIED);
-               ieee80211_set_associated(wpa_s, 0);
-       }
-}
-
-
-static void ieee80211_sta_new_auth(struct wpa_supplicant *wpa_s)
-{
-       struct wpa_ssid *ssid = wpa_s->current_ssid;
-       if (ssid && ssid->mode != WPAS_MODE_INFRA)
-               return;
-
-#if 0 /* FIX */
-       if (local->hw->reset_tsf) {
-               /* Reset own TSF to allow time synchronization work. */
-               local->hw->reset_tsf(local->mdev);
-       }
-#endif
-
-       wpa_s->mlme.wmm_last_param_set = -1; /* allow any WMM update */
-
-
-       if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_OPEN)
-               wpa_s->mlme.auth_alg = WLAN_AUTH_OPEN;
-       else if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_SHARED)
-               wpa_s->mlme.auth_alg = WLAN_AUTH_SHARED_KEY;
-       else if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_LEAP)
-               wpa_s->mlme.auth_alg = WLAN_AUTH_LEAP;
-       else
-               wpa_s->mlme.auth_alg = WLAN_AUTH_OPEN;
-       wpa_printf(MSG_DEBUG, "MLME: Initial auth_alg=%d",
-                  wpa_s->mlme.auth_alg);
-       wpa_s->mlme.auth_transaction = -1;
-       wpa_s->mlme.auth_tries = wpa_s->mlme.assoc_tries = 0;
-       ieee80211_authenticate(wpa_s);
-}
-
-
-static int ieee80211_ibss_allowed(struct wpa_supplicant *wpa_s)
-{
-#if 0 /* FIX */
-       int m, c;
-
-       for (m = 0; m < local->hw->num_modes; m++) {
-               struct ieee80211_hw_modes *mode = &local->hw->modes[m];
-               if (mode->mode != local->conf.phymode)
-                       continue;
-               for (c = 0; c < mode->num_channels; c++) {
-                       struct ieee80211_channel *chan = &mode->channels[c];
-                       if (chan->flag & IEEE80211_CHAN_W_SCAN &&
-                           chan->chan == local->conf.channel) {
-                               if (chan->flag & IEEE80211_CHAN_W_IBSS)
-                                       return 1;
-                               break;
-                       }
-               }
-       }
-#endif
-
-       return 0;
-}
-
-
-static int ieee80211_sta_join_ibss(struct wpa_supplicant *wpa_s,
-                                  struct ieee80211_sta_bss *bss)
-{
-       int res = 0, rates, done = 0, bssid_changed;
-       struct ieee80211_mgmt *mgmt;
-#if 0 /* FIX */
-       struct ieee80211_tx_control control;
-       struct ieee80211_rate *rate;
-       struct rate_control_extra extra;
-#endif
-       u8 *pos, *buf;
-       size_t len;
-
-       /* Remove possible STA entries from other IBSS networks. */
-#if 0 /* FIX */
-       sta_info_flush(local, NULL);
-
-       if (local->hw->reset_tsf) {
-               /* Reset own TSF to allow time synchronization work. */
-               local->hw->reset_tsf(local->mdev);
-       }
-#endif
-       bssid_changed = os_memcmp(wpa_s->bssid, bss->bssid, ETH_ALEN);
-       os_memcpy(wpa_s->bssid, bss->bssid, ETH_ALEN);
-       if (bssid_changed)
-               wpas_notify_bssid_changed(wpa_s);
-
-#if 0 /* FIX */
-       local->conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10;
-
-       sdata->drop_unencrypted = bss->capability &
-               host_to_le16(WLAN_CAPABILITY_PRIVACY) ? 1 : 0;
-#endif
-
-#if 0 /* FIX */
-       os_memset(&rq, 0, sizeof(rq));
-       rq.m = bss->freq * 100000;
-       rq.e = 1;
-       res = ieee80211_ioctl_siwfreq(wpa_s, NULL, &rq, NULL);
-#endif
-
-       if (!ieee80211_ibss_allowed(wpa_s)) {
-#if 0 /* FIX */
-               wpa_printf(MSG_DEBUG, "MLME: IBSS not allowed on channel %d "
-                          "(%d MHz)", local->conf.channel,
-                          local->conf.freq);
-#endif
-               return -1;
-       }
-
-       /* Set beacon template based on scan results */
-       buf = os_malloc(400);
-       len = 0;
-       do {
-               if (buf == NULL)
-                       break;
-
-               mgmt = (struct ieee80211_mgmt *) buf;
-               len += 24 + sizeof(mgmt->u.beacon);
-               os_memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
-               mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-                                                  WLAN_FC_STYPE_BEACON);
-               os_memset(mgmt->da, 0xff, ETH_ALEN);
-               os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-               os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-#if 0 /* FIX */
-               mgmt->u.beacon.beacon_int =
-                       host_to_le16(local->conf.beacon_int);
-#endif
-               mgmt->u.beacon.capab_info = host_to_le16(bss->capability);
-
-               pos = buf + len;
-               len += 2 + wpa_s->mlme.ssid_len;
-               *pos++ = WLAN_EID_SSID;
-               *pos++ = wpa_s->mlme.ssid_len;
-               os_memcpy(pos, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len);
-
-               rates = bss->supp_rates_len;
-               if (rates > 8)
-                       rates = 8;
-               pos = buf + len;
-               len += 2 + rates;
-               *pos++ = WLAN_EID_SUPP_RATES;
-               *pos++ = rates;
-               os_memcpy(pos, bss->supp_rates, rates);
-
-               pos = buf + len;
-               len += 2 + 1;
-               *pos++ = WLAN_EID_DS_PARAMS;
-               *pos++ = 1;
-               *pos++ = bss->channel;
-
-               pos = buf + len;
-               len += 2 + 2;
-               *pos++ = WLAN_EID_IBSS_PARAMS;
-               *pos++ = 2;
-               /* FIX: set ATIM window based on scan results */
-               *pos++ = 0;
-               *pos++ = 0;
-
-               if (bss->supp_rates_len > 8) {
-                       rates = bss->supp_rates_len - 8;
-                       pos = buf + len;
-                       len += 2 + rates;
-                       *pos++ = WLAN_EID_EXT_SUPP_RATES;
-                       *pos++ = rates;
-                       os_memcpy(pos, &bss->supp_rates[8], rates);
-               }
-
-#if 0 /* FIX */
-               os_memset(&control, 0, sizeof(control));
-               control.pkt_type = PKT_PROBE_RESP;
-               os_memset(&extra, 0, sizeof(extra));
-               extra.endidx = local->num_curr_rates;
-               rate = rate_control_get_rate(wpa_s, skb, &extra);
-               if (rate == NULL) {
-                       wpa_printf(MSG_DEBUG, "MLME: Failed to determine TX "
-                                  "rate for IBSS beacon");
-                       break;
-               }
-               control.tx_rate = (wpa_s->mlme.short_preamble &&
-                                  (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
-                       rate->val2 : rate->val;
-               control.antenna_sel = local->conf.antenna_sel;
-               control.power_level = local->conf.power_level;
-               control.no_ack = 1;
-               control.retry_limit = 1;
-               control.rts_cts_duration = 0;
-#endif
-
-#if 0 /* FIX */
-               wpa_s->mlme.probe_resp = skb_copy(skb, GFP_ATOMIC);
-               if (wpa_s->mlme.probe_resp) {
-                       mgmt = (struct ieee80211_mgmt *)
-                               wpa_s->mlme.probe_resp->data;
-                       mgmt->frame_control =
-                               IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-                                            WLAN_FC_STYPE_PROBE_RESP);
-               } else {
-                       wpa_printf(MSG_DEBUG, "MLME: Could not allocate "
-                                  "ProbeResp template for IBSS");
-               }
-
-               if (local->hw->beacon_update &&
-                   local->hw->beacon_update(wpa_s, skb, &control) == 0) {
-                       wpa_printf(MSG_DEBUG, "MLME: Configured IBSS beacon "
-                                  "template based on scan results");
-                       skb = NULL;
-               }
-
-               rates = 0;
-               for (i = 0; i < bss->supp_rates_len; i++) {
-                       int rate = (bss->supp_rates[i] & 0x7f) * 5;
-                       if (local->conf.phymode == MODE_ATHEROS_TURBO)
-                               rate *= 2;
-                       for (j = 0; j < local->num_curr_rates; j++)
-                               if (local->curr_rates[j] == rate)
-                                       rates |= BIT(j);
-               }
-               wpa_s->mlme.supp_rates_bits = rates;
-#endif
-               done = 1;
-       } while (0);
-
-       os_free(buf);
-       if (!done) {
-               wpa_printf(MSG_DEBUG, "MLME: Failed to configure IBSS beacon "
-                          "template");
-       }
-
-       wpa_s->mlme.state = IEEE80211_IBSS_JOINED;
-       ieee80211_reschedule_timer(wpa_s, IEEE80211_IBSS_MERGE_INTERVAL);
-
-       return res;
-}
-
-
-#if 0 /* FIX */
-static int ieee80211_sta_create_ibss(struct wpa_supplicant *wpa_s)
-{
-       struct ieee80211_sta_bss *bss;
-       u8 bssid[ETH_ALEN], *pos;
-       int i;
-
-#if 0
-       /* Easier testing, use fixed BSSID. */
-       os_memset(bssid, 0xfe, ETH_ALEN);
-#else
-       /* Generate random, not broadcast, locally administered BSSID. Mix in
-        * own MAC address to make sure that devices that do not have proper
-        * random number generator get different BSSID. */
-       os_get_random(bssid, ETH_ALEN);
-       for (i = 0; i < ETH_ALEN; i++)
-               bssid[i] ^= wpa_s->own_addr[i];
-       bssid[0] &= ~0x01;
-       bssid[0] |= 0x02;
-#endif
-
-       wpa_printf(MSG_DEBUG, "MLME: Creating new IBSS network, BSSID "
-                  MACSTR "", MAC2STR(bssid));
-
-       bss = ieee80211_bss_add(wpa_s, bssid);
-       if (bss == NULL)
-               return -ENOMEM;
-
-#if 0 /* FIX */
-       if (local->conf.beacon_int == 0)
-               local->conf.beacon_int = 100;
-       bss->beacon_int = local->conf.beacon_int;
-       bss->hw_mode = local->conf.phymode;
-       bss->channel = local->conf.channel;
-       bss->freq = local->conf.freq;
-#endif
-       os_get_time(&bss->last_update);
-       bss->capability = host_to_le16(WLAN_CAPABILITY_IBSS);
-#if 0 /* FIX */
-       if (sdata->default_key) {
-               bss->capability |= host_to_le16(WLAN_CAPABILITY_PRIVACY);
-       } else
-               sdata->drop_unencrypted = 0;
-       bss->supp_rates_len = local->num_curr_rates;
-#endif
-       pos = bss->supp_rates;
-#if 0 /* FIX */
-       for (i = 0; i < local->num_curr_rates; i++) {
-               int rate = local->curr_rates[i];
-               if (local->conf.phymode == MODE_ATHEROS_TURBO)
-                       rate /= 2;
-               *pos++ = (u8) (rate / 5);
-       }
-#endif
-
-       return ieee80211_sta_join_ibss(wpa_s, bss);
-}
-#endif
-
-
-static int ieee80211_sta_find_ibss(struct wpa_supplicant *wpa_s)
-{
-       struct ieee80211_sta_bss *bss;
-       int found = 0;
-       u8 bssid[ETH_ALEN];
-       int active_ibss;
-       struct os_time now;
-
-       if (wpa_s->mlme.ssid_len == 0)
-               return -EINVAL;
-
-       active_ibss = ieee80211_sta_active_ibss(wpa_s);
-#ifdef IEEE80211_IBSS_DEBUG
-       wpa_printf(MSG_DEBUG, "MLME: sta_find_ibss (active_ibss=%d)",
-                  active_ibss);
-#endif /* IEEE80211_IBSS_DEBUG */
-       for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next) {
-               if (wpa_s->mlme.ssid_len != bss->ssid_len ||
-                   os_memcmp(wpa_s->mlme.ssid, bss->ssid, bss->ssid_len) != 0
-                   || !(bss->capability & WLAN_CAPABILITY_IBSS))
-                       continue;
-#ifdef IEEE80211_IBSS_DEBUG
-               wpa_printf(MSG_DEBUG, "   bssid=" MACSTR " found",
-                          MAC2STR(bss->bssid));
-#endif /* IEEE80211_IBSS_DEBUG */
-               os_memcpy(bssid, bss->bssid, ETH_ALEN);
-               found = 1;
-               if (active_ibss ||
-                   os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0)
-                       break;
-       }
-
-#ifdef IEEE80211_IBSS_DEBUG
-       wpa_printf(MSG_DEBUG, "   sta_find_ibss: selected " MACSTR " current "
-                  MACSTR, MAC2STR(bssid), MAC2STR(wpa_s->bssid));
-#endif /* IEEE80211_IBSS_DEBUG */
-       if (found && os_memcmp(wpa_s->bssid, bssid, ETH_ALEN) != 0 &&
-           (bss = ieee80211_bss_get(wpa_s, bssid))) {
-               wpa_printf(MSG_DEBUG, "MLME: Selected IBSS BSSID " MACSTR
-                          " based on configured SSID",
-                          MAC2STR(bssid));
-               return ieee80211_sta_join_ibss(wpa_s, bss);
-       }
-#ifdef IEEE80211_IBSS_DEBUG
-       wpa_printf(MSG_DEBUG, "   did not try to join ibss");
-#endif /* IEEE80211_IBSS_DEBUG */
-
-       /* Selected IBSS not found in current scan results - try to scan */
-       os_get_time(&now);
-#if 0 /* FIX */
-       if (wpa_s->mlme.state == IEEE80211_IBSS_JOINED &&
-           !ieee80211_sta_active_ibss(wpa_s)) {
-               ieee80211_reschedule_timer(wpa_s,
-                                          IEEE80211_IBSS_MERGE_INTERVAL);
-       } else if (time_after(jiffies, wpa_s->mlme.last_scan_completed +
-                             IEEE80211_SCAN_INTERVAL)) {
-               wpa_printf(MSG_DEBUG, "MLME: Trigger new scan to find an IBSS "
-                          "to join");
-               return ieee80211_sta_req_scan(wpa_s->mlme.ssid,
-                                             wpa_s->mlme.ssid_len);
-       } else if (wpa_s->mlme.state != IEEE80211_IBSS_JOINED) {
-               int interval = IEEE80211_SCAN_INTERVAL;
-
-               if (time_after(jiffies, wpa_s->mlme.ibss_join_req +
-                              IEEE80211_IBSS_JOIN_TIMEOUT)) {
-                       if (wpa_s->mlme.create_ibss &&
-                           ieee80211_ibss_allowed(wpa_s))
-                               return ieee80211_sta_create_ibss(wpa_s);
-                       if (wpa_s->mlme.create_ibss) {
-                               wpa_printf(MSG_DEBUG, "MLME: IBSS not allowed "
-                                          "on the configured channel %d "
-                                          "(%d MHz)",
-                                          local->conf.channel,
-                                          local->conf.freq);
-                       }
-
-                       /* No IBSS found - decrease scan interval and continue
-                        * scanning. */
-                       interval = IEEE80211_SCAN_INTERVAL_SLOW;
-               }
-
-               wpa_s->mlme.state = IEEE80211_IBSS_SEARCH;
-               ieee80211_reschedule_timer(wpa_s, interval);
-               return 0;
-       }
-#endif
-
-       return 0;
-}
-
-
-int ieee80211_sta_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid,
-                          size_t *len)
-{
-       os_memcpy(ssid, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len);
-       *len = wpa_s->mlme.ssid_len;
-       return 0;
-}
-
-
-int ieee80211_sta_associate(struct wpa_supplicant *wpa_s,
-                           struct wpa_driver_associate_params *params)
-{
-       struct ieee80211_sta_bss *bss;
-       int bssid_changed;
-
-       wpa_s->mlme.bssid_set = 0;
-       wpa_s->mlme.freq = params->freq;
-       if (params->bssid) {
-               bssid_changed = os_memcmp(wpa_s->bssid, params->bssid,
-                                         ETH_ALEN);
-               os_memcpy(wpa_s->bssid, params->bssid, ETH_ALEN);
-               if (bssid_changed)
-                       wpas_notify_bssid_changed(wpa_s);
-
-               if (!is_zero_ether_addr(params->bssid))
-                       wpa_s->mlme.bssid_set = 1;
-               bss = ieee80211_bss_get(wpa_s, wpa_s->bssid);
-               if (bss) {
-                       wpa_s->mlme.phymode = bss->hw_mode;
-                       wpa_s->mlme.channel = bss->channel;
-                       wpa_s->mlme.freq = bss->freq;
-               }
-       }
-
-#if 0 /* FIX */
-       /* TODO: This should always be done for IBSS, even if IEEE80211_QOS is
-        * not defined. */
-       if (local->hw->conf_tx) {
-               struct ieee80211_tx_queue_params qparam;
-               int i;
-
-               os_memset(&qparam, 0, sizeof(qparam));
-               /* TODO: are these ok defaults for all hw_modes? */
-               qparam.aifs = 2;
-               qparam.cw_min =
-                       local->conf.phymode == MODE_IEEE80211B ? 31 : 15;
-               qparam.cw_max = 1023;
-               qparam.burst_time = 0;
-               for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++)
-               {
-                       local->hw->conf_tx(wpa_s, i + IEEE80211_TX_QUEUE_DATA0,
-                                          &qparam);
-               }
-               /* IBSS uses different parameters for Beacon sending */
-               qparam.cw_min++;
-               qparam.cw_min *= 2;
-               qparam.cw_min--;
-               local->hw->conf_tx(wpa_s, IEEE80211_TX_QUEUE_BEACON, &qparam);
-       }
-#endif
-
-       if (wpa_s->mlme.ssid_len != params->ssid_len ||
-           os_memcmp(wpa_s->mlme.ssid, params->ssid, params->ssid_len) != 0)
-               wpa_s->mlme.prev_bssid_set = 0;
-       os_memcpy(wpa_s->mlme.ssid, params->ssid, params->ssid_len);
-       os_memset(wpa_s->mlme.ssid + params->ssid_len, 0,
-                 MAX_SSID_LEN - params->ssid_len);
-       wpa_s->mlme.ssid_len = params->ssid_len;
-       wpa_s->mlme.ssid_set = 1;
-
-       os_free(wpa_s->mlme.extra_ie);
-       if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
-               wpa_s->mlme.extra_ie = NULL;
-               wpa_s->mlme.extra_ie_len = 0;
-       } else {
-               wpa_s->mlme.extra_ie = os_malloc(params->wpa_ie_len);
-               if (wpa_s->mlme.extra_ie == NULL) {
-                       wpa_s->mlme.extra_ie_len = 0;
-                       return -1;
-               }
-               os_memcpy(wpa_s->mlme.extra_ie, params->wpa_ie,
-                         params->wpa_ie_len);
-               wpa_s->mlme.extra_ie_len = params->wpa_ie_len;
-       }
-
-       wpa_s->mlme.key_mgmt = params->key_mgmt_suite;
-
-       ieee80211_sta_set_channel(wpa_s, wpa_s->mlme.phymode,
-                                 wpa_s->mlme.channel, wpa_s->mlme.freq);
-
-       if (params->mode == WPAS_MODE_IBSS && !wpa_s->mlme.bssid_set) {
-               os_get_time(&wpa_s->mlme.ibss_join_req);
-               wpa_s->mlme.state = IEEE80211_IBSS_SEARCH;
-               return ieee80211_sta_find_ibss(wpa_s);
-       }
-
-       if (wpa_s->mlme.bssid_set)
-               ieee80211_sta_new_auth(wpa_s);
-
-       return 0;
-}
-
-
-static void ieee80211_sta_save_oper_chan(struct wpa_supplicant *wpa_s)
-{
-       wpa_s->mlme.scan_oper_channel = wpa_s->mlme.channel;
-       wpa_s->mlme.scan_oper_freq = wpa_s->mlme.freq;
-       wpa_s->mlme.scan_oper_phymode = wpa_s->mlme.phymode;
-}
-
-
-static int ieee80211_sta_restore_oper_chan(struct wpa_supplicant *wpa_s)
-{
-       wpa_s->mlme.channel = wpa_s->mlme.scan_oper_channel;
-       wpa_s->mlme.freq = wpa_s->mlme.scan_oper_freq;
-       wpa_s->mlme.phymode = wpa_s->mlme.scan_oper_phymode;
-       if (wpa_s->mlme.freq == 0)
-               return 0;
-       return ieee80211_sta_set_channel(wpa_s, wpa_s->mlme.phymode,
-                                        wpa_s->mlme.channel,
-                                        wpa_s->mlme.freq);
-}
-
-
-static int ieee80211_active_scan(struct wpa_supplicant *wpa_s)
-{
-       size_t m;
-       int c;
-
-       for (m = 0; m < wpa_s->mlme.num_modes; m++) {
-               struct hostapd_hw_modes *mode = &wpa_s->mlme.modes[m];
-               if ((int) mode->mode != (int) wpa_s->mlme.phymode)
-                       continue;
-               for (c = 0; c < mode->num_channels; c++) {
-                       struct hostapd_channel_data *chan = &mode->channels[c];
-                       if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
-                           chan->chan == wpa_s->mlme.channel) {
-                               if (!(chan->flag & HOSTAPD_CHAN_PASSIVE_SCAN))
-                                       return 1;
-                               break;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-
-static void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx)
-{
-       struct wpa_supplicant *wpa_s = eloop_ctx;
-       struct hostapd_hw_modes *mode;
-       struct hostapd_channel_data *chan;
-       int skip = 0;
-       int timeout = 0;
-       struct wpa_ssid *ssid = wpa_s->current_ssid;
-       int adhoc;
-
-       if (!wpa_s->mlme.sta_scanning || wpa_s->mlme.modes == NULL)
-               return;
-
-       adhoc = ssid && ssid->mode == 1;
-
-       switch (wpa_s->mlme.scan_state) {
-       case SCAN_SET_CHANNEL:
-               mode = &wpa_s->mlme.modes[wpa_s->mlme.scan_hw_mode_idx];
-               if (wpa_s->mlme.scan_hw_mode_idx >=
-                   (int) wpa_s->mlme.num_modes ||
-                   (wpa_s->mlme.scan_hw_mode_idx + 1 ==
-                    (int) wpa_s->mlme.num_modes
-                    && wpa_s->mlme.scan_channel_idx >= mode->num_channels)) {
-                       if (ieee80211_sta_restore_oper_chan(wpa_s)) {
-                               wpa_printf(MSG_DEBUG, "MLME: failed to "
-                                          "restore operational channel after "
-                                          "scan");
-                       }
-                       wpa_printf(MSG_DEBUG, "MLME: scan completed");
-                       wpa_s->mlme.sta_scanning = 0;
-                       os_get_time(&wpa_s->mlme.last_scan_completed);
-                       wpa_supplicant_event(wpa_s, EVENT_SCAN_RESULTS, NULL);
-                       if (adhoc) {
-                               if (!wpa_s->mlme.bssid_set ||
-                                   (wpa_s->mlme.state ==
-                                    IEEE80211_IBSS_JOINED &&
-                                    !ieee80211_sta_active_ibss(wpa_s)))
-                                       ieee80211_sta_find_ibss(wpa_s);
-                       }
-                       return;
-               }
-               skip = !(wpa_s->mlme.hw_modes & (1 << mode->mode));
-               chan = &mode->channels[wpa_s->mlme.scan_channel_idx];
-               if ((chan->flag & HOSTAPD_CHAN_DISABLED) ||
-                   (adhoc && (chan->flag & HOSTAPD_CHAN_NO_IBSS)) ||
-                   (wpa_s->mlme.hw_modes & (1 << HOSTAPD_MODE_IEEE80211G) &&
-                    mode->mode == HOSTAPD_MODE_IEEE80211B &&
-                    wpa_s->mlme.scan_skip_11b))
-                       skip = 1;
-               if (!skip && wpa_s->mlme.scan_freqs) {
-                       int i, found = 0;
-                       for (i = 0; wpa_s->mlme.scan_freqs[i]; i++) {
-                               if (wpa_s->mlme.scan_freqs[i] == chan->freq) {
-                                       found = 1;
-                                       break;
-                               }
-                       }
-                       if (!found)
-                               skip = 1;
-               }
-
-               if (!skip) {
-                       wpa_printf(MSG_MSGDUMP,
-                                  "MLME: scan channel %d (%d MHz)",
-                                  chan->chan, chan->freq);
-
-                       wpa_s->mlme.channel = chan->chan;
-                       wpa_s->mlme.freq = chan->freq;
-                       wpa_s->mlme.phymode = mode->mode;
-                       if (ieee80211_sta_set_channel(wpa_s, mode->mode,
-                                                     chan->chan, chan->freq))
-                       {
-                               wpa_printf(MSG_DEBUG, "MLME: failed to set "
-                                          "channel %d (%d MHz) for scan",
-                                          chan->chan, chan->freq);
-                               skip = 1;
-                       }
-               }
-
-               wpa_s->mlme.scan_channel_idx++;
-               if (wpa_s->mlme.scan_channel_idx >=
-                   wpa_s->mlme.modes[wpa_s->mlme.scan_hw_mode_idx].
-                   num_channels) {
-                       wpa_s->mlme.scan_hw_mode_idx++;
-                       wpa_s->mlme.scan_channel_idx = 0;
-               }
-
-               if (skip) {
-                       timeout = 0;
-                       break;
-               }
-
-               timeout = IEEE80211_PROBE_DELAY;
-               wpa_s->mlme.scan_state = SCAN_SEND_PROBE;
-               break;
-       case SCAN_SEND_PROBE:
-               if (ieee80211_active_scan(wpa_s)) {
-                       ieee80211_send_probe_req(wpa_s, NULL,
-                                                wpa_s->mlme.scan_ssid,
-                                                wpa_s->mlme.scan_ssid_len);
-                       timeout = IEEE80211_CHANNEL_TIME;
-               } else {
-                       timeout = IEEE80211_PASSIVE_CHANNEL_TIME;
-               }
-               wpa_s->mlme.scan_state = SCAN_SET_CHANNEL;
-               break;
-       }
-
-       eloop_register_timeout(timeout / 1000, 1000 * (timeout % 1000),
-                              ieee80211_sta_scan_timer, wpa_s, NULL);
-}
-
-
-int ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s,
-                          struct wpa_driver_scan_params *params)
-{
-       const u8 *ssid = params->ssids[0].ssid;
-       size_t ssid_len = params->ssids[0].ssid_len;
-
-       if (ssid_len > MAX_SSID_LEN)
-               return -1;
-
-       /* MLME-SCAN.request (page 118)  page 144 (11.1.3.1)
-        * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS
-        * BSSID: MACAddress
-        * SSID
-        * ScanType: ACTIVE, PASSIVE
-        * ProbeDelay: delay (in microseconds) to be used prior to transmitting
-        *    a Probe frame during active scanning
-        * ChannelList
-        * MinChannelTime (>= ProbeDelay), in TU
-        * MaxChannelTime: (>= MinChannelTime), in TU
-        */
-
-        /* MLME-SCAN.confirm
-         * BSSDescriptionSet
-         * ResultCode: SUCCESS, INVALID_PARAMETERS
-        */
-
-       /* TODO: if assoc, move to power save mode for the duration of the
-        * scan */
-
-       if (wpa_s->mlme.sta_scanning)
-               return -1;
-
-       wpa_printf(MSG_DEBUG, "MLME: starting scan");
-
-       ieee80211_sta_set_probe_req_ie(wpa_s, params->extra_ies,
-                                      params->extra_ies_len);
-
-       os_free(wpa_s->mlme.scan_freqs);
-       if (params->freqs) {
-               int i;
-               for (i = 0; params->freqs[i]; i++)
-                       ;
-               wpa_s->mlme.scan_freqs = os_malloc((i + 1) * sizeof(int));
-               if (wpa_s->mlme.scan_freqs)
-                       os_memcpy(wpa_s->mlme.scan_freqs, params->freqs,
-                                 (i + 1) * sizeof(int));
-       } else
-               wpa_s->mlme.scan_freqs = NULL;
-
-       ieee80211_sta_save_oper_chan(wpa_s);
-
-       wpa_s->mlme.sta_scanning = 1;
-       /* TODO: stop TX queue? */
-
-       if (ssid) {
-               wpa_s->mlme.scan_ssid_len = ssid_len;
-               os_memcpy(wpa_s->mlme.scan_ssid, ssid, ssid_len);
-       } else
-               wpa_s->mlme.scan_ssid_len = 0;
-       wpa_s->mlme.scan_skip_11b = 1; /* FIX: clear this is 11g is not
-                                       * supported */
-       wpa_s->mlme.scan_state = SCAN_SET_CHANNEL;
-       wpa_s->mlme.scan_hw_mode_idx = 0;
-       wpa_s->mlme.scan_channel_idx = 0;
-       eloop_register_timeout(0, 1, ieee80211_sta_scan_timer, wpa_s, NULL);
-
-       return 0;
-}
-
-
-struct wpa_scan_results *
-ieee80211_sta_get_scan_results(struct wpa_supplicant *wpa_s)
-{
-       size_t ap_num = 0;
-       struct wpa_scan_results *res;
-       struct wpa_scan_res *r;
-       struct ieee80211_sta_bss *bss;
-
-       res = os_zalloc(sizeof(*res));
-       for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next)
-               ap_num++;
-       res->res = os_zalloc(ap_num * sizeof(struct wpa_scan_res *));
-       if (res->res == NULL) {
-               os_free(res);
-               return NULL;
-       }
-
-       for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next) {
-               r = os_zalloc(sizeof(*r) + bss->ie_len);
-               if (r == NULL)
-                       break;
-               os_memcpy(r->bssid, bss->bssid, ETH_ALEN);
-               r->freq = bss->freq;
-               r->beacon_int = bss->beacon_int;
-               r->caps = bss->capability;
-               r->level = bss->rssi;
-               r->tsf = bss->timestamp;
-               if (bss->ie) {
-                       r->ie_len = bss->ie_len;
-                       os_memcpy(r + 1, bss->ie, bss->ie_len);
-               }
-
-               res->res[res->num++] = r;
-       }
-
-       return res;
-}
-
-
-#if 0 /* FIX */
-struct sta_info * ieee80211_ibss_add_sta(struct wpa_supplicant *wpa_s,
-                                        struct sk_buff *skb, u8 *bssid,
-                                        u8 *addr)
-{
-       struct ieee80211_local *local = dev->priv;
-       struct list_head *ptr;
-       struct sta_info *sta;
-       struct wpa_supplicant *sta_dev = NULL;
-
-       /* TODO: Could consider removing the least recently used entry and
-        * allow new one to be added. */
-       if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
-               if (net_ratelimit()) {
-                       wpa_printf(MSG_DEBUG, "MLME: No room for a new IBSS "
-                                  "STA entry " MACSTR, MAC2STR(addr));
-               }
-               return NULL;
-       }
-
-       spin_lock_bh(&local->sub_if_lock);
-       list_for_each(ptr, &local->sub_if_list) {
-               sdata = list_entry(ptr, struct ieee80211_sub_if_data, list);
-               if (sdata->type == IEEE80211_SUB_IF_TYPE_STA &&
-                   os_memcmp(bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
-                       sta_dev = sdata->dev;
-                       break;
-               }
-       }
-       spin_unlock_bh(&local->sub_if_lock);
-
-       if (sta_dev == NULL)
-               return NULL;
-
-       wpa_printf(MSG_DEBUG, "MLME: Adding new IBSS station " MACSTR
-                  " (dev=%s)", MAC2STR(addr), sta_dev->name);
-
-       sta = sta_info_add(wpa_s, addr);
-       if (sta == NULL) {
-               return NULL;
-       }
-
-       sta->dev = sta_dev;
-       sta->supp_rates = wpa_s->mlme.supp_rates_bits;
-
-       rate_control_rate_init(local, sta);
-
-       return sta; /* caller will call sta_info_release() */
-}
-#endif
-
-
-int ieee80211_sta_deauthenticate(struct wpa_supplicant *wpa_s, u16 reason)
-{
-       wpa_printf(MSG_DEBUG, "MLME: deauthenticate(reason=%d)", reason);
-
-       ieee80211_send_deauth(wpa_s, reason);
-       ieee80211_set_associated(wpa_s, 0);
-       return 0;
-}
-
-
-int ieee80211_sta_disassociate(struct wpa_supplicant *wpa_s, u16 reason)
-{
-       wpa_printf(MSG_DEBUG, "MLME: disassociate(reason=%d)", reason);
-
-       if (!wpa_s->mlme.associated)
-               return -1;
-
-       ieee80211_send_disassoc(wpa_s, reason);
-       ieee80211_set_associated(wpa_s, 0);
-       return 0;
-}
-
-
-void ieee80211_sta_rx(struct wpa_supplicant *wpa_s, const u8 *buf, size_t len,
-                     struct ieee80211_rx_status *rx_status)
-{
-       struct ieee80211_mgmt *mgmt;
-       u16 fc;
-       const u8 *pos;
-
-       /* wpa_hexdump(MSG_MSGDUMP, "MLME: Received frame", buf, len); */
-
-       if (wpa_s->mlme.sta_scanning) {
-               ieee80211_sta_rx_scan(wpa_s, buf, len, rx_status);
-               return;
-       }
-
-       if (len < 24)
-               return;
-
-       mgmt = (struct ieee80211_mgmt *) buf;
-       fc = le_to_host16(mgmt->frame_control);
-
-       if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
-               ieee80211_sta_rx_mgmt(wpa_s, buf, len, rx_status);
-       else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) {
-               if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) !=
-                   WLAN_FC_FROMDS)
-                       return;
-               /* mgmt->sa is actually BSSID for FromDS data frames */
-               if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0)
-                       return;
-               /* Skip IEEE 802.11 and LLC headers */
-               pos = buf + 24 + 6;
-               if (WPA_GET_BE16(pos) != ETH_P_EAPOL)
-                       return;
-               pos += 2;
-               /* mgmt->bssid is actually BSSID for SA data frames */
-               wpa_supplicant_rx_eapol(wpa_s, mgmt->bssid,
-                                       pos, buf + len - pos);
-       }
-}
-
-
-void ieee80211_sta_free_hw_features(struct hostapd_hw_modes *hw_features,
-                                   size_t num_hw_features)
-{
-       size_t i;
-
-       if (hw_features == NULL)
-               return;
-
-       for (i = 0; i < num_hw_features; i++) {
-               os_free(hw_features[i].channels);
-               os_free(hw_features[i].rates);
-       }
-
-       os_free(hw_features);
-}
-
-
-int ieee80211_sta_init(struct wpa_supplicant *wpa_s)
-{
-       u16 num_modes, flags;
-
-       wpa_s->mlme.modes = wpa_drv_get_hw_feature_data(wpa_s, &num_modes,
-                                                       &flags);
-       if (wpa_s->mlme.modes == NULL) {
-               wpa_printf(MSG_ERROR, "MLME: Failed to read supported "
-                          "channels and rates from the driver");
-               return -1;
-       }
-
-       wpa_s->mlme.num_modes = num_modes;
-
-       wpa_s->mlme.hw_modes = 1 << HOSTAPD_MODE_IEEE80211A;
-       wpa_s->mlme.hw_modes |= 1 << HOSTAPD_MODE_IEEE80211B;
-       wpa_s->mlme.hw_modes |= 1 << HOSTAPD_MODE_IEEE80211G;
-
-       wpa_s->mlme.wmm_enabled = 1;
-
-       return 0;
-}
-
-
-void ieee80211_sta_deinit(struct wpa_supplicant *wpa_s)
-{
-       eloop_cancel_timeout(ieee80211_sta_timer, wpa_s, NULL);
-       eloop_cancel_timeout(ieee80211_sta_scan_timer, wpa_s, NULL);
-       os_free(wpa_s->mlme.extra_ie);
-       wpa_s->mlme.extra_ie = NULL;
-       os_free(wpa_s->mlme.extra_probe_ie);
-       wpa_s->mlme.extra_probe_ie = NULL;
-       os_free(wpa_s->mlme.assocreq_ies);
-       wpa_s->mlme.assocreq_ies = NULL;
-       os_free(wpa_s->mlme.assocresp_ies);
-       wpa_s->mlme.assocresp_ies = NULL;
-       ieee80211_bss_list_deinit(wpa_s);
-       ieee80211_sta_free_hw_features(wpa_s->mlme.modes,
-                                      wpa_s->mlme.num_modes);
-#ifdef CONFIG_IEEE80211R
-       os_free(wpa_s->mlme.ft_ies);
-       wpa_s->mlme.ft_ies = NULL;
-       wpa_s->mlme.ft_ies_len = 0;
-#endif /* CONFIG_IEEE80211R */
-
-       os_free(wpa_s->mlme.scan_freqs);
-       wpa_s->mlme.scan_freqs = NULL;
-}
-
-
-#ifdef CONFIG_IEEE80211R
-
-int ieee80211_sta_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
-                               const u8 *ies, size_t ies_len)
-{
-       if (md == NULL) {
-               wpa_printf(MSG_DEBUG, "MLME: Clear FT mobility domain");
-               os_memset(wpa_s->mlme.current_md, 0, MOBILITY_DOMAIN_ID_LEN);
-       } else {
-               wpa_printf(MSG_DEBUG, "MLME: Update FT IEs for MD " MACSTR,
-                          MAC2STR(md));
-               os_memcpy(wpa_s->mlme.current_md, md, MOBILITY_DOMAIN_ID_LEN);
-       }
-
-       wpa_hexdump(MSG_DEBUG, "MLME: FT IEs", ies, ies_len);
-       os_free(wpa_s->mlme.ft_ies);
-       wpa_s->mlme.ft_ies = os_malloc(ies_len);
-       if (wpa_s->mlme.ft_ies == NULL)
-               return -1;
-       os_memcpy(wpa_s->mlme.ft_ies, ies, ies_len);
-       wpa_s->mlme.ft_ies_len = ies_len;
-
-       return 0;
-}
-
-
-int ieee80211_sta_send_ft_action(struct wpa_supplicant *wpa_s, u8 action,
-                                const u8 *target_ap,
-                                const u8 *ies, size_t ies_len)
-{
-       u8 *buf;
-       size_t len;
-       struct ieee80211_mgmt *mgmt;
-       int res;
-
-       /*
-        * Action frame payload:
-        * Category[1] = 6 (Fast BSS Transition)
-        * Action[1] = 1 (Fast BSS Transition Request)
-        * STA Address
-        * Target AP Address
-        * FT IEs
-        */
-
-       buf = os_zalloc(sizeof(*mgmt) + ies_len);
-       if (buf == NULL) {
-               wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
-                          "FT action frame");
-               return -1;
-       }
-
-       mgmt = (struct ieee80211_mgmt *) buf;
-       len = 24;
-       os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
-       os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-       os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-       mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-                                          WLAN_FC_STYPE_ACTION);
-       mgmt->u.action.category = WLAN_ACTION_FT;
-       mgmt->u.action.u.ft_action_req.action = action;
-       os_memcpy(mgmt->u.action.u.ft_action_req.sta_addr, wpa_s->own_addr,
-                 ETH_ALEN);
-       os_memcpy(mgmt->u.action.u.ft_action_req.target_ap_addr, target_ap,
-                 ETH_ALEN);
-       os_memcpy(mgmt->u.action.u.ft_action_req.variable, ies, ies_len);
-       len += 1 + sizeof(mgmt->u.action.u.ft_action_req) + ies_len;
-
-       wpa_printf(MSG_DEBUG, "MLME: Send FT Action Frame: Action=%d "
-                  "Target AP=" MACSTR " body_len=%lu",
-                  action, MAC2STR(target_ap), (unsigned long) ies_len);
-
-       res = ieee80211_sta_tx(wpa_s, buf, len);
-       os_free(buf);
-
-       return res;
-}
-
-#endif /* CONFIG_IEEE80211R */
-
-
-static int ieee80211_sta_set_probe_req_ie(struct wpa_supplicant *wpa_s,
-                                         const u8 *ies, size_t ies_len)
-{
-       os_free(wpa_s->mlme.extra_probe_ie);
-       wpa_s->mlme.extra_probe_ie = NULL;
-       wpa_s->mlme.extra_probe_ie_len = 0;
-
-       if (ies == NULL)
-               return 0;
-
-       wpa_s->mlme.extra_probe_ie = os_malloc(ies_len);
-       if (wpa_s->mlme.extra_probe_ie == NULL)
-               return -1;
-
-       os_memcpy(wpa_s->mlme.extra_probe_ie, ies, ies_len);
-       wpa_s->mlme.extra_probe_ie_len = ies_len;
-
-       return 0;
-}
diff --git a/wpa_supplicant/mlme.h b/wpa_supplicant/mlme.h
deleted file mode 100644 (file)
index 5db3665..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * WPA Supplicant - Client mode MLME
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004, Instant802 Networks, Inc.
- * Copyright (c) 2005-2006, Devicescape Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef MLME_H
-#define MLME_H
-
-struct wpa_supplicant;
-
-struct ieee80211_rx_status {
-       int freq;
-        int channel;
-        int ssi;
-};
-
-#ifdef CONFIG_CLIENT_MLME
-
-int ieee80211_sta_init(struct wpa_supplicant *wpa_s);
-void ieee80211_sta_deinit(struct wpa_supplicant *wpa_s);
-int ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s,
-                          struct wpa_driver_scan_params *params);
-int ieee80211_sta_deauthenticate(struct wpa_supplicant *wpa_s, u16 reason);
-int ieee80211_sta_disassociate(struct wpa_supplicant *wpa_s, u16 reason);
-int ieee80211_sta_associate(struct wpa_supplicant *wpa_s,
-                           struct wpa_driver_associate_params *params);
-int ieee80211_sta_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid,
-                          size_t *len);
-void ieee80211_sta_free_hw_features(struct hostapd_hw_modes *hw_features,
-                                   size_t num_hw_features);
-void ieee80211_sta_rx(struct wpa_supplicant *wpa_s, const u8 *buf, size_t len,
-                     struct ieee80211_rx_status *rx_status);
-struct wpa_scan_results *
-ieee80211_sta_get_scan_results(struct wpa_supplicant *wpa_s);
-int ieee80211_sta_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
-                               const u8 *ies, size_t ies_len);
-int ieee80211_sta_send_ft_action(struct wpa_supplicant *wpa_s, u8 action,
-                                const u8 *target_ap,
-                                const u8 *ies, size_t ies_len);
-
-#else /* CONFIG_CLIENT_MLME */
-
-static inline int ieee80211_sta_init(struct wpa_supplicant *wpa_s)
-{
-       return 0;
-}
-
-static inline void ieee80211_sta_deinit(struct wpa_supplicant *wpa_s)
-{
-}
-
-static inline int ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s,
-                                        struct wpa_driver_scan_params *params)
-{
-       return -1;
-}
-
-static inline int ieee80211_sta_deauthenticate(struct wpa_supplicant *wpa_s,
-                                              u16 reason)
-{
-       return -1;
-}
-
-static inline int ieee80211_sta_disassociate(struct wpa_supplicant *wpa_s,
-                                            u16 reason)
-{
-       return -1;
-}
-
-static inline int
-ieee80211_sta_associate(struct wpa_supplicant *wpa_s,
-                       struct wpa_driver_associate_params *params)
-{
-       return -1;
-}
-
-static inline int ieee80211_sta_get_ssid(struct wpa_supplicant *wpa_s,
-                                        u8 *ssid, size_t *len)
-{
-       return -1;
-}
-
-static inline void
-ieee80211_sta_free_hw_features(struct hostapd_hw_modes *hw_features,
-                              size_t num_hw_features)
-{
-}
-
-static inline void
-ieee80211_sta_rx(struct wpa_supplicant *wpa_s, const u8 *buf, size_t len,
-                struct ieee80211_rx_status *rx_status)
-{
-}
-
-static inline struct wpa_scan_results *
-ieee80211_sta_get_scan_results(struct wpa_supplicant *wpa_s)
-{
-       return NULL;
-}
-
-static inline int
-ieee80211_sta_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
-                           const u8 *ies, size_t ies_len)
-{
-       return -1;
-}
-
-static inline int
-ieee80211_sta_send_ft_action(struct wpa_supplicant *wpa_s, u8 action,
-                            const u8 *target_ap,
-                            const u8 *ies, size_t ies_len)
-{
-       return -1;
-}
-
-#endif /* CONFIG_CLIENT_MLME */
-
-#endif /* MLME_H */
index ac65b4f..71778ae 100644 (file)
 #include "dbus/dbus_common.h"
 #include "dbus/dbus_old.h"
 #include "dbus/dbus_new.h"
+#include "rsn_supp/wpa.h"
 #include "driver_i.h"
 #include "scan.h"
+#include "p2p_supplicant.h"
+#include "sme.h"
 #include "notify.h"
 
 int wpas_notify_supplicant_initialized(struct wpa_global *global)
@@ -81,6 +84,22 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
 
        /* notify the new DBus API */
        wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATE);
+
+#ifdef CONFIG_P2P
+       if (new_state == WPA_COMPLETED)
+               wpas_p2p_notif_connected(wpa_s);
+       else if (new_state < WPA_ASSOCIATED)
+               wpas_p2p_notif_disconnected(wpa_s);
+#endif /* CONFIG_P2P */
+
+       sme_state_changed(wpa_s);
+
+#ifdef ANDROID
+       wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE
+                    "id=%d state=%d BSSID=" MACSTR,
+                    wpa_s->current_ssid ? wpa_s->current_ssid->id : -1,
+                    new_state, MAC2STR(wpa_s->pending_bssid));
+#endif /* ANDROID */
 }
 
 
@@ -102,6 +121,12 @@ void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s)
 }
 
 
+void wpas_notify_auth_changed(struct wpa_supplicant *wpa_s)
+{
+       wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_AUTH_MODE);
+}
+
+
 void wpas_notify_network_enabled_changed(struct wpa_supplicant *wpa_s,
                                         struct wpa_ssid *ssid)
 {
@@ -116,6 +141,15 @@ void wpas_notify_network_selected(struct wpa_supplicant *wpa_s,
 }
 
 
+void wpas_notify_network_request(struct wpa_supplicant *wpa_s,
+                                struct wpa_ssid *ssid,
+                                enum wpa_ctrl_req_type rtype,
+                                const char *default_txt)
+{
+       wpas_dbus_signal_network_request(wpa_s, ssid, rtype, default_txt);
+}
+
+
 void wpas_notify_scanning(struct wpa_supplicant *wpa_s)
 {
        /* notify the old DBus API */
@@ -182,14 +216,45 @@ void wpas_notify_wps_event_success(struct wpa_supplicant *wpa_s)
 void wpas_notify_network_added(struct wpa_supplicant *wpa_s,
                               struct wpa_ssid *ssid)
 {
-       wpas_dbus_register_network(wpa_s, ssid);
+       /*
+        * Networks objects created during any P2P activities should not be
+        * exposed out. They might/will confuse certain non-P2P aware
+        * applications since these network objects won't behave like
+        * regular ones.
+        */
+       if (wpa_s->global->p2p_group_formation != wpa_s)
+               wpas_dbus_register_network(wpa_s, ssid);
+}
+
+
+void wpas_notify_persistent_group_added(struct wpa_supplicant *wpa_s,
+                                       struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_P2P
+       wpas_dbus_register_persistent_group(wpa_s, ssid);
+#endif /* CONFIG_P2P */
+}
+
+
+void wpas_notify_persistent_group_removed(struct wpa_supplicant *wpa_s,
+                                         struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_P2P
+       wpas_dbus_unregister_persistent_group(wpa_s, ssid->id);
+#endif /* CONFIG_P2P */
 }
 
 
 void wpas_notify_network_removed(struct wpa_supplicant *wpa_s,
                                 struct wpa_ssid *ssid)
 {
-       wpas_dbus_unregister_network(wpa_s, ssid->id);
+       if (wpa_s->wpa)
+               wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+       if (wpa_s->global->p2p_group_formation != wpa_s)
+               wpas_dbus_unregister_network(wpa_s, ssid->id);
+#ifdef CONFIG_P2P
+       wpas_p2p_network_removed(wpa_s, ssid);
+#endif /* CONFIG_P2P */
 }
 
 
@@ -337,3 +402,205 @@ void wpas_notify_resume(struct wpa_global *global)
                        wpa_supplicant_req_scan(wpa_s, 0, 100000);
        }
 }
+
+
+#ifdef CONFIG_P2P
+
+void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s,
+                                 const u8 *dev_addr, int new_device)
+{
+       if (new_device) {
+               /* Create the new peer object */
+               wpas_dbus_register_peer(wpa_s, dev_addr);
+       }
+
+       /* Notify a new peer has been detected*/
+       wpas_dbus_signal_peer_device_found(wpa_s, dev_addr);
+}
+
+
+void wpas_notify_p2p_device_lost(struct wpa_supplicant *wpa_s,
+                                const u8 *dev_addr)
+{
+       wpas_dbus_unregister_peer(wpa_s, dev_addr);
+
+       /* Create signal on interface object*/
+       wpas_dbus_signal_peer_device_lost(wpa_s, dev_addr);
+}
+
+
+void wpas_notify_p2p_group_removed(struct wpa_supplicant *wpa_s,
+                                  const struct wpa_ssid *ssid,
+                                  const char *role)
+{
+       wpas_dbus_unregister_p2p_group(wpa_s, ssid);
+
+       wpas_dbus_signal_p2p_group_removed(wpa_s, role);
+}
+
+
+void wpas_notify_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
+                               const u8 *src, u16 dev_passwd_id)
+{
+       wpas_dbus_signal_p2p_go_neg_req(wpa_s, src, dev_passwd_id);
+}
+
+
+void wpas_notify_p2p_go_neg_completed(struct wpa_supplicant *wpa_s,
+                                     struct p2p_go_neg_results *res)
+{
+       wpas_dbus_signal_p2p_go_neg_resp(wpa_s, res);
+}
+
+
+void wpas_notify_p2p_invitation_result(struct wpa_supplicant *wpa_s,
+                                      int status, const u8 *bssid)
+{
+       wpas_dbus_signal_p2p_invitation_result(wpa_s, status, bssid);
+}
+
+
+void wpas_notify_p2p_sd_request(struct wpa_supplicant *wpa_s,
+                               int freq, const u8 *sa, u8 dialog_token,
+                               u16 update_indic, const u8 *tlvs,
+                               size_t tlvs_len)
+{
+       wpas_dbus_signal_p2p_sd_request(wpa_s, freq, sa, dialog_token,
+                                       update_indic, tlvs, tlvs_len);
+}
+
+
+void wpas_notify_p2p_sd_response(struct wpa_supplicant *wpa_s,
+                                const u8 *sa, u16 update_indic,
+                                const u8 *tlvs, size_t tlvs_len)
+{
+       wpas_dbus_signal_p2p_sd_response(wpa_s, sa, update_indic,
+                                        tlvs, tlvs_len);
+}
+
+
+/**
+ * wpas_notify_p2p_provision_discovery - Notification of provision discovery
+ * @dev_addr: Who sent the request or responded to our request.
+ * @request: Will be 1 if request, 0 for response.
+ * @status: Valid only in case of response (0 in case of success)
+ * @config_methods: WPS config methods
+ * @generated_pin: PIN to be displayed in case of WPS_CONFIG_DISPLAY method
+ *
+ * This can be used to notify:
+ * - Requests or responses
+ * - Various config methods
+ * - Failure condition in case of response
+ */
+void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+                                        const u8 *dev_addr, int request,
+                                        enum p2p_prov_disc_status status,
+                                        u16 config_methods,
+                                        unsigned int generated_pin)
+{
+       wpas_dbus_signal_p2p_provision_discovery(wpa_s, dev_addr, request,
+                                                status, config_methods,
+                                                generated_pin);
+}
+
+
+void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
+                                  struct wpa_ssid *ssid, int network_id,
+                                  int client)
+{
+       /* Notify a group has been started */
+       wpas_dbus_register_p2p_group(wpa_s, ssid);
+
+       wpas_dbus_signal_p2p_group_started(wpa_s, ssid, client, network_id);
+}
+
+
+void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+                               struct wps_event_fail *fail)
+{
+       wpas_dbus_signal_p2p_wps_failed(wpa_s, fail);
+}
+
+#endif /* CONFIG_P2P */
+
+
+static void wpas_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
+                                         const u8 *sta)
+{
+#ifdef CONFIG_P2P
+       /*
+        * Register a group member object corresponding to this peer and
+        * emit a PeerJoined signal. This will check if it really is a
+        * P2P group.
+        */
+       wpas_dbus_register_p2p_groupmember(wpa_s, sta);
+
+       /*
+        * Create 'peer-joined' signal on group object -- will also
+        * check P2P itself.
+        */
+       wpas_dbus_signal_p2p_peer_joined(wpa_s, sta);
+#endif /* CONFIG_P2P */
+}
+
+
+static void wpas_notify_ap_sta_deauthorized(struct wpa_supplicant *wpa_s,
+                                           const u8 *sta)
+{
+#ifdef CONFIG_P2P
+       /*
+        * Unregister a group member object corresponding to this peer
+        * if this is a P2P group.
+        */
+       wpas_dbus_unregister_p2p_groupmember(wpa_s, sta);
+
+       /*
+        * Create 'peer-disconnected' signal on group object if this
+        * is a P2P group.
+        */
+       wpas_dbus_signal_p2p_peer_disconnected(wpa_s, sta);
+#endif /* CONFIG_P2P */
+}
+
+
+void wpas_notify_sta_authorized(struct wpa_supplicant *wpa_s,
+                               const u8 *mac_addr, int authorized)
+{
+       if (authorized)
+               wpas_notify_ap_sta_authorized(wpa_s, mac_addr);
+       else
+               wpas_notify_ap_sta_deauthorized(wpa_s, mac_addr);
+}
+
+
+void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
+                              const char *subject, const char *cert_hash,
+                              const struct wpabuf *cert)
+{
+       wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
+               "depth=%d subject='%s'%s%s",
+               depth, subject,
+               cert_hash ? " hash=" : "",
+               cert_hash ? cert_hash : "");
+
+       if (cert) {
+               char *cert_hex;
+               size_t len = wpabuf_len(cert) * 2 + 1;
+               cert_hex = os_malloc(len);
+               if (cert_hex) {
+                       wpa_snprintf_hex(cert_hex, len, wpabuf_head(cert),
+                                        wpabuf_len(cert));
+                       wpa_msg_ctrl(wpa_s, MSG_INFO,
+                                    WPA_EVENT_EAP_PEER_CERT
+                                    "depth=%d subject='%s' cert=%s",
+                                    depth, subject, cert_hex);
+                       os_free(cert_hex);
+               }
+       }
+
+       /* notify the old DBus API */
+       wpa_supplicant_dbus_notify_certification(wpa_s, depth, subject,
+                                                cert_hash, cert);
+       /* notify the new DBus API */
+       wpas_dbus_signal_certification(wpa_s, depth, subject, cert_hash, cert);
+}
index 2e70bdb..7d4a11e 100644 (file)
@@ -15,6 +15,8 @@
 #ifndef NOTIFY_H
 #define NOTIFY_H
 
+#include "p2p/p2p.h"
+
 struct wps_credential;
 struct wps_event_m2d;
 struct wps_event_fail;
@@ -29,10 +31,15 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
 void wpas_notify_network_changed(struct wpa_supplicant *wpa_s);
 void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s);
 void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s);
+void wpas_notify_auth_changed(struct wpa_supplicant *wpa_s);
 void wpas_notify_network_enabled_changed(struct wpa_supplicant *wpa_s,
                                         struct wpa_ssid *ssid);
 void wpas_notify_network_selected(struct wpa_supplicant *wpa_s,
                                  struct wpa_ssid *ssid);
+void wpas_notify_network_request(struct wpa_supplicant *wpa_s,
+                                struct wpa_ssid *ssid,
+                                enum wpa_ctrl_req_type rtype,
+                                const char *default_txt);
 void wpas_notify_scanning(struct wpa_supplicant *wpa_s);
 void wpas_notify_scan_done(struct wpa_supplicant *wpa_s, int success);
 void wpas_notify_scan_results(struct wpa_supplicant *wpa_s);
@@ -78,4 +85,46 @@ void wpas_notify_debug_show_keys_changed(struct wpa_global *global);
 void wpas_notify_suspend(struct wpa_global *global);
 void wpas_notify_resume(struct wpa_global *global);
 
+void wpas_notify_sta_authorized(struct wpa_supplicant *wpa_s,
+                               const u8 *mac_addr, int authorized);
+void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s,
+                                 const u8 *dev_addr, int new_device);
+void wpas_notify_p2p_device_lost(struct wpa_supplicant *wpa_s,
+                                const u8 *dev_addr);
+void wpas_notify_p2p_group_removed(struct wpa_supplicant *wpa_s,
+                                  const struct wpa_ssid *ssid,
+                                  const char *role);
+void wpas_notify_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
+                               const u8 *src, u16 dev_passwd_id);
+void wpas_notify_p2p_go_neg_completed(struct wpa_supplicant *wpa_s,
+                                     struct p2p_go_neg_results *res);
+void wpas_notify_p2p_invitation_result(struct wpa_supplicant *wpa_s,
+                                      int status, const u8 *bssid);
+void wpas_notify_p2p_sd_request(struct wpa_supplicant *wpa_s,
+                               int freq, const u8 *sa, u8 dialog_token,
+                               u16 update_indic, const u8 *tlvs,
+                               size_t tlvs_len);
+void wpas_notify_p2p_sd_response(struct wpa_supplicant *wpa_s,
+                                const u8 *sa, u16 update_indic,
+                                const u8 *tlvs, size_t tlvs_len);
+void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+                                        const u8 *dev_addr, int request,
+                                        enum p2p_prov_disc_status status,
+                                        u16 config_methods,
+                                        unsigned int generated_pin);
+void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
+                                  struct wpa_ssid *ssid, int network_id,
+                                  int client);
+void wpas_notify_persistent_group_added(struct wpa_supplicant *wpa_s,
+                                       struct wpa_ssid *ssid);
+void wpas_notify_persistent_group_removed(struct wpa_supplicant *wpa_s,
+                                         struct wpa_ssid *ssid);
+
+void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+                               struct wps_event_fail *fail);
+
+void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
+                              const char *subject, const char *cert_hash,
+                              const struct wpabuf *cert);
+
 #endif /* NOTIFY_H */
diff --git a/wpa_supplicant/offchannel.c b/wpa_supplicant/offchannel.c
new file mode 100644 (file)
index 0000000..790f14a
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * wpa_supplicant - Off-channel Action frame TX/RX
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "utils/eloop.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "offchannel.h"
+
+
+
+static struct wpa_supplicant *
+wpas_get_tx_interface(struct wpa_supplicant *wpa_s, const u8 *src)
+{
+       struct wpa_supplicant *iface;
+
+       if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0)
+               return wpa_s;
+
+       /*
+        * Try to find a group interface that matches with the source address.
+        */
+       iface = wpa_s->global->ifaces;
+       while (iface) {
+               if (os_memcmp(wpa_s->pending_action_src,
+                             iface->own_addr, ETH_ALEN) == 0)
+                       break;
+               iface = iface->next;
+       }
+       if (iface) {
+               wpa_printf(MSG_DEBUG, "P2P: Use group interface %s "
+                          "instead of interface %s for Action TX",
+                          iface->ifname, wpa_s->ifname);
+               return iface;
+       }
+
+       return wpa_s;
+}
+
+
+static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       struct wpa_supplicant *iface;
+       int res;
+       int without_roc;
+
+       without_roc = wpa_s->pending_action_without_roc;
+       wpa_s->pending_action_without_roc = 0;
+       wpa_printf(MSG_DEBUG, "Off-channel: Send Action callback "
+                  "(without_roc=%d pending_action_tx=%p)",
+                  without_roc, wpa_s->pending_action_tx);
+
+       if (wpa_s->pending_action_tx == NULL)
+               return;
+
+       /*
+        * This call is likely going to be on the P2P device instance if the
+        * driver uses a separate interface for that purpose. However, some
+        * Action frames are actually sent within a P2P Group and when that is
+        * the case, we need to follow power saving (e.g., GO buffering the
+        * frame for a client in PS mode or a client following the advertised
+        * NoA from its GO). To make that easier for the driver, select the
+        * correct group interface here.
+        */
+       iface = wpas_get_tx_interface(wpa_s, wpa_s->pending_action_src);
+
+       if (wpa_s->off_channel_freq != wpa_s->pending_action_freq &&
+           wpa_s->pending_action_freq != 0 &&
+           wpa_s->pending_action_freq != iface->assoc_freq) {
+               wpa_printf(MSG_DEBUG, "Off-channel: Pending Action frame TX "
+                          "waiting for another freq=%u (off_channel_freq=%u "
+                          "assoc_freq=%u)",
+                          wpa_s->pending_action_freq,
+                          wpa_s->off_channel_freq,
+                          iface->assoc_freq);
+               if (without_roc && wpa_s->off_channel_freq == 0) {
+                       /*
+                        * We may get here if wpas_send_action() found us to be
+                        * on the correct channel, but remain-on-channel cancel
+                        * event was received before getting here.
+                        */
+                       wpa_printf(MSG_DEBUG, "Off-channel: Schedule "
+                                  "remain-on-channel to send Action frame");
+                       if (wpa_drv_remain_on_channel(
+                                   wpa_s, wpa_s->pending_action_freq, 200) <
+                           0) {
+                               wpa_printf(MSG_DEBUG, "Off-channel: Failed to "
+                                          "request driver to remain on "
+                                          "channel (%u MHz) for Action Frame "
+                                          "TX", wpa_s->pending_action_freq);
+                       } else {
+                               wpa_s->off_channel_freq = 0;
+                               wpa_s->roc_waiting_drv_freq =
+                                       wpa_s->pending_action_freq;
+                       }
+               }
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "Off-channel: Sending pending Action frame to "
+                  MACSTR " using interface %s",
+                  MAC2STR(wpa_s->pending_action_dst), iface->ifname);
+       res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0,
+                                 wpa_s->pending_action_dst,
+                                 wpa_s->pending_action_src,
+                                 wpa_s->pending_action_bssid,
+                                 wpabuf_head(wpa_s->pending_action_tx),
+                                 wpabuf_len(wpa_s->pending_action_tx),
+                                 wpa_s->pending_action_no_cck);
+       if (res) {
+               wpa_printf(MSG_DEBUG, "Off-channel: Failed to send the "
+                          "pending Action frame");
+               /*
+                * Use fake TX status event to allow state machines to
+                * continue.
+                */
+               offchannel_send_action_tx_status(
+                       wpa_s, wpa_s->pending_action_dst,
+                       wpabuf_head(wpa_s->pending_action_tx),
+                       wpabuf_len(wpa_s->pending_action_tx),
+                       OFFCHANNEL_SEND_ACTION_FAILED);
+       }
+}
+
+
+void offchannel_send_action_tx_status(
+       struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data,
+       size_t data_len, enum offchannel_send_action_result result)
+{
+       if (wpa_s->pending_action_tx == NULL) {
+               wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
+                          "no pending operation");
+               return;
+       }
+
+       if (os_memcmp(dst, wpa_s->pending_action_dst, ETH_ALEN) != 0) {
+               wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
+                          "unknown destination address");
+               return;
+       }
+
+       wpabuf_free(wpa_s->pending_action_tx);
+       wpa_s->pending_action_tx = NULL;
+
+       wpa_printf(MSG_DEBUG, "Off-channel: TX status result=%d cb=%p",
+                  result, wpa_s->pending_action_tx_status_cb);
+
+       if (wpa_s->pending_action_tx_status_cb) {
+               wpa_s->pending_action_tx_status_cb(
+                       wpa_s, wpa_s->pending_action_freq,
+                       wpa_s->pending_action_dst, wpa_s->pending_action_src,
+                       wpa_s->pending_action_bssid,
+                       data, data_len, result);
+       }
+}
+
+
+int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
+                          const u8 *dst, const u8 *src, const u8 *bssid,
+                          const u8 *buf, size_t len, unsigned int wait_time,
+                          void (*tx_cb)(struct wpa_supplicant *wpa_s,
+                                        unsigned int freq, const u8 *dst,
+                                        const u8 *src, const u8 *bssid,
+                                        const u8 *data, size_t data_len,
+                                        enum offchannel_send_action_result
+                                        result),
+                          int no_cck)
+{
+       wpa_printf(MSG_DEBUG, "Off-channel: Send action frame: freq=%d dst="
+                  MACSTR " src=" MACSTR " bssid=" MACSTR " len=%d",
+                  freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
+                  (int) len);
+
+       wpa_s->pending_action_tx_status_cb = tx_cb;
+
+       if (wpa_s->pending_action_tx) {
+               wpa_printf(MSG_DEBUG, "Off-channel: Dropped pending Action "
+                          "frame TX to " MACSTR,
+                          MAC2STR(wpa_s->pending_action_dst));
+               wpabuf_free(wpa_s->pending_action_tx);
+       }
+       wpa_s->pending_action_tx = wpabuf_alloc(len);
+       if (wpa_s->pending_action_tx == NULL) {
+               wpa_printf(MSG_DEBUG, "Off-channel: Failed to allocate Action "
+                          "frame TX buffer (len=%llu)",
+                          (unsigned long long) len);
+               return -1;
+       }
+       wpabuf_put_data(wpa_s->pending_action_tx, buf, len);
+       os_memcpy(wpa_s->pending_action_src, src, ETH_ALEN);
+       os_memcpy(wpa_s->pending_action_dst, dst, ETH_ALEN);
+       os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN);
+       wpa_s->pending_action_freq = freq;
+       wpa_s->pending_action_no_cck = no_cck;
+
+       if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
+               struct wpa_supplicant *iface;
+
+               iface = wpas_get_tx_interface(wpa_s,
+                                             wpa_s->pending_action_src);
+               wpa_s->action_tx_wait_time = wait_time;
+
+               return wpa_drv_send_action(
+                       iface, wpa_s->pending_action_freq,
+                       wait_time, wpa_s->pending_action_dst,
+                       wpa_s->pending_action_src, wpa_s->pending_action_bssid,
+                       wpabuf_head(wpa_s->pending_action_tx),
+                       wpabuf_len(wpa_s->pending_action_tx),
+                       wpa_s->pending_action_no_cck);
+       }
+
+       if (freq) {
+               struct wpa_supplicant *tx_iface;
+               tx_iface = wpas_get_tx_interface(wpa_s, src);
+               if (tx_iface->assoc_freq == freq) {
+                       wpa_printf(MSG_DEBUG, "Off-channel: Already on "
+                                  "requested channel (TX interface operating "
+                                  "channel)");
+                       freq = 0;
+               }
+       }
+
+       if (wpa_s->off_channel_freq == freq || freq == 0) {
+               wpa_printf(MSG_DEBUG, "Off-channel: Already on requested "
+                          "channel; send Action frame immediately");
+               /* TODO: Would there ever be need to extend the current
+                * duration on the channel? */
+               wpa_s->pending_action_without_roc = 1;
+               eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
+               eloop_register_timeout(0, 0, wpas_send_action_cb, wpa_s, NULL);
+               return 0;
+       }
+       wpa_s->pending_action_without_roc = 0;
+
+       if (wpa_s->roc_waiting_drv_freq == freq) {
+               wpa_printf(MSG_DEBUG, "Off-channel: Already waiting for "
+                          "driver to get to frequency %u MHz; continue "
+                          "waiting to send the Action frame", freq);
+               return 0;
+       }
+
+       wpa_printf(MSG_DEBUG, "Off-channel: Schedule Action frame to be "
+                  "transmitted once the driver gets to the requested "
+                  "channel");
+       if (wait_time > wpa_s->max_remain_on_chan)
+               wait_time = wpa_s->max_remain_on_chan;
+       if (wpa_drv_remain_on_channel(wpa_s, freq, wait_time) < 0) {
+               wpa_printf(MSG_DEBUG, "Off-channel: Failed to request driver "
+                          "to remain on channel (%u MHz) for Action "
+                          "Frame TX", freq);
+               return -1;
+       }
+       wpa_s->off_channel_freq = 0;
+       wpa_s->roc_waiting_drv_freq = freq;
+
+       return 0;
+}
+
+
+void offchannel_send_action_done(struct wpa_supplicant *wpa_s)
+{
+       wpa_printf(MSG_DEBUG, "Off-channel: Action frame sequence done "
+                  "notification");
+       wpabuf_free(wpa_s->pending_action_tx);
+       wpa_s->pending_action_tx = NULL;
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX &&
+           wpa_s->action_tx_wait_time)
+               wpa_drv_send_action_cancel_wait(wpa_s);
+
+       if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
+               wpa_drv_cancel_remain_on_channel(wpa_s);
+               wpa_s->off_channel_freq = 0;
+               wpa_s->roc_waiting_drv_freq = 0;
+       }
+}
+
+
+void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+                                    unsigned int freq, unsigned int duration)
+{
+       wpa_s->roc_waiting_drv_freq = 0;
+       wpa_s->off_channel_freq = freq;
+       wpas_send_action_cb(wpa_s, NULL);
+}
+
+
+void offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+                                           unsigned int freq)
+{
+       wpa_s->off_channel_freq = 0;
+}
+
+
+void offchannel_deinit(struct wpa_supplicant *wpa_s)
+{
+       wpabuf_free(wpa_s->pending_action_tx);
+       wpa_s->pending_action_tx = NULL;
+       eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
+}
diff --git a/wpa_supplicant/offchannel.h b/wpa_supplicant/offchannel.h
new file mode 100644 (file)
index 0000000..60e0d03
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * wpa_supplicant - Off-channel Action frame TX/RX
+ * 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.
+ */
+
+#ifndef OFFCHANNEL_H
+#define OFFCHANNEL_H
+
+int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
+                          const u8 *dst, const u8 *src, const u8 *bssid,
+                          const u8 *buf, size_t len, unsigned int wait_time,
+                          void (*tx_cb)(struct wpa_supplicant *wpa_s,
+                                        unsigned int freq, const u8 *dst,
+                                        const u8 *src, const u8 *bssid,
+                                        const u8 *data, size_t data_len,
+                                        enum offchannel_send_action_result
+                                        result),
+                          int no_cck);
+void offchannel_send_action_done(struct wpa_supplicant *wpa_s);
+void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+                                    unsigned int freq, unsigned int duration);
+void offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+                                           unsigned int freq);
+void offchannel_deinit(struct wpa_supplicant *wpa_s);
+void offchannel_send_action_tx_status(
+       struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data,
+       size_t data_len, enum offchannel_send_action_result result);
+
+#endif /* OFFCHANNEL_H */
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
new file mode 100644 (file)
index 0000000..7cf37d0
--- /dev/null
@@ -0,0 +1,4259 @@
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "common/ieee802_11_common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
+#include "wps/wps_i.h"
+#include "p2p/p2p.h"
+#include "ap/hostapd.h"
+#include "ap/ap_config.h"
+#include "ap/p2p_hostapd.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "ap.h"
+#include "config_ssid.h"
+#include "config.h"
+#include "notify.h"
+#include "scan.h"
+#include "bss.h"
+#include "offchannel.h"
+#include "wps_supplicant.h"
+#include "p2p_supplicant.h"
+
+
+/*
+ * How many times to try to scan to find the GO before giving up on join
+ * request.
+ */
+#define P2P_MAX_JOIN_SCAN_ATTEMPTS 10
+
+#ifndef P2P_MAX_CLIENT_IDLE
+/*
+ * How many seconds to try to reconnect to the GO when connection in P2P client
+ * role has been lost.
+ */
+#define P2P_MAX_CLIENT_IDLE 10
+#endif /* P2P_MAX_CLIENT_IDLE */
+
+
+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(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);
+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_scan_res_handler(struct wpa_supplicant *wpa_s,
+                                     struct wpa_scan_results *scan_res)
+{
+       size_t i;
+
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return;
+
+       wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS)",
+                  (int) scan_res->num);
+
+       for (i = 0; i < scan_res->num; i++) {
+               struct wpa_scan_res *bss = scan_res->res[i];
+               if (p2p_scan_res_handler(wpa_s->global->p2p, bss->bssid,
+                                        bss->freq, bss->level,
+                                        (const u8 *) (bss + 1),
+                                        bss->ie_len) > 0)
+                       break;
+       }
+
+       p2p_scan_res_handled(wpa_s->global->p2p);
+}
+
+
+static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
+                        unsigned int num_req_dev_types,
+                        const u8 *req_dev_types)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       struct wpa_driver_scan_params params;
+       int ret;
+       struct wpabuf *wps_ie, *ies;
+       int social_channels[] = { 2412, 2437, 2462, 0, 0 };
+       size_t ielen;
+       int was_in_p2p_scan;
+
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+
+       os_memset(&params, 0, sizeof(params));
+
+       /* P2P Wildcard SSID */
+       params.num_ssids = 1;
+       params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
+       params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+
+       wpa_s->wps->dev.p2p = 1;
+       wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
+                                       WPS_REQ_ENROLLEE,
+                                       num_req_dev_types, req_dev_types);
+       if (wps_ie == NULL)
+               return -1;
+
+       ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
+       ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
+       if (ies == NULL) {
+               wpabuf_free(wps_ie);
+               return -1;
+       }
+       wpabuf_put_buf(ies, wps_ie);
+       wpabuf_free(wps_ie);
+
+       p2p_scan_ie(wpa_s->global->p2p, ies);
+
+       params.p2p_probe = 1;
+       params.extra_ies = wpabuf_head(ies);
+       params.extra_ies_len = wpabuf_len(ies);
+
+       switch (type) {
+       case P2P_SCAN_SOCIAL:
+               params.freqs = social_channels;
+               break;
+       case P2P_SCAN_FULL:
+               break;
+       case P2P_SCAN_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;
+               }
+       }
+
+       return ret;
+}
+
+
+static enum wpa_driver_if_type wpas_p2p_if_type(int p2p_group_interface)
+{
+       switch (p2p_group_interface) {
+       case P2P_GROUP_INTERFACE_PENDING:
+               return WPA_IF_P2P_GROUP;
+       case P2P_GROUP_INTERFACE_GO:
+               return WPA_IF_P2P_GO;
+       case P2P_GROUP_INTERFACE_CLIENT:
+               return WPA_IF_P2P_CLIENT;
+       }
+
+       return WPA_IF_P2P_GROUP;
+}
+
+
+static struct wpa_supplicant * wpas_get_p2p_group(struct wpa_supplicant *wpa_s,
+                                                 const u8 *ssid,
+                                                 size_t ssid_len, int *go)
+{
+       struct wpa_ssid *s;
+
+       for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+               for (s = wpa_s->conf->ssid; s; s = s->next) {
+                       if (s->disabled != 0 || !s->p2p_group ||
+                           s->ssid_len != ssid_len ||
+                           os_memcmp(ssid, s->ssid, ssid_len) != 0)
+                               continue;
+                       if (s->mode == WPAS_MODE_P2P_GO &&
+                           s != wpa_s->current_ssid)
+                               continue;
+                       if (go)
+                               *go = s->mode == WPAS_MODE_P2P_GO;
+                       return wpa_s;
+               }
+       }
+
+       return NULL;
+}
+
+
+static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
+{
+       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.
+                */
+               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)))
+                               break;
+                       ssid = ssid->next;
+               }
+       }
+       if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_GO)
+               gtype = "GO";
+       else if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT ||
+                (ssid && ssid->mode == WPAS_MODE_INFRA)) {
+               wpa_s->reassociate = 0;
+               wpa_s->disconnected = 1;
+               wpa_supplicant_deauthenticate(wpa_s,
+                                             WLAN_REASON_DEAUTH_LEAVING);
+               gtype = "client";
+       } else
+               gtype = "GO";
+       if (wpa_s->cross_connect_in_use) {
+               wpa_s->cross_connect_in_use = 0;
+               wpa_msg(wpa_s->parent, MSG_INFO,
+                       P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+                       wpa_s->ifname, wpa_s->cross_connect_uplink);
+       }
+       switch (wpa_s->removal_reason) {
+       case P2P_GROUP_REMOVAL_REQUESTED:
+               reason = " reason=REQUESTED";
+               break;
+       case P2P_GROUP_REMOVAL_IDLE_TIMEOUT:
+               reason = " reason=IDLE";
+               break;
+       case P2P_GROUP_REMOVAL_UNAVAILABLE:
+               reason = " reason=UNAVAILABLE";
+               break;
+       default:
+               reason = "";
+               break;
+       }
+       wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_REMOVED "%s %s%s",
+               wpa_s->ifname, gtype, reason);
+
+       if (ssid)
+               wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
+
+       if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
+               struct wpa_global *global;
+               char *ifname;
+               enum wpa_driver_if_type type;
+               wpa_printf(MSG_DEBUG, "P2P: Remove group interface %s",
+                       wpa_s->ifname);
+               global = wpa_s->global;
+               ifname = os_strdup(wpa_s->ifname);
+               type = wpas_p2p_if_type(wpa_s->p2p_group_interface);
+               wpa_supplicant_remove_iface(wpa_s->global, wpa_s);
+               wpa_s = global->ifaces;
+               if (wpa_s && ifname)
+                       wpa_drv_if_remove(wpa_s, type, ifname);
+               os_free(ifname);
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "P2P: Remove temporary group network");
+       if (ssid && (ssid->p2p_group ||
+                    ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION ||
+                    (ssid->key_mgmt & WPA_KEY_MGMT_WPS))) {
+               int id = ssid->id;
+               if (ssid == wpa_s->current_ssid) {
+                       wpa_sm_set_config(wpa_s->wpa, NULL);
+                       eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+                       wpa_s->current_ssid = NULL;
+               }
+               /*
+                * Networks objects created during any P2P activities are not
+                * exposed out as they might/will confuse certain non-P2P aware
+                * applications since these network objects won't behave like
+                * regular ones.
+                *
+                * Likewise, we don't send out network removed signals for such
+                * network objects.
+                */
+               wpa_config_remove_network(wpa_s->conf, id);
+               wpa_supplicant_clear_status(wpa_s);
+       } else {
+               wpa_printf(MSG_DEBUG, "P2P: Temporary group network not "
+                          "found");
+       }
+       wpa_supplicant_ap_deinit(wpa_s);
+}
+
+
+static int wpas_p2p_persistent_group(struct wpa_supplicant *wpa_s,
+                                    u8 *go_dev_addr,
+                                    const u8 *ssid, size_t ssid_len)
+{
+       struct wpa_bss *bss;
+       const u8 *bssid;
+       struct wpabuf *p2p;
+       u8 group_capab;
+       const u8 *addr;
+
+       if (wpa_s->go_params)
+               bssid = wpa_s->go_params->peer_interface_addr;
+       else
+               bssid = wpa_s->bssid;
+
+       bss = wpa_bss_get(wpa_s, bssid, ssid, ssid_len);
+       if (bss == NULL) {
+               u8 iface_addr[ETH_ALEN];
+               if (p2p_get_interface_addr(wpa_s->global->p2p, bssid,
+                                          iface_addr) == 0)
+                       bss = wpa_bss_get(wpa_s, iface_addr, ssid, ssid_len);
+       }
+       if (bss == NULL) {
+               wpa_printf(MSG_DEBUG, "P2P: Could not figure out whether "
+                          "group is persistent - BSS " MACSTR " not found",
+                          MAC2STR(bssid));
+               return 0;
+       }
+
+       p2p = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+       if (p2p == NULL) {
+               wpa_printf(MSG_DEBUG, "P2P: Could not figure out whether "
+                          "group is persistent - BSS " MACSTR
+                          " did not include P2P IE", MAC2STR(bssid));
+               wpa_hexdump(MSG_DEBUG, "P2P: Probe Response IEs",
+                           (u8 *) (bss + 1), bss->ie_len);
+               wpa_hexdump(MSG_DEBUG, "P2P: Beacon IEs",
+                           ((u8 *) bss + 1) + bss->ie_len,
+                           bss->beacon_ie_len);
+               return 0;
+       }
+
+       group_capab = p2p_get_group_capab(p2p);
+       addr = p2p_get_go_dev_addr(p2p);
+       wpa_printf(MSG_DEBUG, "P2P: Checking whether group is persistent: "
+                  "group_capab=0x%x", group_capab);
+       if (addr) {
+               os_memcpy(go_dev_addr, addr, ETH_ALEN);
+               wpa_printf(MSG_DEBUG, "P2P: GO Device Address " MACSTR,
+                          MAC2STR(addr));
+       } else
+               os_memset(go_dev_addr, 0, ETH_ALEN);
+       wpabuf_free(p2p);
+
+       wpa_printf(MSG_DEBUG, "P2P: BSS " MACSTR " group_capab=0x%x "
+                  "go_dev_addr=" MACSTR,
+                  MAC2STR(bssid), group_capab, MAC2STR(go_dev_addr));
+
+       return group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+}
+
+
+static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
+                                          struct wpa_ssid *ssid,
+                                          const u8 *go_dev_addr)
+{
+       struct wpa_ssid *s;
+       int changed = 0;
+
+       wpa_printf(MSG_DEBUG, "P2P: Storing credentials for a persistent "
+                  "group (GO Dev Addr " MACSTR ")", MAC2STR(go_dev_addr));
+       for (s = wpa_s->conf->ssid; s; s = s->next) {
+               if (s->disabled == 2 &&
+                   os_memcmp(go_dev_addr, s->bssid, ETH_ALEN) == 0 &&
+                   s->ssid_len == ssid->ssid_len &&
+                   os_memcmp(ssid->ssid, s->ssid, ssid->ssid_len) == 0)
+                       break;
+       }
+
+       if (s) {
+               wpa_printf(MSG_DEBUG, "P2P: Update existing persistent group "
+                          "entry");
+               if (ssid->passphrase && !s->passphrase)
+                       changed = 1;
+               else if (ssid->passphrase && s->passphrase &&
+                        os_strcmp(ssid->passphrase, s->passphrase) != 0)
+                       changed = 1;
+       } else {
+               wpa_printf(MSG_DEBUG, "P2P: Create a new persistent group "
+                          "entry");
+               changed = 1;
+               s = wpa_config_add_network(wpa_s->conf);
+               if (s == NULL)
+                       return -1;
+
+               /*
+                * Instead of network_added we emit persistent_group_added
+                * notification. Also to keep the defense checks in
+                * persistent_group obj registration method, we set the
+                * relevant flags in s to designate it as a persistent group.
+                */
+               s->p2p_group = 1;
+               s->p2p_persistent_group = 1;
+               wpas_notify_persistent_group_added(wpa_s, s);
+               wpa_config_set_network_defaults(s);
+       }
+
+       s->p2p_group = 1;
+       s->p2p_persistent_group = 1;
+       s->disabled = 2;
+       s->bssid_set = 1;
+       os_memcpy(s->bssid, go_dev_addr, ETH_ALEN);
+       s->mode = ssid->mode;
+       s->auth_alg = WPA_AUTH_ALG_OPEN;
+       s->key_mgmt = WPA_KEY_MGMT_PSK;
+       s->proto = WPA_PROTO_RSN;
+       s->pairwise_cipher = WPA_CIPHER_CCMP;
+       s->export_keys = 1;
+       if (ssid->passphrase) {
+               os_free(s->passphrase);
+               s->passphrase = os_strdup(ssid->passphrase);
+       }
+       if (ssid->psk_set) {
+               s->psk_set = 1;
+               os_memcpy(s->psk, ssid->psk, 32);
+       }
+       if (s->passphrase && !s->psk_set)
+               wpa_config_update_psk(s);
+       if (s->ssid == NULL || s->ssid_len < ssid->ssid_len) {
+               os_free(s->ssid);
+               s->ssid = os_malloc(ssid->ssid_len);
+       }
+       if (s->ssid) {
+               s->ssid_len = ssid->ssid_len;
+               os_memcpy(s->ssid, ssid->ssid, s->ssid_len);
+       }
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+       if (changed && wpa_s->conf->update_config &&
+           wpa_config_write(wpa_s->confname, wpa_s->conf)) {
+               wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
+       }
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+       return s->id;
+}
+
+
+static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
+                                          int success)
+{
+       struct wpa_ssid *ssid;
+       const char *ssid_txt;
+       int client;
+       int persistent;
+       u8 go_dev_addr[ETH_ALEN];
+       int network_id = -1;
+
+       /*
+        * This callback is likely called for the main interface. Update wpa_s
+        * to use the group interface if a new interface was created for the
+        * group.
+        */
+       if (wpa_s->global->p2p_group_formation)
+               wpa_s = wpa_s->global->p2p_group_formation;
+       wpa_s->global->p2p_group_formation = NULL;
+       wpa_s->p2p_in_provisioning = 0;
+
+       if (!success) {
+               wpa_msg(wpa_s->parent, MSG_INFO,
+                       P2P_EVENT_GROUP_FORMATION_FAILURE);
+               wpas_p2p_group_delete(wpa_s);
+               return;
+       }
+
+       wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_FORMATION_SUCCESS);
+
+       ssid = wpa_s->current_ssid;
+       if (ssid && ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
+               ssid->mode = WPAS_MODE_P2P_GO;
+               p2p_group_notif_formation_done(wpa_s->p2p_group);
+               wpa_supplicant_ap_mac_addr_filter(wpa_s, NULL);
+       }
+
+       persistent = 0;
+       if (ssid) {
+               ssid_txt = wpa_ssid_txt(ssid->ssid, ssid->ssid_len);
+               client = ssid->mode == WPAS_MODE_INFRA;
+               if (ssid->mode == WPAS_MODE_P2P_GO) {
+                       persistent = ssid->p2p_persistent_group;
+                       os_memcpy(go_dev_addr, wpa_s->parent->own_addr,
+                                 ETH_ALEN);
+               } else
+                       persistent = wpas_p2p_persistent_group(wpa_s,
+                                                              go_dev_addr,
+                                                              ssid->ssid,
+                                                              ssid->ssid_len);
+       } else {
+               ssid_txt = "";
+               client = wpa_s->p2p_group_interface ==
+                       P2P_GROUP_INTERFACE_CLIENT;
+               os_memset(go_dev_addr, 0, ETH_ALEN);
+       }
+
+       wpa_s->show_group_started = 0;
+       if (client) {
+               /*
+                * Indicate event only after successfully completed 4-way
+                * handshake, i.e., when the interface is ready for data
+                * packets.
+                */
+               wpa_s->show_group_started = 1;
+       } else if (ssid && ssid->passphrase == NULL && ssid->psk_set) {
+               char psk[65];
+               wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
+               wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+                       "%s GO ssid=\"%s\" freq=%d psk=%s go_dev_addr=" MACSTR
+                       "%s",
+                       wpa_s->ifname, ssid_txt, ssid->frequency, psk,
+                       MAC2STR(go_dev_addr),
+                       persistent ? " [PERSISTENT]" : "");
+               wpas_p2p_cross_connect_setup(wpa_s);
+               wpas_p2p_set_group_idle_timeout(wpa_s);
+       } else {
+               wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+                       "%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
+                       "go_dev_addr=" MACSTR "%s",
+                       wpa_s->ifname, ssid_txt, ssid ? ssid->frequency : 0,
+                       ssid && ssid->passphrase ? ssid->passphrase : "",
+                       MAC2STR(go_dev_addr),
+                       persistent ? " [PERSISTENT]" : "");
+               wpas_p2p_cross_connect_setup(wpa_s);
+               wpas_p2p_set_group_idle_timeout(wpa_s);
+       }
+
+       if (persistent)
+               network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
+                                                            ssid, go_dev_addr);
+       if (network_id < 0 && ssid)
+               network_id = ssid->id;
+       if (!client)
+               wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+}
+
+
+static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
+                                          unsigned int freq,
+                                          const u8 *dst, const u8 *src,
+                                          const u8 *bssid,
+                                          const u8 *data, size_t data_len,
+                                          enum offchannel_send_action_result
+                                          result)
+{
+       enum p2p_send_action_result res = P2P_SEND_ACTION_SUCCESS;
+
+       if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
+               return;
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return;
+
+       switch (result) {
+       case OFFCHANNEL_SEND_ACTION_SUCCESS:
+               res = P2P_SEND_ACTION_SUCCESS;
+               break;
+       case OFFCHANNEL_SEND_ACTION_NO_ACK:
+               res = P2P_SEND_ACTION_NO_ACK;
+               break;
+       case OFFCHANNEL_SEND_ACTION_FAILED:
+               res = P2P_SEND_ACTION_FAILED;
+               break;
+       }
+
+       p2p_send_action_cb(wpa_s->global->p2p, freq, dst, src, bssid, res);
+
+       if (wpa_s->pending_pd_before_join &&
+           (os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
+            os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
+               wpa_s->pending_pd_before_join = 0;
+               wpa_printf(MSG_DEBUG, "P2P: Starting pending "
+                          "join-existing-group operation");
+               wpas_p2p_join_start(wpa_s);
+       }
+}
+
+
+static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
+                           const u8 *src, const u8 *bssid, const u8 *buf,
+                           size_t len, unsigned int wait_time)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       return offchannel_send_action(wpa_s, freq, dst, src, bssid, buf, len,
+                                     wait_time,
+                                     wpas_p2p_send_action_tx_status, 1);
+}
+
+
+static void wpas_send_action_done(void *ctx)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       offchannel_send_action_done(wpa_s);
+}
+
+
+static int wpas_copy_go_neg_results(struct wpa_supplicant *wpa_s,
+                                   struct p2p_go_neg_results *params)
+{
+       if (wpa_s->go_params == NULL) {
+               wpa_s->go_params = os_malloc(sizeof(*params));
+               if (wpa_s->go_params == NULL)
+                       return -1;
+       }
+       os_memcpy(wpa_s->go_params, params, sizeof(*params));
+       return 0;
+}
+
+
+static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
+                                   struct p2p_go_neg_results *res)
+{
+       wpa_printf(MSG_DEBUG, "P2P: Start WPS Enrollee for peer " MACSTR,
+                  MAC2STR(res->peer_interface_addr));
+       wpa_hexdump_ascii(MSG_DEBUG, "P2P: Start WPS Enrollee for SSID",
+                         res->ssid, res->ssid_len);
+       wpa_supplicant_ap_deinit(wpa_s);
+       wpas_copy_go_neg_results(wpa_s, res);
+       if (res->wps_method == WPS_PBC)
+               wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1);
+       else {
+               u16 dev_pw_id = DEV_PW_DEFAULT;
+               if (wpa_s->p2p_wps_method == WPS_PIN_KEYPAD)
+                       dev_pw_id = DEV_PW_REGISTRAR_SPECIFIED;
+               wpas_wps_start_pin(wpa_s, res->peer_interface_addr,
+                                  wpa_s->p2p_pin, 1, dev_pw_id);
+       }
+}
+
+
+static void p2p_go_configured(void *ctx, void *data)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       struct p2p_go_neg_results *params = data;
+       struct wpa_ssid *ssid;
+       int network_id = -1;
+
+       ssid = wpa_s->current_ssid;
+       if (ssid && ssid->mode == WPAS_MODE_P2P_GO) {
+               wpa_printf(MSG_DEBUG, "P2P: Group setup without provisioning");
+               if (wpa_s->global->p2p_group_formation == wpa_s)
+                       wpa_s->global->p2p_group_formation = NULL;
+               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 (params->persistent_group)
+                       network_id = wpas_p2p_store_persistent_group(
+                               wpa_s->parent, ssid,
+                               wpa_s->parent->own_addr);
+               if (network_id < 0)
+                       network_id = ssid->id;
+               wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+               wpas_p2p_cross_connect_setup(wpa_s);
+               wpas_p2p_set_group_idle_timeout(wpa_s);
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "P2P: Setting up WPS for GO provisioning");
+       if (wpa_supplicant_ap_mac_addr_filter(wpa_s,
+                                             params->peer_interface_addr)) {
+               wpa_printf(MSG_DEBUG, "P2P: Failed to setup MAC address "
+                          "filtering");
+               return;
+       }
+       if (params->wps_method == WPS_PBC)
+               wpa_supplicant_ap_wps_pbc(wpa_s, params->peer_interface_addr,
+                                         params->peer_device_addr);
+       else if (wpa_s->p2p_pin[0])
+               wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
+                                         wpa_s->p2p_pin, NULL, 0);
+       os_free(wpa_s->go_params);
+       wpa_s->go_params = NULL;
+}
+
+
+static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
+                             struct p2p_go_neg_results *params,
+                             int group_formation)
+{
+       struct wpa_ssid *ssid;
+
+       if (wpas_copy_go_neg_results(wpa_s, params) < 0)
+               return;
+
+       ssid = wpa_config_add_network(wpa_s->conf);
+       if (ssid == NULL)
+               return;
+
+       wpa_s->show_group_started = 0;
+
+       wpa_config_set_network_defaults(ssid);
+       ssid->temporary = 1;
+       ssid->p2p_group = 1;
+       ssid->p2p_persistent_group = params->persistent_group;
+       ssid->mode = group_formation ? WPAS_MODE_P2P_GROUP_FORMATION :
+               WPAS_MODE_P2P_GO;
+       ssid->frequency = params->freq;
+       ssid->ssid = os_zalloc(params->ssid_len + 1);
+       if (ssid->ssid) {
+               os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
+               ssid->ssid_len = params->ssid_len;
+       }
+       ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+       ssid->key_mgmt = WPA_KEY_MGMT_PSK;
+       ssid->proto = WPA_PROTO_RSN;
+       ssid->pairwise_cipher = WPA_CIPHER_CCMP;
+       ssid->passphrase = os_strdup(params->passphrase);
+
+       wpa_s->ap_configured_cb = p2p_go_configured;
+       wpa_s->ap_configured_cb_ctx = wpa_s;
+       wpa_s->ap_configured_cb_data = wpa_s->go_params;
+       wpa_s->connect_without_scan = ssid;
+       wpa_s->reassociate = 1;
+       wpa_s->disconnected = 0;
+       wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
+
+
+static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
+                                 const struct wpa_supplicant *src)
+{
+       struct wpa_config *d;
+       const struct wpa_config *s;
+
+       d = dst->conf;
+       s = src->conf;
+
+#define C(n) if (s->n) d->n = os_strdup(s->n)
+       C(device_name);
+       C(manufacturer);
+       C(model_name);
+       C(model_number);
+       C(serial_number);
+       C(config_methods);
+#undef C
+
+       os_memcpy(d->device_type, s->device_type, WPS_DEV_TYPE_LEN);
+       os_memcpy(d->sec_device_type, s->sec_device_type,
+                 sizeof(d->sec_device_type));
+       d->num_sec_device_types = s->num_sec_device_types;
+
+       d->p2p_group_idle = s->p2p_group_idle;
+       d->p2p_intra_bss = s->p2p_intra_bss;
+       d->persistent_reconnect = s->persistent_reconnect;
+}
+
+
+static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
+                                       enum wpa_driver_if_type type)
+{
+       char ifname[120], force_ifname[120];
+
+       if (wpa_s->pending_interface_name[0]) {
+               wpa_printf(MSG_DEBUG, "P2P: Pending virtual interface exists "
+                          "- skip creation of a new one");
+               if (is_zero_ether_addr(wpa_s->pending_interface_addr)) {
+                       wpa_printf(MSG_DEBUG, "P2P: Pending virtual address "
+                                  "unknown?! ifname='%s'",
+                                  wpa_s->pending_interface_name);
+                       return -1;
+               }
+               return 0;
+       }
+
+       os_snprintf(ifname, sizeof(ifname), "p2p-%s-%d", wpa_s->ifname,
+                   wpa_s->p2p_group_idx);
+       if (os_strlen(ifname) >= IFNAMSIZ &&
+           os_strlen(wpa_s->ifname) < IFNAMSIZ) {
+               /* Try to avoid going over the IFNAMSIZ length limit */
+               os_snprintf(ifname, sizeof(ifname), "p2p-%d",
+                           wpa_s->p2p_group_idx);
+       }
+       force_ifname[0] = '\0';
+
+       wpa_printf(MSG_DEBUG, "P2P: Create a new interface %s for the group",
+                  ifname);
+       wpa_s->p2p_group_idx++;
+
+       wpa_s->pending_interface_type = type;
+       if (wpa_drv_if_add(wpa_s, type, ifname, NULL, NULL, force_ifname,
+                          wpa_s->pending_interface_addr, NULL) < 0) {
+               wpa_printf(MSG_ERROR, "P2P: Failed to create new group "
+                          "interface");
+               return -1;
+       }
+
+       if (force_ifname[0]) {
+               wpa_printf(MSG_DEBUG, "P2P: Driver forced interface name %s",
+                          force_ifname);
+               os_strlcpy(wpa_s->pending_interface_name, force_ifname,
+                          sizeof(wpa_s->pending_interface_name));
+       } else
+               os_strlcpy(wpa_s->pending_interface_name, ifname,
+                          sizeof(wpa_s->pending_interface_name));
+       wpa_printf(MSG_DEBUG, "P2P: Created pending virtual interface %s addr "
+                  MACSTR, wpa_s->pending_interface_name,
+                  MAC2STR(wpa_s->pending_interface_addr));
+
+       return 0;
+}
+
+
+static void wpas_p2p_remove_pending_group_interface(
+       struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s->pending_interface_name[0] ||
+           is_zero_ether_addr(wpa_s->pending_interface_addr))
+               return; /* No pending virtual interface */
+
+       wpa_printf(MSG_DEBUG, "P2P: Removing pending group interface %s",
+                  wpa_s->pending_interface_name);
+       wpa_drv_if_remove(wpa_s, wpa_s->pending_interface_type,
+                         wpa_s->pending_interface_name);
+       os_memset(wpa_s->pending_interface_addr, 0, ETH_ALEN);
+       wpa_s->pending_interface_name[0] = '\0';
+}
+
+
+static struct wpa_supplicant *
+wpas_p2p_init_group_interface(struct wpa_supplicant *wpa_s, int go)
+{
+       struct wpa_interface iface;
+       struct wpa_supplicant *group_wpa_s;
+
+       if (!wpa_s->pending_interface_name[0]) {
+               wpa_printf(MSG_ERROR, "P2P: No pending group interface");
+               if (!wpas_p2p_create_iface(wpa_s))
+                       return NULL;
+               /*
+                * Something has forced us to remove the pending interface; try
+                * to create a new one and hope for the best that we will get
+                * the same local address.
+                */
+               if (wpas_p2p_add_group_interface(wpa_s, go ? WPA_IF_P2P_GO :
+                                                WPA_IF_P2P_CLIENT) < 0)
+                       return NULL;
+       }
+
+       os_memset(&iface, 0, sizeof(iface));
+       iface.ifname = wpa_s->pending_interface_name;
+       iface.driver = wpa_s->driver->name;
+       iface.ctrl_interface = wpa_s->conf->ctrl_interface;
+       iface.driver_param = wpa_s->conf->driver_param;
+       group_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
+       if (group_wpa_s == NULL) {
+               wpa_printf(MSG_ERROR, "P2P: Failed to create new "
+                          "wpa_supplicant interface");
+               return NULL;
+       }
+       wpa_s->pending_interface_name[0] = '\0';
+       group_wpa_s->parent = wpa_s;
+       group_wpa_s->p2p_group_interface = go ? P2P_GROUP_INTERFACE_GO :
+               P2P_GROUP_INTERFACE_CLIENT;
+       wpa_s->global->p2p_group_formation = group_wpa_s;
+
+       wpas_p2p_clone_config(group_wpa_s, wpa_s);
+
+       return group_wpa_s;
+}
+
+
+static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
+                                            void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       wpa_printf(MSG_DEBUG, "P2P: Group Formation timed out");
+       if (wpa_s->global->p2p)
+               p2p_group_formation_failed(wpa_s->global->p2p);
+       else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               wpa_drv_p2p_group_formation_failed(wpa_s);
+       wpas_group_formation_completed(wpa_s, 0);
+}
+
+
+void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
+               wpa_drv_cancel_remain_on_channel(wpa_s);
+               wpa_s->off_channel_freq = 0;
+               wpa_s->roc_waiting_drv_freq = 0;
+       }
+
+       if (res->status) {
+               wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_FAILURE "status=%d",
+                       res->status);
+               wpas_notify_p2p_go_neg_completed(wpa_s, res);
+               wpas_p2p_remove_pending_group_interface(wpa_s);
+               return;
+       }
+
+       wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS);
+       wpas_notify_p2p_go_neg_completed(wpa_s, res);
+
+       if (wpa_s->create_p2p_iface) {
+               struct wpa_supplicant *group_wpa_s =
+                       wpas_p2p_init_group_interface(wpa_s, res->role_go);
+               if (group_wpa_s == NULL) {
+                       wpas_p2p_remove_pending_group_interface(wpa_s);
+                       return;
+               }
+               if (group_wpa_s != wpa_s) {
+                       os_memcpy(group_wpa_s->p2p_pin, wpa_s->p2p_pin,
+                                 sizeof(group_wpa_s->p2p_pin));
+                       group_wpa_s->p2p_wps_method = wpa_s->p2p_wps_method;
+               }
+               os_memset(wpa_s->pending_interface_addr, 0, ETH_ALEN);
+               wpa_s->pending_interface_name[0] = '\0';
+               group_wpa_s->p2p_in_provisioning = 1;
+
+               if (res->role_go)
+                       wpas_start_wps_go(group_wpa_s, res, 1);
+               else
+                       wpas_start_wps_enrollee(group_wpa_s, res);
+       } else {
+               wpa_s->p2p_in_provisioning = 1;
+               wpa_s->global->p2p_group_formation = wpa_s;
+
+               if (res->role_go)
+                       wpas_start_wps_go(wpa_s, res, 1);
+               else
+                       wpas_start_wps_enrollee(ctx, res);
+       }
+
+       wpa_s->p2p_long_listen = 0;
+       eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
+
+       eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
+       eloop_register_timeout(15 + res->peer_config_timeout / 100,
+                              (res->peer_config_timeout % 100) * 10000,
+                              wpas_p2p_group_formation_timeout, wpa_s, NULL);
+}
+
+
+void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_REQUEST MACSTR
+               " dev_passwd_id=%u", MAC2STR(src), dev_passwd_id);
+
+       wpas_notify_p2p_go_neg_req(wpa_s, src, dev_passwd_id);
+}
+
+
+void wpas_dev_found(void *ctx, const u8 *addr,
+                   const struct p2p_peer_info *info,
+                   int new_device)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+       struct wpa_supplicant *wpa_s = ctx;
+       char devtype[WPS_DEV_TYPE_BUFSIZE];
+
+       wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
+               " p2p_dev_addr=" MACSTR
+               " pri_dev_type=%s name='%s' config_methods=0x%x "
+               "dev_capab=0x%x group_capab=0x%x",
+               MAC2STR(addr), MAC2STR(info->p2p_device_addr),
+               wps_dev_type_bin2str(info->pri_dev_type, devtype,
+                                    sizeof(devtype)),
+               info->device_name, info->config_methods,
+               info->dev_capab, info->group_capab);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+       wpas_notify_p2p_device_found(ctx, info->p2p_device_addr, new_device);
+}
+
+
+static void wpas_dev_lost(void *ctx, const u8 *dev_addr)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_LOST
+               "p2p_dev_addr=" MACSTR, MAC2STR(dev_addr));
+
+       wpas_notify_p2p_device_lost(wpa_s, dev_addr);
+}
+
+
+static int wpas_start_listen(void *ctx, unsigned int freq,
+                            unsigned int duration,
+                            const struct wpabuf *probe_resp_ie)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       wpa_drv_set_ap_wps_ie(wpa_s, NULL, probe_resp_ie, NULL);
+
+       if (wpa_drv_probe_req_report(wpa_s, 1) < 0) {
+               wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver to "
+                          "report received Probe Request frames");
+               return -1;
+       }
+
+       wpa_s->pending_listen_freq = freq;
+       wpa_s->pending_listen_duration = duration;
+
+       if (wpa_drv_remain_on_channel(wpa_s, freq, duration) < 0) {
+               wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver "
+                          "to remain on channel (%u MHz) for Listen "
+                          "state", freq);
+               wpa_s->pending_listen_freq = 0;
+               return -1;
+       }
+       wpa_s->off_channel_freq = 0;
+       wpa_s->roc_waiting_drv_freq = freq;
+
+       return 0;
+}
+
+
+static void wpas_stop_listen(void *ctx)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
+               wpa_drv_cancel_remain_on_channel(wpa_s);
+               wpa_s->off_channel_freq = 0;
+               wpa_s->roc_waiting_drv_freq = 0;
+       }
+       wpa_drv_set_ap_wps_ie(wpa_s, NULL, NULL, NULL);
+       wpa_drv_probe_req_report(wpa_s, 0);
+}
+
+
+static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1);
+}
+
+
+static struct p2p_srv_bonjour *
+wpas_p2p_service_get_bonjour(struct wpa_supplicant *wpa_s,
+                            const struct wpabuf *query)
+{
+       struct p2p_srv_bonjour *bsrv;
+       size_t len;
+
+       len = wpabuf_len(query);
+       dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
+                        struct p2p_srv_bonjour, list) {
+               if (len == wpabuf_len(bsrv->query) &&
+                   os_memcmp(wpabuf_head(query), wpabuf_head(bsrv->query),
+                             len) == 0)
+                       return bsrv;
+       }
+       return NULL;
+}
+
+
+static struct p2p_srv_upnp *
+wpas_p2p_service_get_upnp(struct wpa_supplicant *wpa_s, u8 version,
+                         const char *service)
+{
+       struct p2p_srv_upnp *usrv;
+
+       dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp,
+                        struct p2p_srv_upnp, list) {
+               if (version == usrv->version &&
+                   os_strcmp(service, usrv->service) == 0)
+                       return usrv;
+       }
+       return NULL;
+}
+
+
+static void wpas_sd_add_proto_not_avail(struct wpabuf *resp, u8 srv_proto,
+                                       u8 srv_trans_id)
+{
+       u8 *len_pos;
+
+       if (wpabuf_tailroom(resp) < 5)
+               return;
+
+       /* Length (to be filled) */
+       len_pos = wpabuf_put(resp, 2);
+       wpabuf_put_u8(resp, srv_proto);
+       wpabuf_put_u8(resp, srv_trans_id);
+       /* Status Code */
+       wpabuf_put_u8(resp, P2P_SD_PROTO_NOT_AVAILABLE);
+       /* Response Data: empty */
+       WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+}
+
+
+static void wpas_sd_all_bonjour(struct wpa_supplicant *wpa_s,
+                               struct wpabuf *resp, u8 srv_trans_id)
+{
+       struct p2p_srv_bonjour *bsrv;
+       u8 *len_pos;
+
+       wpa_printf(MSG_DEBUG, "P2P: SD Request for all Bonjour services");
+
+       if (dl_list_empty(&wpa_s->global->p2p_srv_bonjour)) {
+               wpa_printf(MSG_DEBUG, "P2P: Bonjour protocol not available");
+               return;
+       }
+
+       dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
+                        struct p2p_srv_bonjour, list) {
+               if (wpabuf_tailroom(resp) <
+                   5 + wpabuf_len(bsrv->query) + wpabuf_len(bsrv->resp))
+                       return;
+               /* Length (to be filled) */
+               len_pos = wpabuf_put(resp, 2);
+               wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
+               wpabuf_put_u8(resp, srv_trans_id);
+               /* Status Code */
+               wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+               wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
+                                 wpabuf_head(bsrv->resp),
+                                 wpabuf_len(bsrv->resp));
+               /* Response Data */
+               wpabuf_put_buf(resp, bsrv->query); /* Key */
+               wpabuf_put_buf(resp, bsrv->resp); /* Value */
+               WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
+                            2);
+       }
+}
+
+
+static 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;
+
+       wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for Bonjour",
+                         query, query_len);
+       if (dl_list_empty(&wpa_s->global->p2p_srv_bonjour)) {
+               wpa_printf(MSG_DEBUG, "P2P: Bonjour protocol not available");
+               wpas_sd_add_proto_not_avail(resp, P2P_SERV_BONJOUR,
+                                           srv_trans_id);
+               return;
+       }
+
+       if (query_len == 0) {
+               wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id);
+               return;
+       }
+
+       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);
+
+       wpabuf_set(&buf, query, query_len);
+       bsrv = wpas_p2p_service_get_bonjour(wpa_s, &buf);
+       if (bsrv == NULL) {
+               wpa_printf(MSG_DEBUG, "P2P: Requested Bonjour service not "
+                          "available");
+
+               /* Status Code */
+               wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
+               /* Response Data: empty */
+               WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
+                            2);
+               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);
+}
+
+
+static void wpas_sd_all_upnp(struct wpa_supplicant *wpa_s,
+                            struct wpabuf *resp, u8 srv_trans_id)
+{
+       struct p2p_srv_upnp *usrv;
+       u8 *len_pos;
+
+       wpa_printf(MSG_DEBUG, "P2P: SD Request for all UPnP services");
+
+       if (dl_list_empty(&wpa_s->global->p2p_srv_upnp)) {
+               wpa_printf(MSG_DEBUG, "P2P: UPnP protocol not available");
+               return;
+       }
+
+       dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp,
+                        struct p2p_srv_upnp, list) {
+               if (wpabuf_tailroom(resp) < 5 + 1 + os_strlen(usrv->service))
+                       return;
+
+               /* Length (to be filled) */
+               len_pos = wpabuf_put(resp, 2);
+               wpabuf_put_u8(resp, P2P_SERV_UPNP);
+               wpabuf_put_u8(resp, srv_trans_id);
+
+               /* Status Code */
+               wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+               /* Response Data */
+               wpabuf_put_u8(resp, usrv->version);
+               wpa_printf(MSG_DEBUG, "P2P: Matching UPnP Service: %s",
+                          usrv->service);
+               wpabuf_put_str(resp, usrv->service);
+               WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
+                            2);
+       }
+}
+
+
+static void wpas_sd_req_upnp(struct wpa_supplicant *wpa_s,
+                            struct wpabuf *resp, u8 srv_trans_id,
+                            const u8 *query, size_t query_len)
+{
+       struct p2p_srv_upnp *usrv;
+       u8 *len_pos;
+       u8 version;
+       char *str;
+       int count = 0;
+
+       wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for UPnP",
+                         query, query_len);
+
+       if (dl_list_empty(&wpa_s->global->p2p_srv_upnp)) {
+               wpa_printf(MSG_DEBUG, "P2P: UPnP protocol not available");
+               wpas_sd_add_proto_not_avail(resp, P2P_SERV_UPNP,
+                                           srv_trans_id);
+               return;
+       }
+
+       if (query_len == 0) {
+               wpas_sd_all_upnp(wpa_s, resp, srv_trans_id);
+               return;
+       }
+
+       if (wpabuf_tailroom(resp) < 5)
+               return;
+
+       /* Length (to be filled) */
+       len_pos = wpabuf_put(resp, 2);
+       wpabuf_put_u8(resp, P2P_SERV_UPNP);
+       wpabuf_put_u8(resp, srv_trans_id);
+
+       version = query[0];
+       str = os_malloc(query_len);
+       if (str == NULL)
+               return;
+       os_memcpy(str, query + 1, query_len - 1);
+       str[query_len - 1] = '\0';
+
+       dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp,
+                        struct p2p_srv_upnp, list) {
+               if (version != usrv->version)
+                       continue;
+
+               if (os_strcmp(str, "ssdp:all") != 0 &&
+                   os_strstr(usrv->service, str) == NULL)
+                       continue;
+
+               if (wpabuf_tailroom(resp) < 2)
+                       break;
+               if (count == 0) {
+                       /* Status Code */
+                       wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+                       /* Response Data */
+                       wpabuf_put_u8(resp, version);
+               } else
+                       wpabuf_put_u8(resp, ',');
+
+               count++;
+
+               wpa_printf(MSG_DEBUG, "P2P: Matching UPnP Service: %s",
+                          usrv->service);
+               if (wpabuf_tailroom(resp) < os_strlen(usrv->service))
+                       break;
+               wpabuf_put_str(resp, usrv->service);
+       }
+       os_free(str);
+
+       if (count == 0) {
+               wpa_printf(MSG_DEBUG, "P2P: Requested UPnP service not "
+                          "available");
+               /* Status Code */
+               wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
+               /* Response Data: empty */
+       }
+
+       WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+}
+
+
+void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
+                    u16 update_indic, const u8 *tlvs, size_t tlvs_len)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       const u8 *pos = tlvs;
+       const u8 *end = tlvs + tlvs_len;
+       const u8 *tlv_end;
+       u16 slen;
+       struct wpabuf *resp;
+       u8 srv_proto, srv_trans_id;
+       size_t buf_len;
+       char *buf;
+
+       wpa_hexdump(MSG_MSGDUMP, "P2P: Service Discovery Request TLVs",
+                   tlvs, tlvs_len);
+       buf_len = 2 * tlvs_len + 1;
+       buf = os_malloc(buf_len);
+       if (buf) {
+               wpa_snprintf_hex(buf, buf_len, tlvs, tlvs_len);
+               wpa_msg_ctrl(wpa_s, MSG_INFO, P2P_EVENT_SERV_DISC_REQ "%d "
+                            MACSTR " %u %u %s",
+                            freq, MAC2STR(sa), dialog_token, update_indic,
+                            buf);
+               os_free(buf);
+       }
+
+       if (wpa_s->p2p_sd_over_ctrl_iface)
+               return; /* to be processed by an external program */
+
+       resp = wpabuf_alloc(10000);
+       if (resp == NULL)
+               return;
+
+       while (pos + 1 < end) {
+               wpa_printf(MSG_DEBUG, "P2P: Service Request TLV");
+               slen = WPA_GET_LE16(pos);
+               pos += 2;
+               if (pos + slen > end || slen < 2) {
+                       wpa_printf(MSG_DEBUG, "P2P: Unexpected Query Data "
+                                  "length");
+                       wpabuf_free(resp);
+                       return;
+               }
+               tlv_end = pos + slen;
+
+               srv_proto = *pos++;
+               wpa_printf(MSG_DEBUG, "P2P: Service Protocol Type %u",
+                          srv_proto);
+               srv_trans_id = *pos++;
+               wpa_printf(MSG_DEBUG, "P2P: Service Transaction ID %u",
+                          srv_trans_id);
+
+               wpa_hexdump(MSG_MSGDUMP, "P2P: Query Data",
+                           pos, tlv_end - pos);
+
+
+               if (wpa_s->force_long_sd) {
+                       wpa_printf(MSG_DEBUG, "P2P: SD test - force long "
+                                  "response");
+                       wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id);
+                       wpas_sd_all_upnp(wpa_s, resp, srv_trans_id);
+                       goto done;
+               }
+
+               switch (srv_proto) {
+               case P2P_SERV_ALL_SERVICES:
+                       wpa_printf(MSG_DEBUG, "P2P: Service Discovery Request "
+                                  "for all services");
+                       if (dl_list_empty(&wpa_s->global->p2p_srv_upnp) &&
+                           dl_list_empty(&wpa_s->global->p2p_srv_bonjour)) {
+                               wpa_printf(MSG_DEBUG, "P2P: No service "
+                                          "discovery protocols available");
+                               wpas_sd_add_proto_not_avail(
+                                       resp, P2P_SERV_ALL_SERVICES,
+                                       srv_trans_id);
+                               break;
+                       }
+                       wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id);
+                       wpas_sd_all_upnp(wpa_s, resp, srv_trans_id);
+                       break;
+               case P2P_SERV_BONJOUR:
+                       wpas_sd_req_bonjour(wpa_s, resp, srv_trans_id,
+                                           pos, tlv_end - pos);
+                       break;
+               case P2P_SERV_UPNP:
+                       wpas_sd_req_upnp(wpa_s, resp, srv_trans_id,
+                                        pos, tlv_end - pos);
+                       break;
+               default:
+                       wpa_printf(MSG_DEBUG, "P2P: Unavailable service "
+                                  "protocol %u", srv_proto);
+                       wpas_sd_add_proto_not_avail(resp, srv_proto,
+                                                   srv_trans_id);
+                       break;
+               }
+
+               pos = tlv_end;
+       }
+
+done:
+       wpas_notify_p2p_sd_request(wpa_s, freq, sa, dialog_token,
+                                  update_indic, tlvs, tlvs_len);
+
+       wpas_p2p_sd_response(wpa_s, freq, sa, dialog_token, resp);
+
+       wpabuf_free(resp);
+}
+
+
+void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
+                     const u8 *tlvs, size_t tlvs_len)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       const u8 *pos = tlvs;
+       const u8 *end = tlvs + tlvs_len;
+       const u8 *tlv_end;
+       u16 slen;
+       size_t buf_len;
+       char *buf;
+
+       wpa_hexdump(MSG_MSGDUMP, "P2P: Service Discovery Response TLVs",
+                   tlvs, tlvs_len);
+       if (tlvs_len > 1500) {
+               /* TODO: better way for handling this */
+               wpa_msg_ctrl(wpa_s, MSG_INFO,
+                            P2P_EVENT_SERV_DISC_RESP MACSTR
+                            " %u <long response: %u bytes>",
+                            MAC2STR(sa), update_indic,
+                            (unsigned int) tlvs_len);
+       } else {
+               buf_len = 2 * tlvs_len + 1;
+               buf = os_malloc(buf_len);
+               if (buf) {
+                       wpa_snprintf_hex(buf, buf_len, tlvs, tlvs_len);
+                       wpa_msg_ctrl(wpa_s, MSG_INFO,
+                                    P2P_EVENT_SERV_DISC_RESP MACSTR " %u %s",
+                                    MAC2STR(sa), update_indic, buf);
+                       os_free(buf);
+               }
+       }
+
+       while (pos < end) {
+               u8 srv_proto, srv_trans_id, status;
+
+               wpa_printf(MSG_DEBUG, "P2P: Service Response TLV");
+               slen = WPA_GET_LE16(pos);
+               pos += 2;
+               if (pos + slen > end || slen < 3) {
+                       wpa_printf(MSG_DEBUG, "P2P: Unexpected Response Data "
+                                  "length");
+                       return;
+               }
+               tlv_end = pos + slen;
+
+               srv_proto = *pos++;
+               wpa_printf(MSG_DEBUG, "P2P: Service Protocol Type %u",
+                          srv_proto);
+               srv_trans_id = *pos++;
+               wpa_printf(MSG_DEBUG, "P2P: Service Transaction ID %u",
+                          srv_trans_id);
+               status = *pos++;
+               wpa_printf(MSG_DEBUG, "P2P: Status Code ID %u",
+                          status);
+
+               wpa_hexdump(MSG_MSGDUMP, "P2P: Response Data",
+                           pos, tlv_end - pos);
+
+               pos = tlv_end;
+       }
+
+       wpas_notify_p2p_sd_response(wpa_s, sa, update_indic, tlvs, tlvs_len);
+}
+
+
+u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+                       const struct wpabuf *tlvs)
+{
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return wpa_drv_p2p_sd_request(wpa_s, dst, tlvs);
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return 0;
+       return (uintptr_t) p2p_sd_request(wpa_s->global->p2p, dst, tlvs);
+}
+
+
+u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
+                            u8 version, const char *query)
+{
+       struct wpabuf *tlvs;
+       u64 ret;
+
+       tlvs = wpabuf_alloc(2 + 1 + 1 + 1 + os_strlen(query));
+       if (tlvs == NULL)
+               return 0;
+       wpabuf_put_le16(tlvs, 1 + 1 + 1 + os_strlen(query));
+       wpabuf_put_u8(tlvs, P2P_SERV_UPNP); /* Service Protocol Type */
+       wpabuf_put_u8(tlvs, 1); /* Service Transaction ID */
+       wpabuf_put_u8(tlvs, version);
+       wpabuf_put_str(tlvs, query);
+       ret = wpas_p2p_sd_request(wpa_s, dst, tlvs);
+       wpabuf_free(tlvs);
+       return ret;
+}
+
+
+int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req)
+{
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return wpa_drv_p2p_sd_cancel_request(wpa_s, req);
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+       return p2p_sd_cancel_request(wpa_s->global->p2p,
+                                    (void *) (uintptr_t) req);
+}
+
+
+void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
+                         const u8 *dst, u8 dialog_token,
+                         const struct wpabuf *resp_tlvs)
+{
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
+               wpa_drv_p2p_sd_response(wpa_s, freq, dst, dialog_token,
+                                       resp_tlvs);
+               return;
+       }
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return;
+       p2p_sd_response(wpa_s->global->p2p, freq, dst, dialog_token,
+                       resp_tlvs);
+}
+
+
+void wpas_p2p_sd_service_update(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
+               wpa_drv_p2p_service_update(wpa_s);
+               return;
+       }
+       if (wpa_s->global->p2p)
+               p2p_sd_service_update(wpa_s->global->p2p);
+}
+
+
+static void wpas_p2p_srv_bonjour_free(struct p2p_srv_bonjour *bsrv)
+{
+       dl_list_del(&bsrv->list);
+       wpabuf_free(bsrv->query);
+       wpabuf_free(bsrv->resp);
+       os_free(bsrv);
+}
+
+
+static void wpas_p2p_srv_upnp_free(struct p2p_srv_upnp *usrv)
+{
+       dl_list_del(&usrv->list);
+       os_free(usrv->service);
+       os_free(usrv);
+}
+
+
+void wpas_p2p_service_flush(struct wpa_supplicant *wpa_s)
+{
+       struct p2p_srv_bonjour *bsrv, *bn;
+       struct p2p_srv_upnp *usrv, *un;
+
+       dl_list_for_each_safe(bsrv, bn, &wpa_s->global->p2p_srv_bonjour,
+                             struct p2p_srv_bonjour, list)
+               wpas_p2p_srv_bonjour_free(bsrv);
+
+       dl_list_for_each_safe(usrv, un, &wpa_s->global->p2p_srv_upnp,
+                             struct p2p_srv_upnp, list)
+               wpas_p2p_srv_upnp_free(usrv);
+
+       wpas_p2p_sd_service_update(wpa_s);
+}
+
+
+int wpas_p2p_service_add_bonjour(struct wpa_supplicant *wpa_s,
+                                struct wpabuf *query, struct wpabuf *resp)
+{
+       struct p2p_srv_bonjour *bsrv;
+
+       bsrv = 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;
+       bsrv->query = query;
+       bsrv->resp = resp;
+       dl_list_add(&wpa_s->global->p2p_srv_bonjour, &bsrv->list);
+
+       wpas_p2p_sd_service_update(wpa_s);
+       return 0;
+}
+
+
+int wpas_p2p_service_del_bonjour(struct wpa_supplicant *wpa_s,
+                                const struct wpabuf *query)
+{
+       struct p2p_srv_bonjour *bsrv;
+
+       bsrv = wpas_p2p_service_get_bonjour(wpa_s, query);
+       if (bsrv == NULL)
+               return -1;
+       wpas_p2p_srv_bonjour_free(bsrv);
+       wpas_p2p_sd_service_update(wpa_s);
+       return 0;
+}
+
+
+int wpas_p2p_service_add_upnp(struct wpa_supplicant *wpa_s, u8 version,
+                             const char *service)
+{
+       struct p2p_srv_upnp *usrv;
+
+       if (wpas_p2p_service_get_upnp(wpa_s, version, service))
+               return 0; /* Already listed */
+       usrv = os_zalloc(sizeof(*usrv));
+       if (usrv == NULL)
+               return -1;
+       usrv->version = version;
+       usrv->service = os_strdup(service);
+       if (usrv->service == NULL) {
+               os_free(usrv);
+               return -1;
+       }
+       dl_list_add(&wpa_s->global->p2p_srv_upnp, &usrv->list);
+
+       wpas_p2p_sd_service_update(wpa_s);
+       return 0;
+}
+
+
+int wpas_p2p_service_del_upnp(struct wpa_supplicant *wpa_s, u8 version,
+                             const char *service)
+{
+       struct p2p_srv_upnp *usrv;
+
+       usrv = wpas_p2p_service_get_upnp(wpa_s, version, service);
+       if (usrv == NULL)
+               return -1;
+       wpas_p2p_srv_upnp_free(usrv);
+       wpas_p2p_sd_service_update(wpa_s);
+       return 0;
+}
+
+
+static void wpas_prov_disc_local_display(struct wpa_supplicant *wpa_s,
+                                        const u8 *peer, const char *params,
+                                        unsigned int generated_pin)
+{
+       wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_SHOW_PIN MACSTR " %08d%s",
+               MAC2STR(peer), generated_pin, params);
+}
+
+
+static void wpas_prov_disc_local_keypad(struct wpa_supplicant *wpa_s,
+                                       const u8 *peer, const char *params)
+{
+       wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_ENTER_PIN MACSTR "%s",
+               MAC2STR(peer), params);
+}
+
+
+void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
+                       const u8 *dev_addr, const u8 *pri_dev_type,
+                       const char *dev_name, u16 supp_config_methods,
+                       u8 dev_capab, u8 group_capab, const u8 *group_id,
+                       size_t group_id_len)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       char devtype[WPS_DEV_TYPE_BUFSIZE];
+       char params[300];
+       u8 empty_dev_type[8];
+       unsigned int generated_pin = 0;
+       struct wpa_supplicant *group = NULL;
+
+       if (group_id) {
+               for (group = wpa_s->global->ifaces; group; group = group->next)
+               {
+                       struct wpa_ssid *s = group->current_ssid;
+                       if (s != NULL &&
+                           s->mode == WPAS_MODE_P2P_GO &&
+                           group_id_len - ETH_ALEN == s->ssid_len &&
+                           os_memcmp(group_id + ETH_ALEN, s->ssid,
+                                     s->ssid_len) == 0)
+                               break;
+               }
+       }
+
+       if (pri_dev_type == NULL) {
+               os_memset(empty_dev_type, 0, sizeof(empty_dev_type));
+               pri_dev_type = empty_dev_type;
+       }
+       os_snprintf(params, sizeof(params), " p2p_dev_addr=" MACSTR
+                   " pri_dev_type=%s name='%s' config_methods=0x%x "
+                   "dev_capab=0x%x group_capab=0x%x%s%s",
+                   MAC2STR(dev_addr),
+                   wps_dev_type_bin2str(pri_dev_type, devtype,
+                                        sizeof(devtype)),
+                   dev_name, supp_config_methods, dev_capab, group_capab,
+                   group ? " group=" : "",
+                   group ? group->ifname : "");
+       params[sizeof(params) - 1] = '\0';
+
+       if (config_methods & WPS_CONFIG_DISPLAY) {
+               generated_pin = wps_generate_pin();
+               wpas_prov_disc_local_display(wpa_s, peer, params,
+                                            generated_pin);
+       } else if (config_methods & WPS_CONFIG_KEYPAD)
+               wpas_prov_disc_local_keypad(wpa_s, peer, params);
+       else if (config_methods & WPS_CONFIG_PUSHBUTTON)
+               wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_REQ MACSTR
+                       "%s", MAC2STR(peer), params);
+
+       wpas_notify_p2p_provision_discovery(wpa_s, peer, 1 /* request */,
+                                           P2P_PROV_DISC_SUCCESS,
+                                           config_methods, generated_pin);
+}
+
+
+void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       unsigned int generated_pin = 0;
+
+       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);
+
+       if (wpa_s->pending_pd_before_join &&
+           (os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
+            os_memcmp(peer, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
+               wpa_s->pending_pd_before_join = 0;
+               wpa_printf(MSG_DEBUG, "P2P: Starting pending "
+                          "join-existing-group operation");
+               wpas_p2p_join_start(wpa_s);
+       }
+}
+
+
+static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
+                               enum p2p_prov_disc_status status)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
+                                           status, 0, 0);
+}
+
+
+static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
+                                 const u8 *go_dev_addr, const u8 *ssid,
+                                 size_t ssid_len, int *go, u8 *group_bssid,
+                                 int *force_freq, int persistent_group)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       struct wpa_ssid *s;
+       u8 cur_bssid[ETH_ALEN];
+       int res;
+       struct wpa_supplicant *grp;
+
+       if (!persistent_group) {
+               wpa_printf(MSG_DEBUG, "P2P: Invitation from " MACSTR
+                          " to join an active group", MAC2STR(sa));
+               if (!is_zero_ether_addr(wpa_s->p2p_auth_invite) &&
+                   (os_memcmp(go_dev_addr, wpa_s->p2p_auth_invite, ETH_ALEN)
+                    == 0 ||
+                    os_memcmp(sa, wpa_s->p2p_auth_invite, ETH_ALEN) == 0)) {
+                       wpa_printf(MSG_DEBUG, "P2P: Accept previously "
+                                  "authorized invitation");
+                       goto accept_inv;
+               }
+               /*
+                * Do not accept the invitation automatically; notify user and
+                * request approval.
+                */
+               return P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
+       }
+
+       grp = wpas_get_p2p_group(wpa_s, ssid, ssid_len, go);
+       if (grp) {
+               wpa_printf(MSG_DEBUG, "P2P: Accept invitation to already "
+                          "running persistent group");
+               if (*go)
+                       os_memcpy(group_bssid, grp->own_addr, ETH_ALEN);
+               goto accept_inv;
+       }
+
+       if (!wpa_s->conf->persistent_reconnect)
+               return P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
+
+       for (s = wpa_s->conf->ssid; s; s = s->next) {
+               if (s->disabled == 2 &&
+                   os_memcmp(s->bssid, go_dev_addr, ETH_ALEN) == 0 &&
+                   s->ssid_len == ssid_len &&
+                   os_memcmp(ssid, s->ssid, ssid_len) == 0)
+                       break;
+       }
+
+       if (!s) {
+               wpa_printf(MSG_DEBUG, "P2P: Invitation from " MACSTR
+                          " requested reinvocation of an unknown group",
+                          MAC2STR(sa));
+               return P2P_SC_FAIL_UNKNOWN_GROUP;
+       }
+
+       if (s->mode == WPAS_MODE_P2P_GO && !wpas_p2p_create_iface(wpa_s)) {
+               *go = 1;
+               if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+                       wpa_printf(MSG_DEBUG, "P2P: The only available "
+                                  "interface is already in use - reject "
+                                  "invitation");
+                       return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
+               }
+               os_memcpy(group_bssid, wpa_s->own_addr, ETH_ALEN);
+       } else if (s->mode == WPAS_MODE_P2P_GO) {
+               *go = 1;
+               if (wpas_p2p_add_group_interface(wpa_s, WPA_IF_P2P_GO) < 0)
+               {
+                       wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new "
+                                  "interface address for the group");
+                       return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
+               }
+               os_memcpy(group_bssid, wpa_s->pending_interface_addr,
+                         ETH_ALEN);
+       }
+
+accept_inv:
+       if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, cur_bssid) == 0 &&
+           wpa_s->assoc_freq) {
+               wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match "
+                          "the channel we are already using");
+               *force_freq = wpa_s->assoc_freq;
+       }
+
+       res = wpa_drv_shared_freq(wpa_s);
+       if (res > 0) {
+               wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match "
+                          "with the channel we are already using on a "
+                          "shared interface");
+               *force_freq = res;
+       }
+
+       return P2P_SC_SUCCESS;
+}
+
+
+static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
+                                    const u8 *ssid, size_t ssid_len,
+                                    const u8 *go_dev_addr, u8 status,
+                                    int op_freq)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       struct wpa_ssid *s;
+
+       for (s = wpa_s->conf->ssid; s; s = s->next) {
+               if (s->disabled == 2 &&
+                   s->ssid_len == ssid_len &&
+                   os_memcmp(ssid, s->ssid, ssid_len) == 0)
+                       break;
+       }
+
+       if (status == P2P_SC_SUCCESS) {
+               wpa_printf(MSG_DEBUG, "P2P: Invitation from peer " MACSTR
+                          " was accepted; op_freq=%d MHz",
+                          MAC2STR(sa), op_freq);
+               if (s) {
+                       wpas_p2p_group_add_persistent(
+                               wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0);
+               } else if (bssid) {
+                       wpas_p2p_join(wpa_s, bssid, go_dev_addr,
+                                     wpa_s->p2p_wps_method);
+               }
+               return;
+       }
+
+       if (status != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
+               wpa_printf(MSG_DEBUG, "P2P: Invitation from peer " MACSTR
+                          " was rejected (status %u)", MAC2STR(sa), status);
+               return;
+       }
+
+       if (!s) {
+               if (bssid) {
+                       wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED
+                               "sa=" MACSTR " go_dev_addr=" MACSTR
+                               " bssid=" MACSTR " unknown-network",
+                               MAC2STR(sa), MAC2STR(go_dev_addr),
+                               MAC2STR(bssid));
+               } else {
+                       wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED
+                               "sa=" MACSTR " go_dev_addr=" MACSTR
+                               " unknown-network",
+                               MAC2STR(sa), MAC2STR(go_dev_addr));
+               }
+               return;
+       }
+
+       wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED "sa=" MACSTR
+               " persistent=%d", MAC2STR(sa), s->id);
+}
+
+
+static void wpas_invitation_result(void *ctx, int status, const u8 *bssid)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       struct wpa_ssid *ssid;
+
+       if (bssid) {
+               wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
+                       "status=%d " MACSTR,
+                       status, MAC2STR(bssid));
+       } else {
+               wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
+                       "status=%d ", status);
+       }
+       wpas_notify_p2p_invitation_result(wpa_s, status, bssid);
+
+       if (wpa_s->pending_invite_ssid_id == -1)
+               return; /* Invitation to active group */
+
+       if (status != P2P_SC_SUCCESS) {
+               wpas_p2p_remove_pending_group_interface(wpa_s);
+               return;
+       }
+
+       ssid = wpa_config_get_network(wpa_s->conf,
+                                     wpa_s->pending_invite_ssid_id);
+       if (ssid == NULL) {
+               wpa_printf(MSG_ERROR, "P2P: Could not find persistent group "
+                          "data matching with invitation");
+               return;
+       }
+
+       wpas_p2p_group_add_persistent(wpa_s, ssid,
+                                     ssid->mode == WPAS_MODE_P2P_GO, 0);
+}
+
+
+static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
+                                    struct p2p_channels *chan)
+{
+       int i, cla = 0;
+
+       wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for 2.4 GHz "
+                  "band");
+
+       /* Operating class 81 - 2.4 GHz band channels 1..13 */
+       chan->reg_class[cla].reg_class = 81;
+       chan->reg_class[cla].channels = 11;
+       for (i = 0; i < 11; i++)
+               chan->reg_class[cla].channel[i] = i + 1;
+       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++;
+
+       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_classes = cla;
+       return 0;
+}
+
+
+static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
+                                         u16 num_modes,
+                                         enum hostapd_hw_mode mode)
+{
+       u16 i;
+
+       for (i = 0; i < num_modes; i++) {
+               if (modes[i].mode == mode)
+                       return &modes[i];
+       }
+
+       return NULL;
+}
+
+
+static int has_channel(struct hostapd_hw_modes *mode, u8 chan, int *flags)
+{
+       int i;
+
+       for (i = 0; i < mode->num_channels; i++) {
+               if (mode->channels[i].chan == chan) {
+                       if (flags)
+                               *flags = mode->channels[i].flag;
+                       return !(mode->channels[i].flag &
+                                (HOSTAPD_CHAN_DISABLED |
+                                 HOSTAPD_CHAN_PASSIVE_SCAN |
+                                 HOSTAPD_CHAN_NO_IBSS |
+                                 HOSTAPD_CHAN_RADAR));
+               }
+       }
+
+       return 0;
+}
+
+
+struct p2p_oper_class_map {
+       enum hostapd_hw_mode mode;
+       u8 op_class;
+       u8 min_chan;
+       u8 max_chan;
+       u8 inc;
+       enum { BW20, BW40PLUS, BW40MINUS } bw;
+};
+
+static 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 "
+                          "of all supported channels; assume dualband "
+                          "support");
+               return wpas_p2p_default_channels(wpa_s, chan);
+       }
+
+       cla = 0;
+
+       for (op = 0; op_class[op].op_class; op++) {
+               struct p2p_oper_class_map *o = &op_class[op];
+               u8 ch;
+               struct p2p_reg_class *reg = NULL;
+
+               mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
+               if (mode == NULL)
+                       continue;
+               for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
+                       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)))
+                               continue;
+                       if (reg == NULL) {
+                               wpa_printf(MSG_DEBUG, "P2P: Add operating "
+                                          "class %u", o->op_class);
+                               reg = &chan->reg_class[cla];
+                               cla++;
+                               reg->reg_class = o->op_class;
+                       }
+                       reg->channel[reg->channels] = ch;
+                       reg->channels++;
+               }
+               if (reg) {
+                       wpa_hexdump(MSG_DEBUG, "P2P: Channels",
+                                   reg->channel, reg->channels);
+               }
+       }
+
+       chan->reg_classes = cla;
+
+       return 0;
+}
+
+
+static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf,
+                       size_t buf_len)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+               if (os_memcmp(wpa_s->own_addr, interface_addr, ETH_ALEN) == 0)
+                       break;
+       }
+       if (wpa_s == NULL)
+               return -1;
+
+       return wpa_drv_get_noa(wpa_s, buf, buf_len);
+}
+
+
+/**
+ * wpas_p2p_init - Initialize P2P module for %wpa_supplicant
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
+ * Returns: 0 on success, -1 on failure
+ */
+int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
+{
+       struct p2p_config p2p;
+       unsigned int r;
+       int i;
+
+       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
+               return 0;
+
+       if (global->p2p)
+               return 0;
+
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
+               struct p2p_params params;
+
+               wpa_printf(MSG_DEBUG, "P2P: Use driver-based P2P management");
+               os_memset(&params, 0, sizeof(params));
+               params.dev_name = wpa_s->conf->device_name;
+               os_memcpy(params.pri_dev_type, wpa_s->conf->device_type,
+                         WPS_DEV_TYPE_LEN);
+               params.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
+               os_memcpy(params.sec_dev_type,
+                         wpa_s->conf->sec_device_type,
+                         params.num_sec_dev_types * WPS_DEV_TYPE_LEN);
+
+               if (wpa_drv_p2p_set_params(wpa_s, &params) < 0)
+                       return -1;
+
+               return 0;
+       }
+
+       os_memset(&p2p, 0, sizeof(p2p));
+       p2p.msg_ctx = wpa_s;
+       p2p.cb_ctx = wpa_s;
+       p2p.p2p_scan = wpas_p2p_scan;
+       p2p.send_action = wpas_send_action;
+       p2p.send_action_done = wpas_send_action_done;
+       p2p.go_neg_completed = wpas_go_neg_completed;
+       p2p.go_neg_req_rx = wpas_go_neg_req_rx;
+       p2p.dev_found = wpas_dev_found;
+       p2p.dev_lost = wpas_dev_lost;
+       p2p.start_listen = wpas_start_listen;
+       p2p.stop_listen = wpas_stop_listen;
+       p2p.send_probe_resp = wpas_send_probe_resp;
+       p2p.sd_request = wpas_sd_request;
+       p2p.sd_response = wpas_sd_response;
+       p2p.prov_disc_req = wpas_prov_disc_req;
+       p2p.prov_disc_resp = wpas_prov_disc_resp;
+       p2p.prov_disc_fail = wpas_prov_disc_fail;
+       p2p.invitation_process = wpas_invitation_process;
+       p2p.invitation_received = wpas_invitation_received;
+       p2p.invitation_result = wpas_invitation_result;
+       p2p.get_noa = wpas_get_noa;
+
+       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);
+       p2p.dev_name = wpa_s->conf->device_name;
+       p2p.manufacturer = wpa_s->conf->manufacturer;
+       p2p.model_name = wpa_s->conf->model_name;
+       p2p.model_number = wpa_s->conf->model_number;
+       p2p.serial_number = wpa_s->conf->serial_number;
+       if (wpa_s->wps) {
+               os_memcpy(p2p.uuid, wpa_s->wps->uuid, 16);
+               p2p.config_methods = wpa_s->wps->config_methods;
+       }
+
+       if (wpa_s->conf->p2p_listen_reg_class &&
+           wpa_s->conf->p2p_listen_channel) {
+               p2p.reg_class = wpa_s->conf->p2p_listen_reg_class;
+               p2p.channel = wpa_s->conf->p2p_listen_channel;
+       } else {
+               p2p.reg_class = 81;
+               /*
+                * Pick one of the social channels randomly as the listen
+                * channel.
+                */
+               os_get_random((u8 *) &r, sizeof(r));
+               p2p.channel = 1 + (r % 3) * 5;
+       }
+       wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d", p2p.channel);
+
+       if (wpa_s->conf->p2p_oper_reg_class &&
+           wpa_s->conf->p2p_oper_channel) {
+               p2p.op_reg_class = wpa_s->conf->p2p_oper_reg_class;
+               p2p.op_channel = wpa_s->conf->p2p_oper_channel;
+               p2p.cfg_op_channel = 1;
+               wpa_printf(MSG_DEBUG, "P2P: Configured operating channel: "
+                          "%d:%d", p2p.op_reg_class, p2p.op_channel);
+
+       } else {
+               p2p.op_reg_class = 81;
+               /*
+                * Use random operation channel from (1, 6, 11) if no other
+                * preference is indicated.
+                */
+               os_get_random((u8 *) &r, sizeof(r));
+               p2p.op_channel = 1 + (r % 3) * 5;
+               p2p.cfg_op_channel = 0;
+               wpa_printf(MSG_DEBUG, "P2P: Random operating channel: "
+                          "%d:%d", p2p.op_reg_class, p2p.op_channel);
+       }
+       if (wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
+               os_memcpy(p2p.country, wpa_s->conf->country, 2);
+               p2p.country[2] = 0x04;
+       } else
+               os_memcpy(p2p.country, "XX\x04", 3);
+
+       if (wpas_p2p_setup_channels(wpa_s, &p2p.channels)) {
+               wpa_printf(MSG_ERROR, "P2P: Failed to configure supported "
+                          "channel list");
+               return -1;
+       }
+
+       os_memcpy(p2p.pri_dev_type, wpa_s->conf->device_type,
+                 WPS_DEV_TYPE_LEN);
+
+       p2p.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
+       os_memcpy(p2p.sec_dev_type, wpa_s->conf->sec_device_type,
+                 p2p.num_sec_dev_types * WPS_DEV_TYPE_LEN);
+
+       p2p.concurrent_operations = !!(wpa_s->drv_flags &
+                                      WPA_DRIVER_FLAGS_P2P_CONCURRENT);
+
+       p2p.max_peers = 100;
+
+       if (wpa_s->conf->p2p_ssid_postfix) {
+               p2p.ssid_postfix_len =
+                       os_strlen(wpa_s->conf->p2p_ssid_postfix);
+               if (p2p.ssid_postfix_len > sizeof(p2p.ssid_postfix))
+                       p2p.ssid_postfix_len = sizeof(p2p.ssid_postfix);
+               os_memcpy(p2p.ssid_postfix, wpa_s->conf->p2p_ssid_postfix,
+                         p2p.ssid_postfix_len);
+       }
+
+       p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss;
+
+       global->p2p = p2p_init(&p2p);
+       if (global->p2p == NULL)
+               return -1;
+
+       for (i = 0; i < MAX_WPS_VENDOR_EXT; i++) {
+               if (wpa_s->conf->wps_vendor_ext[i] == NULL)
+                       continue;
+               p2p_add_wps_vendor_extension(
+                       global->p2p, wpa_s->conf->wps_vendor_ext[i]);
+       }
+
+       return 0;
+}
+
+
+/**
+ * wpas_p2p_deinit - Deinitialize per-interface P2P data
+ * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
+ *
+ * This function deinitialize per-interface P2P data.
+ */
+void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->driver && wpa_s->drv_priv)
+               wpa_drv_probe_req_report(wpa_s, 0);
+
+       if (wpa_s->go_params) {
+               /* Clear any stored provisioning info */
+               p2p_clear_provisioning_info(
+                       wpa_s->global->p2p,
+                       wpa_s->go_params->peer_interface_addr);
+       }
+
+       os_free(wpa_s->go_params);
+       wpa_s->go_params = NULL;
+       eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
+       eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+       wpa_s->p2p_long_listen = 0;
+       eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
+       eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
+       wpas_p2p_remove_pending_group_interface(wpa_s);
+
+       /* TODO: remove group interface from the driver if this wpa_s instance
+        * is on top of a P2P group interface */
+}
+
+
+/**
+ * wpas_p2p_deinit_global - Deinitialize global P2P module
+ * @global: Pointer to global data from wpa_supplicant_init()
+ *
+ * This function deinitializes the global (per device) P2P module.
+ */
+void wpas_p2p_deinit_global(struct wpa_global *global)
+{
+       struct wpa_supplicant *wpa_s, *tmp;
+       char *ifname;
+
+       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 ||
+                       tmp->p2p_group_interface == NOT_P2P_GROUP_INTERFACE)) {
+                       tmp = tmp->next;
+               }
+               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);
+       }
+
+       /*
+        * Deinit GO data on any possibly remaining interface (if main
+        * interface is used as GO).
+        */
+       for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+               if (wpa_s->ap_iface)
+                       wpas_p2p_group_deinit(wpa_s);
+       }
+
+       p2p_deinit(global->p2p);
+       global->p2p = NULL;
+}
+
+
+static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->drv_flags &
+           (WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE |
+            WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P))
+               return 1; /* P2P group requires a new interface in every case
+                          */
+       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CONCURRENT))
+               return 0; /* driver does not support concurrent operations */
+       if (wpa_s->global->ifaces->next)
+               return 1; /* more that one interface already in use */
+       if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+               return 1; /* this interface is already in use */
+       return 0;
+}
+
+
+static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s,
+                                const u8 *peer_addr,
+                                enum p2p_wps_method wps_method,
+                                int go_intent, const u8 *own_interface_addr,
+                                unsigned int force_freq, int persistent_group)
+{
+       if (persistent_group && wpa_s->conf->persistent_reconnect)
+               persistent_group = 2;
+
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
+               return wpa_drv_p2p_connect(wpa_s, peer_addr, wps_method,
+                                          go_intent, own_interface_addr,
+                                          force_freq, persistent_group);
+       }
+
+       return p2p_connect(wpa_s->global->p2p, peer_addr, wps_method,
+                          go_intent, own_interface_addr, force_freq,
+                          persistent_group);
+}
+
+
+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)
+{
+       if (persistent_group && wpa_s->conf->persistent_reconnect)
+               persistent_group = 2;
+
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return -1;
+
+       return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method,
+                            go_intent, own_interface_addr, force_freq,
+                            persistent_group);
+}
+
+
+static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s)
+{
+       wpa_s->p2p_join_scan_count++;
+       wpa_printf(MSG_DEBUG, "P2P: Join scan attempt %d",
+                  wpa_s->p2p_join_scan_count);
+       if (wpa_s->p2p_join_scan_count > P2P_MAX_JOIN_SCAN_ATTEMPTS) {
+               wpa_printf(MSG_DEBUG, "P2P: Failed to find GO " MACSTR
+                          " for join operationg - stop join attempt",
+                          MAC2STR(wpa_s->pending_join_iface_addr));
+               eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+               wpa_msg(wpa_s->parent, MSG_INFO,
+                       P2P_EVENT_GROUP_FORMATION_FAILURE);
+       }
+}
+
+
+static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
+                                  struct wpa_scan_results *scan_res)
+{
+       struct wpa_bss *bss;
+       int freq;
+       u8 iface_addr[ETH_ALEN];
+
+       eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+
+       if (wpa_s->global->p2p_disabled)
+               return;
+
+       wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS) for join",
+                  scan_res ? (int) scan_res->num : -1);
+
+       if (scan_res)
+               wpas_p2p_scan_res_handler(wpa_s, scan_res);
+
+       freq = p2p_get_oper_freq(wpa_s->global->p2p,
+                                wpa_s->pending_join_iface_addr);
+       if (freq < 0 &&
+           p2p_get_interface_addr(wpa_s->global->p2p,
+                                  wpa_s->pending_join_dev_addr,
+                                  iface_addr) == 0 &&
+           os_memcmp(iface_addr, wpa_s->pending_join_dev_addr, ETH_ALEN) != 0)
+       {
+               wpa_printf(MSG_DEBUG, "P2P: Overwrite pending interface "
+                          "address for join from " MACSTR " to " MACSTR
+                          " based on newly discovered P2P peer entry",
+                          MAC2STR(wpa_s->pending_join_iface_addr),
+                          MAC2STR(iface_addr));
+               os_memcpy(wpa_s->pending_join_iface_addr, iface_addr,
+                         ETH_ALEN);
+
+               freq = p2p_get_oper_freq(wpa_s->global->p2p,
+                                        wpa_s->pending_join_iface_addr);
+       }
+       if (freq >= 0) {
+               wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
+                          "from P2P peer table: %d MHz", freq);
+       }
+       bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr);
+       if (bss) {
+               freq = bss->freq;
+               wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
+                          "from BSS table: %d MHz", freq);
+       }
+       if (freq > 0) {
+               u16 method;
+
+               wpa_printf(MSG_DEBUG, "P2P: Send Provision Discovery Request "
+                          "prior to joining an existing group (GO " MACSTR
+                          " freq=%u MHz)",
+                          MAC2STR(wpa_s->pending_join_dev_addr), freq);
+               wpa_s->pending_pd_before_join = 1;
+
+               switch (wpa_s->pending_join_wps_method) {
+               case WPS_PIN_DISPLAY:
+                       method = WPS_CONFIG_KEYPAD;
+                       break;
+               case WPS_PIN_KEYPAD:
+                       method = WPS_CONFIG_DISPLAY;
+                       break;
+               case WPS_PBC:
+                       method = WPS_CONFIG_PUSHBUTTON;
+                       break;
+               default:
+                       method = 0;
+                       break;
+               }
+
+               if ((p2p_get_provisioning_info(wpa_s->global->p2p,
+                                              wpa_s->pending_join_dev_addr) ==
+                    method)) {
+                       /*
+                        * We have already performed provision discovery for
+                        * joining the group. Proceed directly to join
+                        * operation without duplicated provision discovery. */
+                       wpa_printf(MSG_DEBUG, "P2P: Provision discovery "
+                                  "with " MACSTR " already done - proceed to "
+                                  "join",
+                                  MAC2STR(wpa_s->pending_join_dev_addr));
+                       wpa_s->pending_pd_before_join = 0;
+                       goto start;
+               }
+
+               if (p2p_prov_disc_req(wpa_s->global->p2p,
+                                     wpa_s->pending_join_dev_addr, method, 1,
+                                     freq) < 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;
+       }
+
+       wpa_printf(MSG_DEBUG, "P2P: Failed to find BSS/GO - try again later");
+       eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+       eloop_register_timeout(1, 0, wpas_p2p_join_scan, wpa_s, NULL);
+       wpas_p2p_check_join_scan_limit(wpa_s);
+       return;
+
+start:
+       /* Start join operation immediately */
+       wpas_p2p_join_start(wpa_s);
+}
+
+
+static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       int ret;
+       struct wpa_driver_scan_params params;
+       struct wpabuf *wps_ie, *ies;
+       size_t ielen;
+
+       os_memset(&params, 0, sizeof(params));
+
+       /* P2P Wildcard SSID */
+       params.num_ssids = 1;
+       params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
+       params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+
+       wpa_s->wps->dev.p2p = 1;
+       wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
+                                       WPS_REQ_ENROLLEE, 0, NULL);
+       if (wps_ie == NULL) {
+               wpas_p2p_scan_res_join(wpa_s, NULL);
+               return;
+       }
+
+       ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
+       ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
+       if (ies == NULL) {
+               wpabuf_free(wps_ie);
+               wpas_p2p_scan_res_join(wpa_s, NULL);
+               return;
+       }
+       wpabuf_put_buf(ies, wps_ie);
+       wpabuf_free(wps_ie);
+
+       p2p_scan_ie(wpa_s->global->p2p, ies);
+
+       params.p2p_probe = 1;
+       params.extra_ies = wpabuf_head(ies);
+       params.extra_ies_len = wpabuf_len(ies);
+
+       /*
+        * Run a scan to update BSS table and start Provision Discovery once
+        * the new scan results become available.
+        */
+       wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
+       ret = wpa_drv_scan(wpa_s, &params);
+
+       wpabuf_free(ies);
+
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "P2P: Failed to start scan for join - "
+                          "try again later");
+               eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+               eloop_register_timeout(1, 0, wpas_p2p_join_scan, wpa_s, NULL);
+               wpas_p2p_check_join_scan_limit(wpa_s);
+       }
+}
+
+
+static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
+                        const u8 *dev_addr, enum p2p_wps_method wps_method)
+{
+       wpa_printf(MSG_DEBUG, "P2P: Request to join existing group (iface "
+                  MACSTR " dev " MACSTR ")",
+                  MAC2STR(iface_addr), MAC2STR(dev_addr));
+
+       os_memcpy(wpa_s->pending_join_iface_addr, iface_addr, ETH_ALEN);
+       os_memcpy(wpa_s->pending_join_dev_addr, dev_addr, ETH_ALEN);
+       wpa_s->pending_join_wps_method = wps_method;
+
+       /* Make sure we are not running find during connection establishment */
+       wpas_p2p_stop_find(wpa_s);
+
+       wpa_s->p2p_join_scan_count = 0;
+       wpas_p2p_join_scan(wpa_s, NULL);
+       return 0;
+}
+
+
+static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_supplicant *group;
+       struct p2p_go_neg_results res;
+
+       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;
+
+       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;
+       wpas_start_wps_enrollee(group, &res);
+
+       /*
+        * Allow a longer timeout for join-a-running-group than normal 15
+        * second group formation timeout since the GO may not have authorized
+        * our connection yet.
+        */
+       eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
+       eloop_register_timeout(60, 0, wpas_p2p_group_formation_timeout,
+                              wpa_s, NULL);
+
+       return 0;
+}
+
+
+/**
+ * wpas_p2p_connect - Request P2P Group Formation to be started
+ * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
+ * @peer_addr: Address of the peer P2P Device
+ * @pin: PIN to use during provisioning or %NULL to indicate PBC mode
+ * @persistent_group: Whether to create a persistent group
+ * @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
+ * 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 force_freq = 0, oper_freq = 0;
+       u8 bssid[ETH_ALEN];
+       int ret = 0;
+       enum wpa_driver_if_type iftype;
+       const u8 *if_addr;
+
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+
+       if (go_intent < 0)
+               go_intent = wpa_s->conf->p2p_go_intent;
+
+       if (!auth)
+               wpa_s->p2p_long_listen = 0;
+
+       wpa_s->p2p_wps_method = wps_method;
+
+       if (pin)
+               os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
+       else if (wps_method == WPS_PIN_DISPLAY) {
+               ret = wps_generate_pin();
+               os_snprintf(wpa_s->p2p_pin, sizeof(wpa_s->p2p_pin), "%08d",
+                           ret);
+               wpa_printf(MSG_DEBUG, "P2P: Randomly generated PIN: %s",
+                          wpa_s->p2p_pin);
+       } else
+               wpa_s->p2p_pin[0] = '\0';
+
+       if (join) {
+               u8 iface_addr[ETH_ALEN], dev_addr[ETH_ALEN];
+               if (auth) {
+                       wpa_printf(MSG_DEBUG, "P2P: Authorize invitation to "
+                                  "connect a running group from " MACSTR,
+                                  MAC2STR(peer_addr));
+                       os_memcpy(wpa_s->p2p_auth_invite, peer_addr, ETH_ALEN);
+                       return ret;
+               }
+               os_memcpy(dev_addr, peer_addr, ETH_ALEN);
+               if (p2p_get_interface_addr(wpa_s->global->p2p, peer_addr,
+                                          iface_addr) < 0) {
+                       os_memcpy(iface_addr, peer_addr, ETH_ALEN);
+                       p2p_get_dev_addr(wpa_s->global->p2p, peer_addr,
+                                        dev_addr);
+               }
+               if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method) <
+                   0)
+                       return -1;
+               return ret;
+       }
+
+       if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
+           wpa_s->assoc_freq)
+               oper_freq = wpa_s->assoc_freq;
+       else {
+               oper_freq = wpa_drv_shared_freq(wpa_s);
+               if (oper_freq < 0)
+                       oper_freq = 0;
+       }
+
+       if (freq > 0) {
+               if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+                       wpa_printf(MSG_DEBUG, "P2P: The forced channel "
+                                  "(%u MHz) is not supported for P2P uses",
+                                  freq);
+                       return -3;
+               }
+
+               if (oper_freq > 0 && freq != oper_freq &&
+                   !(wpa_s->drv_flags &
+                     WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+                       wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
+                                  "on %u MHz while connected on another "
+                                  "channel (%u MHz)", freq, oper_freq);
+                       return -2;
+               }
+               wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
+                          "requested channel (%u MHz)", freq);
+               force_freq = freq;
+       } else if (oper_freq > 0 &&
+                  !p2p_supported_freq(wpa_s->global->p2p, oper_freq)) {
+               if (!(wpa_s->drv_flags &
+                     WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+                       wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
+                                  "while connected on non-P2P supported "
+                                  "channel (%u MHz)", oper_freq);
+                       return -2;
+               }
+               wpa_printf(MSG_DEBUG, "P2P: Current operating channel "
+                          "(%u MHz) not available for P2P - try to use "
+                          "another channel", oper_freq);
+               force_freq = 0;
+       } else if (oper_freq > 0) {
+               wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
+                          "channel we are already using (%u MHz) on another "
+                          "interface", oper_freq);
+               force_freq = oper_freq;
+       }
+
+       wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
+
+       if (wpa_s->create_p2p_iface) {
+               /* Prepare to add a new interface for the group */
+               iftype = WPA_IF_P2P_GROUP;
+               if (go_intent == 15)
+                       iftype = WPA_IF_P2P_GO;
+               if (wpas_p2p_add_group_interface(wpa_s, iftype) < 0) {
+                       wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new "
+                                  "interface for the group");
+                       return -1;
+               }
+
+               if_addr = wpa_s->pending_interface_addr;
+       } else
+               if_addr = wpa_s->own_addr;
+
+       if (auth) {
+               if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method,
+                                        go_intent, if_addr,
+                                        force_freq, persistent_group) < 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) {
+               if (wpa_s->create_p2p_iface)
+                       wpas_p2p_remove_pending_group_interface(wpa_s);
+               return -1;
+       }
+       return ret;
+}
+
+
+/**
+ * wpas_p2p_remain_on_channel_cb - Indication of remain-on-channel start
+ * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
+ * @freq: Frequency of the channel in MHz
+ * @duration: Duration of the stay on the channel in milliseconds
+ *
+ * This callback is called when the driver indicates that it has started the
+ * requested remain-on-channel duration.
+ */
+void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+                                  unsigned int freq, unsigned int duration)
+{
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return;
+       if (wpa_s->off_channel_freq == wpa_s->pending_listen_freq) {
+               p2p_listen_cb(wpa_s->global->p2p, wpa_s->pending_listen_freq,
+                             wpa_s->pending_listen_duration);
+               wpa_s->pending_listen_freq = 0;
+       }
+}
+
+
+static int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s,
+                                unsigned int timeout)
+{
+       /* Limit maximum Listen state time based on driver limitation. */
+       if (timeout > wpa_s->max_remain_on_chan)
+               timeout = wpa_s->max_remain_on_chan;
+
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return wpa_drv_p2p_listen(wpa_s, timeout);
+
+       return p2p_listen(wpa_s->global->p2p, timeout);
+}
+
+
+/**
+ * wpas_p2p_cancel_remain_on_channel_cb - Remain-on-channel timeout
+ * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
+ * @freq: Frequency of the channel in MHz
+ *
+ * This callback is called when the driver indicates that a remain-on-channel
+ * operation has been completed, i.e., the duration on the requested channel
+ * has timed out.
+ */
+void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+                                         unsigned int freq)
+{
+       wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
+                  "(p2p_long_listen=%d ms pending_action_tx=%p)",
+                  wpa_s->p2p_long_listen, wpa_s->pending_action_tx);
+       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)
+               return;
+       if (wpa_s->p2p_long_listen > 0)
+               wpa_s->p2p_long_listen -= wpa_s->max_remain_on_chan;
+       if (wpa_s->p2p_long_listen > 0) {
+               wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
+               wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
+       }
+}
+
+
+/**
+ * wpas_p2p_group_remove - Remove a P2P group
+ * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
+ * @ifname: Network interface name of the group interface or "*" to remove all
+ *     groups
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to remove a P2P group. This can be used to disconnect
+ * from a group in which the local end is a P2P Client or to end a P2P Group in
+ * case the local end is the Group Owner. If a virtual network interface was
+ * created for this group, that interface will be removed. Otherwise, only the
+ * configured P2P group network will be removed from the interface.
+ */
+int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
+{
+       struct wpa_global *global = wpa_s->global;
+
+       if (os_strcmp(ifname, "*") == 0) {
+               struct wpa_supplicant *prev;
+               wpa_s = global->ifaces;
+               while (wpa_s) {
+                       prev = wpa_s;
+                       wpa_s = wpa_s->next;
+                       wpas_p2p_disconnect(prev);
+               }
+               return 0;
+       }
+
+       for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+               if (os_strcmp(wpa_s->ifname, ifname) == 0)
+                       break;
+       }
+
+       return wpas_p2p_disconnect(wpa_s);
+}
+
+
+static void wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
+                                   struct p2p_go_neg_results *params,
+                                   int freq)
+{
+       u8 bssid[ETH_ALEN];
+       int res;
+
+       os_memset(params, 0, sizeof(*params));
+       params->role_go = 1;
+       if (freq) {
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on forced "
+                          "frequency %d MHz", freq);
+               params->freq = freq;
+       } else if (wpa_s->conf->p2p_oper_reg_class == 81 &&
+                  wpa_s->conf->p2p_oper_channel >= 1 &&
+                  wpa_s->conf->p2p_oper_channel <= 11) {
+               params->freq = 2407 + 5 * wpa_s->conf->p2p_oper_channel;
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
+                          "frequency %d MHz", params->freq);
+       } else if (wpa_s->conf->p2p_oper_reg_class == 115 ||
+                  wpa_s->conf->p2p_oper_reg_class == 124) {
+               params->freq = 5000 + 5 * wpa_s->conf->p2p_oper_channel;
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
+                          "frequency %d MHz", params->freq);
+       } else if (wpa_s->conf->p2p_oper_channel == 0 &&
+                  wpa_s->best_overall_freq > 0 &&
+                  p2p_supported_freq(wpa_s->global->p2p,
+                                     wpa_s->best_overall_freq)) {
+               params->freq = wpa_s->best_overall_freq;
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best overall "
+                          "channel %d MHz", params->freq);
+       } else if (wpa_s->conf->p2p_oper_channel == 0 &&
+                  wpa_s->best_24_freq > 0 &&
+                  p2p_supported_freq(wpa_s->global->p2p,
+                                     wpa_s->best_24_freq)) {
+               params->freq = wpa_s->best_24_freq;
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 2.4 GHz "
+                          "channel %d MHz", params->freq);
+       } else if (wpa_s->conf->p2p_oper_channel == 0 &&
+                  wpa_s->best_5_freq > 0 &&
+                  p2p_supported_freq(wpa_s->global->p2p,
+                                     wpa_s->best_5_freq)) {
+               params->freq = wpa_s->best_5_freq;
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz "
+                          "channel %d MHz", params->freq);
+       } else {
+               params->freq = 2412;
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference "
+                          "known)", params->freq);
+       }
+
+       if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
+           wpa_s->assoc_freq && !freq) {
+               wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are "
+                          "already using");
+               params->freq = wpa_s->assoc_freq;
+       }
+
+       res = wpa_drv_shared_freq(wpa_s);
+       if (res > 0 && !freq) {
+               wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are "
+                          "already using on a shared interface");
+               params->freq = res;
+       }
+}
+
+
+static struct wpa_supplicant *
+wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
+                        int go)
+{
+       struct wpa_supplicant *group_wpa_s;
+
+       if (!wpas_p2p_create_iface(wpa_s))
+               return wpa_s;
+
+       if (wpas_p2p_add_group_interface(wpa_s, go ? WPA_IF_P2P_GO :
+                                        WPA_IF_P2P_CLIENT) < 0)
+               return NULL;
+       group_wpa_s = wpas_p2p_init_group_interface(wpa_s, go);
+       if (group_wpa_s == NULL) {
+               wpas_p2p_remove_pending_group_interface(wpa_s);
+               return NULL;
+       }
+
+       return group_wpa_s;
+}
+
+
+/**
+ * wpas_p2p_group_add - Add a new P2P group with local end as Group Owner
+ * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
+ * @persistent_group: Whether to create a persistent group
+ * @freq: Frequency for the group or 0 to indicate no hardcoding
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function creates a new P2P group with the local end as the Group Owner,
+ * i.e., without using Group Owner Negotiation.
+ */
+int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
+                      int freq)
+{
+       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);
+               }
+       }
+
+       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;
+       }
+
+       wpas_p2p_init_go_params(wpa_s, &params, freq);
+       p2p_go_params(wpa_s->global->p2p, &params);
+       params.persistent_group = persistent_group;
+
+       wpa_s = wpas_p2p_get_group_iface(wpa_s, 0, 1);
+       if (wpa_s == NULL)
+               return -1;
+       wpas_start_wps_go(wpa_s, &params, 0);
+
+       return 0;
+}
+
+
+static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
+                                struct wpa_ssid *params, int addr_allocated)
+{
+       struct wpa_ssid *ssid;
+
+       wpa_s = wpas_p2p_get_group_iface(wpa_s, addr_allocated, 0);
+       if (wpa_s == NULL)
+               return -1;
+
+       wpa_supplicant_ap_deinit(wpa_s);
+
+       ssid = wpa_config_add_network(wpa_s->conf);
+       if (ssid == NULL)
+               return -1;
+       wpa_config_set_network_defaults(ssid);
+       ssid->temporary = 1;
+       ssid->proto = WPA_PROTO_RSN;
+       ssid->pairwise_cipher = WPA_CIPHER_CCMP;
+       ssid->group_cipher = WPA_CIPHER_CCMP;
+       ssid->key_mgmt = WPA_KEY_MGMT_PSK;
+       ssid->ssid = os_malloc(params->ssid_len);
+       if (ssid->ssid == NULL) {
+               wpa_config_remove_network(wpa_s->conf, ssid->id);
+               return -1;
+       }
+       os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
+       ssid->ssid_len = params->ssid_len;
+       ssid->p2p_group = 1;
+       ssid->export_keys = 1;
+       if (params->psk_set) {
+               os_memcpy(ssid->psk, params->psk, 32);
+               ssid->psk_set = 1;
+       }
+       if (params->passphrase)
+               ssid->passphrase = os_strdup(params->passphrase);
+
+       wpa_supplicant_select_network(wpa_s, ssid);
+
+       wpa_s->show_group_started = 1;
+
+       return 0;
+}
+
+
+int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
+                                 struct wpa_ssid *ssid, int addr_allocated,
+                                 int freq)
+{
+       struct p2p_go_neg_results params;
+       int go = 0;
+
+       if (ssid->disabled != 2 || ssid->ssid == NULL)
+               return -1;
+
+       if (wpas_get_p2p_group(wpa_s, ssid->ssid, ssid->ssid_len, &go) &&
+           go == (ssid->mode == WPAS_MODE_P2P_GO)) {
+               wpa_printf(MSG_DEBUG, "P2P: Requested persistent group is "
+                          "already running");
+               return 0;
+       }
+
+       /* Make sure we are not running find during connection establishment */
+       wpas_p2p_stop_find(wpa_s);
+
+       if (ssid->mode == WPAS_MODE_INFRA)
+               return wpas_start_p2p_client(wpa_s, ssid, addr_allocated);
+
+       if (ssid->mode != WPAS_MODE_P2P_GO)
+               return -1;
+
+       wpas_p2p_init_go_params(wpa_s, &params, freq);
+
+       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;
+       }
+       os_strlcpy(params.passphrase, ssid->passphrase,
+                  sizeof(params.passphrase));
+       os_memcpy(params.ssid, ssid->ssid, ssid->ssid_len);
+       params.ssid_len = ssid->ssid_len;
+       params.persistent_group = 1;
+
+       wpa_s = wpas_p2p_get_group_iface(wpa_s, addr_allocated, 1);
+       if (wpa_s == NULL)
+               return -1;
+
+       wpas_start_wps_go(wpa_s, &params, 0);
+
+       return 0;
+}
+
+
+static void wpas_p2p_ie_update(void *ctx, struct wpabuf *beacon_ies,
+                              struct wpabuf *proberesp_ies)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       if (wpa_s->ap_iface) {
+               struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
+               if (!(hapd->conf->p2p & P2P_GROUP_OWNER)) {
+                       wpabuf_free(beacon_ies);
+                       wpabuf_free(proberesp_ies);
+                       return;
+               }
+               if (beacon_ies) {
+                       wpabuf_free(hapd->p2p_beacon_ie);
+                       hapd->p2p_beacon_ie = beacon_ies;
+               }
+               wpabuf_free(hapd->p2p_probe_resp_ie);
+               hapd->p2p_probe_resp_ie = proberesp_ies;
+       } else {
+               wpabuf_free(beacon_ies);
+               wpabuf_free(proberesp_ies);
+       }
+       wpa_supplicant_ap_update_beacon(wpa_s);
+}
+
+
+static void wpas_p2p_idle_update(void *ctx, int idle)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       if (!wpa_s->ap_iface)
+               return;
+       wpa_printf(MSG_DEBUG, "P2P: GO - group %sidle", idle ? "" : "not ");
+       if (idle)
+               wpas_p2p_set_group_idle_timeout(wpa_s);
+       else
+               eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
+}
+
+
+struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
+                                      int persistent_group,
+                                      int group_formation)
+{
+       struct p2p_group *group;
+       struct p2p_group_config *cfg;
+
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return NULL;
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return NULL;
+
+       cfg = os_zalloc(sizeof(*cfg));
+       if (cfg == NULL)
+               return NULL;
+
+       if (persistent_group && wpa_s->conf->persistent_reconnect)
+               cfg->persistent_group = 2;
+       else if (persistent_group)
+               cfg->persistent_group = 1;
+       os_memcpy(cfg->interface_addr, wpa_s->own_addr, ETH_ALEN);
+       if (wpa_s->max_stations &&
+           wpa_s->max_stations < wpa_s->conf->max_num_sta)
+               cfg->max_clients = wpa_s->max_stations;
+       else
+               cfg->max_clients = wpa_s->conf->max_num_sta;
+       cfg->cb_ctx = wpa_s;
+       cfg->ie_update = wpas_p2p_ie_update;
+       cfg->idle_update = wpas_p2p_idle_update;
+
+       group = p2p_group_init(wpa_s->global->p2p, cfg);
+       if (group == NULL)
+               os_free(cfg);
+       if (!group_formation)
+               p2p_group_notif_formation_done(group);
+       wpa_s->p2p_group = group;
+       return group;
+}
+
+
+void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+                         int registrar)
+{
+       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);
+
+       eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
+                            NULL);
+       if (wpa_s->global->p2p)
+               p2p_wps_success_cb(wpa_s->global->p2p, peer_addr);
+       else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               wpa_drv_wps_success_cb(wpa_s, peer_addr);
+       wpas_group_formation_completed(wpa_s, 1);
+}
+
+
+void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+                        struct wps_event_fail *fail)
+{
+       if (!wpa_s->p2p_in_provisioning) {
+               wpa_printf(MSG_DEBUG, "P2P: Ignore WPS fail event - P2P "
+                          "provisioning not in progress");
+               return;
+       }
+
+       if (wpa_s->go_params) {
+               p2p_clear_provisioning_info(
+                       wpa_s->global->p2p,
+                       wpa_s->go_params->peer_interface_addr);
+       }
+
+       wpas_notify_p2p_wps_failed(wpa_s, fail);
+}
+
+
+int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+                      const char *config_method, int join)
+{
+       u16 config_methods;
+
+       if (os_strncmp(config_method, "display", 7) == 0)
+               config_methods = WPS_CONFIG_DISPLAY;
+       else if (os_strncmp(config_method, "keypad", 6) == 0)
+               config_methods = WPS_CONFIG_KEYPAD;
+       else if (os_strncmp(config_method, "pbc", 3) == 0 ||
+                os_strncmp(config_method, "pushbutton", 10) == 0)
+               config_methods = WPS_CONFIG_PUSHBUTTON;
+       else {
+               wpa_printf(MSG_DEBUG, "P2P: Unknown config method");
+               return -1;
+       }
+
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
+               return wpa_drv_p2p_prov_disc_req(wpa_s, peer_addr,
+                                                config_methods, 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);
+}
+
+
+int wpas_p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
+                             char *end)
+{
+       return p2p_scan_result_text(ies, ies_len, buf, end);
+}
+
+
+static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s->pending_action_tx)
+               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;
+}
+
+
+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)
+{
+       wpas_p2p_clear_pending_action_tx(wpa_s);
+       wpa_s->p2p_long_listen = 0;
+
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return wpa_drv_p2p_find(wpa_s, timeout, type);
+
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+
+       return p2p_find(wpa_s->global->p2p, timeout, type,
+                       num_req_dev_types, req_dev_types);
+}
+
+
+void wpas_p2p_stop_find(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;
+
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
+               wpa_drv_p2p_stop_find(wpa_s);
+               return;
+       }
+
+       if (wpa_s->global->p2p)
+               p2p_stop_find(wpa_s->global->p2p);
+
+       wpas_p2p_remove_pending_group_interface(wpa_s);
+}
+
+
+static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       wpa_s->p2p_long_listen = 0;
+}
+
+
+int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout)
+{
+       int res;
+
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+
+       wpas_p2p_clear_pending_action_tx(wpa_s);
+
+       if (timeout == 0) {
+               /*
+                * This is a request for unlimited Listen state. However, at
+                * least for now, this is mapped to a Listen state for one
+                * hour.
+                */
+               timeout = 3600;
+       }
+       eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
+       wpa_s->p2p_long_listen = 0;
+
+       /*
+        * Stop previous find/listen operation to avoid trying to request a new
+        * remain-on-channel operation while the driver is still running the
+        * previous one.
+        */
+       if (wpa_s->global->p2p)
+               p2p_stop_find(wpa_s->global->p2p);
+
+       res = wpas_p2p_listen_start(wpa_s, timeout * 1000);
+       if (res == 0 && timeout * 1000 > wpa_s->max_remain_on_chan) {
+               wpa_s->p2p_long_listen = timeout * 1000;
+               eloop_register_timeout(timeout, 0,
+                                      wpas_p2p_long_listen_timeout,
+                                      wpa_s, NULL);
+       }
+
+       return res;
+}
+
+
+int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+                         u8 *buf, size_t len, int p2p_group)
+{
+       struct wpabuf *p2p_ie;
+       int ret;
+
+       if (wpa_s->global->p2p_disabled)
+               return -1;
+       if (wpa_s->global->p2p == NULL)
+               return -1;
+       if (bss == NULL)
+               return -1;
+
+       p2p_ie = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+       ret = p2p_assoc_req_ie(wpa_s->global->p2p, bss->bssid, buf, len,
+                              p2p_group, p2p_ie);
+       wpabuf_free(p2p_ie);
+
+       return ret;
+}
+
+
+int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
+                         const u8 *dst, const u8 *bssid,
+                         const u8 *ie, size_t ie_len)
+{
+       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);
+}
+
+
+void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
+                       const u8 *sa, const u8 *bssid,
+                       u8 category, const u8 *data, size_t len, int freq)
+{
+       if (wpa_s->global->p2p_disabled)
+               return;
+       if (wpa_s->global->p2p == NULL)
+               return;
+
+       p2p_rx_action(wpa_s->global->p2p, da, sa, bssid, category, data, len,
+                     freq);
+}
+
+
+void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies)
+{
+       if (wpa_s->global->p2p_disabled)
+               return;
+       if (wpa_s->global->p2p == NULL)
+               return;
+
+       p2p_scan_ie(wpa_s->global->p2p, ies);
+}
+
+
+void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s)
+{
+       p2p_group_deinit(wpa_s->p2p_group);
+       wpa_s->p2p_group = NULL;
+
+       wpa_s->ap_configured_cb = NULL;
+       wpa_s->ap_configured_cb_ctx = NULL;
+       wpa_s->ap_configured_cb_data = NULL;
+       wpa_s->connect_without_scan = NULL;
+}
+
+
+int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+       wpa_s->p2p_long_listen = 0;
+
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return wpa_drv_p2p_reject(wpa_s, addr);
+
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+
+       return p2p_reject(wpa_s->global->p2p, addr);
+}
+
+
+/* Invite to reinvoke a persistent group */
+int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+                   struct wpa_ssid *ssid, const u8 *go_dev_addr)
+{
+       enum p2p_invite_role role;
+       u8 *bssid = NULL;
+
+       if (ssid->mode == WPAS_MODE_P2P_GO) {
+               role = P2P_INVITE_ROLE_GO;
+               if (peer_addr == NULL) {
+                       wpa_printf(MSG_DEBUG, "P2P: Missing peer "
+                                  "address in invitation command");
+                       return -1;
+               }
+               if (wpas_p2p_create_iface(wpa_s)) {
+                       if (wpas_p2p_add_group_interface(wpa_s,
+                                                        WPA_IF_P2P_GO) < 0) {
+                               wpa_printf(MSG_ERROR, "P2P: Failed to "
+                                          "allocate a new interface for the "
+                                          "group");
+                               return -1;
+                       }
+                       bssid = wpa_s->pending_interface_addr;
+               } else
+                       bssid = wpa_s->own_addr;
+       } else {
+               role = P2P_INVITE_ROLE_CLIENT;
+               peer_addr = ssid->bssid;
+       }
+       wpa_s->pending_invite_ssid_id = ssid->id;
+
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid,
+                                         ssid->ssid, ssid->ssid_len,
+                                         go_dev_addr, 1);
+
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+
+       return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
+                         ssid->ssid, ssid->ssid_len, 0, go_dev_addr, 1);
+}
+
+
+/* Invite to join an active group */
+int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
+                         const u8 *peer_addr, const u8 *go_dev_addr)
+{
+       struct wpa_global *global = wpa_s->global;
+       enum p2p_invite_role role;
+       u8 *bssid = NULL;
+       struct wpa_ssid *ssid;
+
+       for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+               if (os_strcmp(wpa_s->ifname, ifname) == 0)
+                       break;
+       }
+       if (wpa_s == NULL) {
+               wpa_printf(MSG_DEBUG, "P2P: Interface '%s' not found", ifname);
+               return -1;
+       }
+
+       ssid = wpa_s->current_ssid;
+       if (ssid == NULL) {
+               wpa_printf(MSG_DEBUG, "P2P: No current SSID to use for "
+                          "invitation");
+               return -1;
+       }
+
+       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;
+       } else {
+               role = P2P_INVITE_ROLE_CLIENT;
+               if (wpa_s->wpa_state < WPA_ASSOCIATED) {
+                       wpa_printf(MSG_DEBUG, "P2P: Not associated - cannot "
+                                  "invite to current group");
+                       return -1;
+               }
+               bssid = wpa_s->bssid;
+               if (go_dev_addr == NULL &&
+                   !is_zero_ether_addr(wpa_s->go_dev_addr))
+                       go_dev_addr = wpa_s->go_dev_addr;
+       }
+       wpa_s->parent->pending_invite_ssid_id = -1;
+
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid,
+                                         ssid->ssid, ssid->ssid_len,
+                                         go_dev_addr, 0);
+
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+
+       return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
+                         ssid->ssid, ssid->ssid_len, wpa_s->assoc_freq,
+                         go_dev_addr, 0);
+}
+
+
+void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_ssid *ssid = wpa_s->current_ssid;
+       const char *ssid_txt;
+       u8 go_dev_addr[ETH_ALEN];
+       int network_id = -1;
+       int persistent;
+       int freq;
+
+       if (!wpa_s->show_group_started || !ssid)
+               return;
+
+       wpa_s->show_group_started = 0;
+
+       ssid_txt = wpa_ssid_txt(ssid->ssid, ssid->ssid_len);
+       os_memset(go_dev_addr, 0, ETH_ALEN);
+       if (ssid->bssid_set)
+               os_memcpy(go_dev_addr, ssid->bssid, ETH_ALEN);
+       persistent = wpas_p2p_persistent_group(wpa_s, go_dev_addr, ssid->ssid,
+                                              ssid->ssid_len);
+       os_memcpy(wpa_s->go_dev_addr, go_dev_addr, ETH_ALEN);
+
+       if (wpa_s->global->p2p_group_formation == wpa_s)
+               wpa_s->global->p2p_group_formation = NULL;
+
+       freq = wpa_s->current_bss ? wpa_s->current_bss->freq :
+               (int) wpa_s->assoc_freq;
+       if (ssid->passphrase == NULL && ssid->psk_set) {
+               char psk[65];
+               wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
+               wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+                       "%s client ssid=\"%s\" freq=%d psk=%s go_dev_addr="
+                       MACSTR "%s",
+                       wpa_s->ifname, ssid_txt, freq, psk,
+                       MAC2STR(go_dev_addr),
+                       persistent ? " [PERSISTENT]" : "");
+       } else {
+               wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+                       "%s client ssid=\"%s\" freq=%d passphrase=\"%s\" "
+                       "go_dev_addr=" MACSTR "%s",
+                       wpa_s->ifname, ssid_txt, freq,
+                       ssid->passphrase ? ssid->passphrase : "",
+                       MAC2STR(go_dev_addr),
+                       persistent ? " [PERSISTENT]" : "");
+       }
+
+       if (persistent)
+               network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
+                                                            ssid, go_dev_addr);
+       if (network_id < 0)
+               network_id = ssid->id;
+       wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1);
+}
+
+
+int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
+                         u32 interval1, u32 duration2, u32 interval2)
+{
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return -1;
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+
+       if (wpa_s->wpa_state < WPA_ASSOCIATED ||
+           wpa_s->current_ssid == NULL ||
+           wpa_s->current_ssid->mode != WPAS_MODE_INFRA)
+               return -1;
+
+       return p2p_presence_req(wpa_s->global->p2p, wpa_s->bssid,
+                               wpa_s->own_addr, wpa_s->assoc_freq,
+                               duration1, interval1, duration2, interval2);
+}
+
+
+int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
+                       unsigned int interval)
+{
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return -1;
+
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+
+       return p2p_ext_listen(wpa_s->global->p2p, period, interval);
+}
+
+
+static int wpas_p2p_is_client(struct wpa_supplicant *wpa_s)
+{
+       return wpa_s->current_ssid != NULL &&
+               wpa_s->current_ssid->p2p_group &&
+               wpa_s->current_ssid->mode == WPAS_MODE_INFRA;
+}
+
+
+static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+
+       if (wpa_s->conf->p2p_group_idle == 0 && !wpas_p2p_is_client(wpa_s)) {
+               wpa_printf(MSG_DEBUG, "P2P: Ignore group idle timeout - "
+                          "disabled");
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "P2P: Group idle timeout reached - terminate "
+                  "group");
+       wpa_s->removal_reason = P2P_GROUP_REMOVAL_IDLE_TIMEOUT;
+       wpas_p2p_group_delete(wpa_s);
+}
+
+
+static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
+{
+       unsigned int 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;
+
+       timeout = wpa_s->conf->p2p_group_idle;
+       if (wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
+           (timeout == 0 || timeout > P2P_MAX_CLIENT_IDLE))
+           timeout = P2P_MAX_CLIENT_IDLE;
+
+       if (timeout == 0)
+               return;
+
+       wpa_printf(MSG_DEBUG, "P2P: Set P2P group idle timeout to %u seconds",
+                  timeout);
+       eloop_register_timeout(timeout, 0, wpas_p2p_group_idle_timeout,
+                              wpa_s, NULL);
+}
+
+
+void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
+                          u16 reason_code, const u8 *ie, size_t ie_len)
+{
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return;
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return;
+
+       p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len);
+}
+
+
+void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
+                            u16 reason_code, const u8 *ie, size_t ie_len)
+{
+       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);
+}
+
+
+void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
+{
+       struct p2p_data *p2p = wpa_s->global->p2p;
+
+       if (p2p == NULL)
+               return;
+
+       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
+               return;
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_NAME)
+               p2p_set_dev_name(p2p, wpa_s->conf->device_name);
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_TYPE)
+               p2p_set_pri_dev_type(p2p, wpa_s->conf->device_type);
+
+       if (wpa_s->wps &&
+           (wpa_s->conf->changed_parameters & CFG_CHANGED_CONFIG_METHODS))
+               p2p_set_config_methods(p2p, wpa_s->wps->config_methods);
+
+       if (wpa_s->wps && (wpa_s->conf->changed_parameters & CFG_CHANGED_UUID))
+               p2p_set_uuid(p2p, wpa_s->wps->uuid);
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_WPS_STRING) {
+               p2p_set_manufacturer(p2p, wpa_s->conf->manufacturer);
+               p2p_set_model_name(p2p, wpa_s->conf->model_name);
+               p2p_set_model_number(p2p, wpa_s->conf->model_number);
+               p2p_set_serial_number(p2p, wpa_s->conf->serial_number);
+       }
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_SEC_DEVICE_TYPE)
+               p2p_set_sec_dev_types(p2p,
+                                     (void *) wpa_s->conf->sec_device_type,
+                                     wpa_s->conf->num_sec_device_types);
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_VENDOR_EXTENSION) {
+               int i;
+               p2p_remove_wps_vendor_extensions(p2p);
+               for (i = 0; i < MAX_WPS_VENDOR_EXT; i++) {
+                       if (wpa_s->conf->wps_vendor_ext[i] == NULL)
+                               continue;
+                       p2p_add_wps_vendor_extension(
+                               p2p, wpa_s->conf->wps_vendor_ext[i]);
+               }
+       }
+
+       if ((wpa_s->conf->changed_parameters & CFG_CHANGED_COUNTRY) &&
+           wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
+               char country[3];
+               country[0] = wpa_s->conf->country[0];
+               country[1] = wpa_s->conf->country[1];
+               country[2] = 0x04;
+               p2p_set_country(p2p, country);
+       }
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_SSID_POSTFIX) {
+               p2p_set_ssid_postfix(p2p, (u8 *) wpa_s->conf->p2p_ssid_postfix,
+                                    wpa_s->conf->p2p_ssid_postfix ?
+                                    os_strlen(wpa_s->conf->p2p_ssid_postfix) :
+                                    0);
+       }
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_INTRA_BSS)
+               p2p_set_intra_bss_dist(p2p, wpa_s->conf->p2p_intra_bss);
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_LISTEN_CHANNEL) {
+               u8 reg_class, channel;
+               int ret;
+               unsigned int r;
+               if (wpa_s->conf->p2p_listen_reg_class &&
+                   wpa_s->conf->p2p_listen_channel) {
+                       reg_class = wpa_s->conf->p2p_listen_reg_class;
+                       channel = wpa_s->conf->p2p_listen_channel;
+               } else {
+                       reg_class = 81;
+                       /*
+                        * Pick one of the social channels randomly as the
+                        * listen channel.
+                        */
+                       os_get_random((u8 *) &r, sizeof(r));
+                       channel = 1 + (r % 3) * 5;
+               }
+               ret = p2p_set_listen_channel(p2p, reg_class, channel);
+               if (ret)
+                       wpa_printf(MSG_ERROR, "P2P: Own listen channel update "
+                                  "failed: %d", ret);
+       }
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_OPER_CHANNEL) {
+               u8 op_reg_class, op_channel, cfg_op_channel;
+               int ret = 0;
+               unsigned int r;
+               if (wpa_s->conf->p2p_oper_reg_class &&
+                   wpa_s->conf->p2p_oper_channel) {
+                       op_reg_class = wpa_s->conf->p2p_oper_reg_class;
+                       op_channel = wpa_s->conf->p2p_oper_channel;
+                       cfg_op_channel = 1;
+               } else {
+                       op_reg_class = 81;
+                       /*
+                        * Use random operation channel from (1, 6, 11)
+                        *if no other preference is indicated.
+                        */
+                       os_get_random((u8 *) &r, sizeof(r));
+                       op_channel = 1 + (r % 3) * 5;
+                       cfg_op_channel = 0;
+               }
+               ret = p2p_set_oper_channel(p2p, op_reg_class, op_channel,
+                                          cfg_op_channel);
+               if (ret)
+                       wpa_printf(MSG_ERROR, "P2P: Own oper channel update "
+                                  "failed: %d", ret);
+       }
+}
+
+
+int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start,
+                    int duration)
+{
+       if (!wpa_s->ap_iface)
+               return -1;
+       return hostapd_p2p_set_noa(wpa_s->ap_iface->bss[0], count, start,
+                                  duration);
+}
+
+
+int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled)
+{
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return -1;
+
+       wpa_s->global->cross_connection = enabled;
+       p2p_set_cross_connect(wpa_s->global->p2p, enabled);
+
+       if (!enabled) {
+               struct wpa_supplicant *iface;
+
+               for (iface = wpa_s->global->ifaces; iface; iface = iface->next)
+               {
+                       if (iface->cross_connect_enabled == 0)
+                               continue;
+
+                       iface->cross_connect_enabled = 0;
+                       iface->cross_connect_in_use = 0;
+                       wpa_msg(iface->parent, MSG_INFO,
+                               P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+                               iface->ifname, iface->cross_connect_uplink);
+               }
+       }
+
+       return 0;
+}
+
+
+static void wpas_p2p_enable_cross_connect(struct wpa_supplicant *uplink)
+{
+       struct wpa_supplicant *iface;
+
+       if (!uplink->global->cross_connection)
+               return;
+
+       for (iface = uplink->global->ifaces; iface; iface = iface->next) {
+               if (!iface->cross_connect_enabled)
+                       continue;
+               if (os_strcmp(uplink->ifname, iface->cross_connect_uplink) !=
+                   0)
+                       continue;
+               if (iface->ap_iface == NULL)
+                       continue;
+               if (iface->cross_connect_in_use)
+                       continue;
+
+               iface->cross_connect_in_use = 1;
+               wpa_msg(iface->parent, MSG_INFO,
+                       P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
+                       iface->ifname, iface->cross_connect_uplink);
+       }
+}
+
+
+static void wpas_p2p_disable_cross_connect(struct wpa_supplicant *uplink)
+{
+       struct wpa_supplicant *iface;
+
+       for (iface = uplink->global->ifaces; iface; iface = iface->next) {
+               if (!iface->cross_connect_enabled)
+                       continue;
+               if (os_strcmp(uplink->ifname, iface->cross_connect_uplink) !=
+                   0)
+                       continue;
+               if (!iface->cross_connect_in_use)
+                       continue;
+
+               wpa_msg(iface->parent, MSG_INFO,
+                       P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+                       iface->ifname, iface->cross_connect_uplink);
+               iface->cross_connect_in_use = 0;
+       }
+}
+
+
+void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->ap_iface || wpa_s->current_ssid == NULL ||
+           wpa_s->current_ssid->mode != WPAS_MODE_INFRA ||
+           wpa_s->cross_connect_disallowed)
+               wpas_p2p_disable_cross_connect(wpa_s);
+       else
+               wpas_p2p_enable_cross_connect(wpa_s);
+       if (!wpa_s->ap_iface)
+               eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
+}
+
+
+void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s)
+{
+       wpas_p2p_disable_cross_connect(wpa_s);
+       if (!wpa_s->ap_iface &&
+           !eloop_is_timeout_registered(wpas_p2p_group_idle_timeout,
+                                        wpa_s, NULL))
+               wpas_p2p_set_group_idle_timeout(wpa_s);
+}
+
+
+static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_supplicant *iface;
+
+       if (!wpa_s->global->cross_connection)
+               return;
+
+       for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+               if (iface == wpa_s)
+                       continue;
+               if (iface->drv_flags &
+                   WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)
+                       continue;
+               if (iface->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE)
+                       continue;
+
+               wpa_s->cross_connect_enabled = 1;
+               os_strlcpy(wpa_s->cross_connect_uplink, iface->ifname,
+                          sizeof(wpa_s->cross_connect_uplink));
+               wpa_printf(MSG_DEBUG, "P2P: Enable cross connection from "
+                          "%s to %s whenever uplink is available",
+                          wpa_s->ifname, wpa_s->cross_connect_uplink);
+
+               if (iface->ap_iface || iface->current_ssid == NULL ||
+                   iface->current_ssid->mode != WPAS_MODE_INFRA ||
+                   iface->cross_connect_disallowed ||
+                   iface->wpa_state != WPA_COMPLETED)
+                       break;
+
+               wpa_s->cross_connect_in_use = 1;
+               wpa_msg(wpa_s->parent, MSG_INFO,
+                       P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
+                       wpa_s->ifname, wpa_s->cross_connect_uplink);
+               break;
+       }
+}
+
+
+int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->p2p_group_interface != P2P_GROUP_INTERFACE_CLIENT &&
+           !wpa_s->p2p_in_provisioning)
+               return 0; /* not P2P client operation */
+
+       wpa_printf(MSG_DEBUG, "P2P: Terminate connection due to WPS PBC "
+                  "session overlap");
+       if (wpa_s != wpa_s->parent)
+               wpa_msg_ctrl(wpa_s->parent, MSG_INFO, WPS_EVENT_OVERLAP);
+
+       if (wpa_s->global->p2p)
+               p2p_group_formation_failed(wpa_s->global->p2p);
+
+       eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+                            wpa_s->parent, NULL);
+
+       wpas_group_formation_completed(wpa_s, 0);
+       return 1;
+}
+
+
+void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s)
+{
+       struct p2p_channels chan;
+
+       if (wpa_s->global == NULL || wpa_s->global->p2p == NULL)
+               return;
+
+       os_memset(&chan, 0, sizeof(chan));
+       if (wpas_p2p_setup_channels(wpa_s, &chan)) {
+               wpa_printf(MSG_ERROR, "P2P: Failed to update supported "
+                          "channel list");
+               return;
+       }
+
+       p2p_update_channel_list(wpa_s->global->p2p, &chan);
+}
+
+
+int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_global *global = wpa_s->global;
+       int found = 0;
+       const u8 *peer;
+
+       if (global->p2p == NULL)
+               return -1;
+
+       wpa_printf(MSG_DEBUG, "P2P: Request to cancel group formation");
+
+       if (wpa_s->pending_interface_name[0] &&
+           !is_zero_ether_addr(wpa_s->pending_interface_addr))
+               found = 1;
+
+       peer = p2p_get_go_neg_peer(global->p2p);
+       if (peer) {
+               wpa_printf(MSG_DEBUG, "P2P: Unauthorize pending GO Neg peer "
+                          MACSTR, MAC2STR(peer));
+               p2p_unauthorize(global->p2p, peer);
+       }
+
+       wpas_p2p_stop_find(wpa_s);
+
+       for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+               if (wpa_s == global->p2p_group_formation &&
+                   (wpa_s->p2p_in_provisioning ||
+                    wpa_s->parent->pending_interface_type ==
+                    WPA_IF_P2P_CLIENT)) {
+                       wpa_printf(MSG_DEBUG, "P2P: Interface %s in group "
+                                  "formation found - cancelling",
+                                  wpa_s->ifname);
+                       found = 1;
+                       eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+                                            wpa_s->parent, NULL);
+                       wpas_p2p_group_delete(wpa_s);
+                       break;
+               }
+       }
+
+       if (!found) {
+               wpa_printf(MSG_DEBUG, "P2P: No ongoing group formation found");
+               return -1;
+       }
+
+       return 0;
+}
+
+
+void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->current_ssid == NULL || !wpa_s->current_ssid->p2p_group)
+               return;
+
+       wpa_printf(MSG_DEBUG, "P2P: Remove group due to driver resource not "
+                  "being available anymore");
+       wpa_s->removal_reason = P2P_GROUP_REMOVAL_UNAVAILABLE;
+       wpas_p2p_group_delete(wpa_s);
+}
+
+
+void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s,
+                                  int freq_24, int freq_5, int freq_overall)
+{
+       struct p2p_data *p2p = wpa_s->global->p2p;
+       if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT))
+               return;
+       p2p_set_best_channels(p2p, freq_24, freq_5, freq_overall);
+}
+
+
+int wpas_p2p_unauthorize(struct wpa_supplicant *wpa_s, const char *addr)
+{
+       u8 peer[ETH_ALEN];
+       struct p2p_data *p2p = wpa_s->global->p2p;
+
+       if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT))
+               return -1;
+
+       if (hwaddr_aton(addr, peer))
+               return -1;
+
+       return p2p_unauthorize(p2p, peer);
+}
+
+
+/**
+ * wpas_p2p_disconnect - Disconnect from a P2P Group
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This can be used to disconnect from a group in which the local end is a P2P
+ * Client or to end a P2P Group in case the local end is the Group Owner. If a
+ * virtual network interface was created for this group, that interface will be
+ * removed. Otherwise, only the configured P2P group network will be removed
+ * from the interface.
+ */
+int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s)
+{
+
+       if (wpa_s == NULL)
+               return -1;
+
+       wpa_s->removal_reason = P2P_GROUP_REMOVAL_REQUESTED;
+       wpas_p2p_group_delete(wpa_s);
+
+       return 0;
+}
+
+
+int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return 0;
+
+       return p2p_in_progress(wpa_s->global->p2p);
+}
+
+
+void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
+                             struct wpa_ssid *ssid)
+
+{
+       if (wpa_s->p2p_in_provisioning && ssid->p2p_group &&
+           eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+                                wpa_s->parent, NULL) > 0) {
+               wpa_printf(MSG_DEBUG, "P2P: Canceled group formation due to "
+                          "P2P group network getting removed");
+               wpas_p2p_group_formation_timeout(wpa_s->parent, NULL);
+       }
+}
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
new file mode 100644 (file)
index 0000000..9a0af1f
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+#ifndef P2P_SUPPLICANT_H
+#define P2P_SUPPLICANT_H
+
+enum p2p_wps_method;
+struct p2p_go_neg_results;
+enum p2p_send_action_result;
+struct p2p_peer_info;
+
+int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s);
+void wpas_p2p_deinit(struct wpa_supplicant *wpa_s);
+void wpas_p2p_deinit_global(struct wpa_global *global);
+int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+                    const char *pin, enum p2p_wps_method wps_method,
+                    int persistent_group, int join, int auth, int go_intent,
+                    int freq);
+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 wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
+                                 struct wpa_ssid *ssid, int addr_allocated,
+                                 int freq);
+struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
+                                      int persistent_group,
+                                      int group_formation);
+void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+                         int registrar);
+int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+                      const char *config_method, int join);
+void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst,
+                               const u8 *data, size_t data_len,
+                               enum p2p_send_action_result result);
+int wpas_p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
+                             char *end);
+enum p2p_discovery_type;
+int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
+                 enum p2p_discovery_type type,
+                 unsigned int num_req_dev_types, const u8 *req_dev_types);
+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);
+void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
+                       const u8 *sa, const u8 *bssid,
+                       u8 category, const u8 *data, size_t len, int freq);
+void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies);
+void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s);
+void wpas_dev_found(void *ctx, const u8 *addr,
+                   const struct p2p_peer_info *info,
+                   int new_device);
+void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res);
+void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id);
+void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
+                       const u8 *dev_addr, const u8 *pri_dev_type,
+                       const char *dev_name, u16 supp_config_methods,
+                       u8 dev_capab, u8 group_capab, const u8 *group_id,
+                       size_t group_id_len);
+void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods);
+void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
+                    u16 update_indic, const u8 *tlvs, size_t tlvs_len);
+void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
+                     const u8 *tlvs, size_t tlvs_len);
+u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+                       const struct wpabuf *tlvs);
+u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
+                            u8 version, const char *query);
+int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req);
+void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
+                         const u8 *dst, u8 dialog_token,
+                         const struct wpabuf *resp_tlvs);
+void wpas_p2p_sd_service_update(struct wpa_supplicant *wpa_s);
+void wpas_p2p_service_flush(struct wpa_supplicant *wpa_s);
+int wpas_p2p_service_add_bonjour(struct wpa_supplicant *wpa_s,
+                                struct wpabuf *query, struct wpabuf *resp);
+int wpas_p2p_service_del_bonjour(struct wpa_supplicant *wpa_s,
+                                const struct wpabuf *query);
+int wpas_p2p_service_add_upnp(struct wpa_supplicant *wpa_s, u8 version,
+                             const char *service);
+int wpas_p2p_service_del_upnp(struct wpa_supplicant *wpa_s, u8 version,
+                             const char *service);
+int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr);
+int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+                   struct wpa_ssid *ssid, const u8 *go_dev_addr);
+int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
+                         const u8 *peer_addr, const u8 *go_dev_addr);
+void wpas_p2p_completed(struct wpa_supplicant *wpa_s);
+int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
+                         u32 interval1, u32 duration2, u32 interval2);
+int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
+                       unsigned int interval);
+void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
+                          u16 reason_code, const u8 *ie, size_t ie_len);
+void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
+                            u16 reason_code, const u8 *ie, size_t ie_len);
+void wpas_p2p_update_config(struct wpa_supplicant *wpa_s);
+int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start,
+                    int duration);
+int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled);
+void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s);
+void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s);
+int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s);
+void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s);
+int wpas_p2p_cancel(struct wpa_supplicant *wpa_s);
+void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s);
+void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s,
+                                  int freq_24, int freq_5, int freq_overall);
+int wpas_p2p_unauthorize(struct wpa_supplicant *wpa_s, const char *addr);
+int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s);
+void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+                        struct wps_event_fail *fail);
+int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s);
+void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
+                             struct wpa_ssid *ssid);
+
+#endif /* P2P_SUPPLICANT_H */
index 7b464d8..adc6213 100644 (file)
@@ -20,8 +20,9 @@
 #include "config.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
-#include "mlme.h"
 #include "wps_supplicant.h"
+#include "p2p_supplicant.h"
+#include "p2p/p2p.h"
 #include "notify.h"
 #include "bss.h"
 #include "scan.h"
@@ -42,21 +43,21 @@ static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
                        wpas_notify_network_changed(wpa_s);
        }
        wpa_supplicant_initiate_eapol(wpa_s);
-       wpa_printf(MSG_DEBUG, "Already associated with a configured network - "
-                  "generating associated event");
+       wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with a configured "
+               "network - generating associated event");
        os_memset(&data, 0, sizeof(data));
        wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data);
 }
 
 
 #ifdef CONFIG_WPS
-static int wpas_wps_in_use(struct wpa_config *conf,
+static int wpas_wps_in_use(struct wpa_supplicant *wpa_s,
                           enum wps_request_type *req_type)
 {
        struct wpa_ssid *ssid;
        int wps = 0;
 
-       for (ssid = conf->ssid; ssid; ssid = ssid->next) {
+       for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
                if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
                        continue;
 
@@ -69,6 +70,14 @@ static int wpas_wps_in_use(struct wpa_config *conf,
                        return 2;
        }
 
+#ifdef CONFIG_P2P
+       wpa_s->wps->dev.p2p = 1;
+       if (!wps) {
+               wps = 1;
+               *req_type = WPS_REQ_ENROLLEE_INFO;
+       }
+#endif /* CONFIG_P2P */
+
        return wps;
 }
 #endif /* CONFIG_WPS */
@@ -77,12 +86,13 @@ static int wpas_wps_in_use(struct wpa_config *conf,
 int wpa_supplicant_enabled_networks(struct wpa_config *conf)
 {
        struct wpa_ssid *ssid = conf->ssid;
+       int count = 0;
        while (ssid) {
                if (!ssid->disabled)
-                       return 1;
+                       count++;
                ssid = ssid->next;
        }
-       return 0;
+       return count;
 }
 
 
@@ -97,8 +107,8 @@ static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s,
 
        /* ap_scan=2 mode - try to associate with each SSID. */
        if (ssid == NULL) {
-               wpa_printf(MSG_DEBUG, "wpa_supplicant_scan: Reached "
-                          "end of scan list - go back to beginning");
+               wpa_dbg(wpa_s, MSG_DEBUG, "wpa_supplicant_assoc_try: Reached "
+                       "end of scan list - go back to beginning");
                wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
                wpa_supplicant_req_scan(wpa_s, 0, 0);
                return;
@@ -189,16 +199,71 @@ int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
 
        wpa_supplicant_notify_scanning(wpa_s, 1);
 
-       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-               ret = ieee80211_sta_req_scan(wpa_s, params);
-       else
-               ret = wpa_drv_scan(wpa_s, params);
-
+       ret = wpa_drv_scan(wpa_s, params);
        if (ret) {
                wpa_supplicant_notify_scanning(wpa_s, 0);
                wpas_notify_scan_done(wpa_s, 0);
-       } else
+       } else {
                wpa_s->scan_runs++;
+               wpa_s->normal_scans++;
+       }
+
+       return ret;
+}
+
+
+static void
+wpa_supplicant_delayed_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+
+       wpa_dbg(wpa_s, MSG_DEBUG, "Starting delayed sched scan");
+
+       if (wpa_supplicant_req_sched_scan(wpa_s))
+               wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
+
+
+static void
+wpa_supplicant_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+
+       wpa_dbg(wpa_s, MSG_DEBUG, "Sched scan timeout - stopping it");
+
+       wpa_s->sched_scan_timed_out = 1;
+       wpa_supplicant_cancel_sched_scan(wpa_s);
+}
+
+
+static int
+wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
+                               struct wpa_driver_scan_params *params,
+                               int interval)
+{
+       int ret;
+
+       wpa_supplicant_notify_scanning(wpa_s, 1);
+       ret = wpa_drv_sched_scan(wpa_s, params, interval * 1000);
+       if (ret)
+               wpa_supplicant_notify_scanning(wpa_s, 0);
+       else
+               wpa_s->sched_scanning = 1;
+
+       return ret;
+}
+
+
+static int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
+{
+       int ret;
+
+       ret = wpa_drv_stop_sched_scan(wpa_s);
+       if (ret) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "stopping sched_scan failed!");
+               /* TODO: what to do if stopping fails? */
+               return -1;
+       }
 
        return ret;
 }
@@ -237,47 +302,153 @@ wpa_supplicant_build_filter_ssids(struct wpa_config *conf, size_t *num_ssids)
 }
 
 
-static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
+static void wpa_supplicant_optimize_freqs(
+       struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params)
 {
-       struct wpa_supplicant *wpa_s = eloop_ctx;
-       struct wpa_ssid *ssid;
-       int scan_req = 0, ret;
-       struct wpabuf *wps_ie = NULL;
+#ifdef CONFIG_P2P
+       if (params->freqs == NULL && wpa_s->p2p_in_provisioning &&
+           wpa_s->go_params) {
+               /* Optimize provisioning state scan based on GO information */
+               if (wpa_s->p2p_in_provisioning < 5 &&
+                   wpa_s->go_params->freq > 0) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO "
+                               "preferred frequency %d MHz",
+                               wpa_s->go_params->freq);
+                       params->freqs = os_zalloc(2 * sizeof(int));
+                       if (params->freqs)
+                               params->freqs[0] = wpa_s->go_params->freq;
+               } else if (wpa_s->p2p_in_provisioning < 8 &&
+                          wpa_s->go_params->freq_list[0]) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only common "
+                               "channels");
+                       int_array_concat(&params->freqs,
+                                        wpa_s->go_params->freq_list);
+                       if (params->freqs)
+                               int_array_sort_unique(params->freqs);
+               }
+               wpa_s->p2p_in_provisioning++;
+       }
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WPS
+       if (params->freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) {
+               /*
+                * Optimize post-provisioning scan based on channel used
+                * during provisioning.
+                */
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz "
+                       "that was used during provisioning", wpa_s->wps_freq);
+               params->freqs = os_zalloc(2 * sizeof(int));
+               if (params->freqs)
+                       params->freqs[0] = wpa_s->wps_freq;
+               wpa_s->after_wps--;
+       }
+
+#endif /* CONFIG_WPS */
+}
+
+
+#ifdef CONFIG_INTERWORKING
+static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s,
+                                          struct wpabuf *buf)
+{
+       if (wpa_s->conf->interworking == 0)
+               return;
+
+       wpabuf_put_u8(buf, WLAN_EID_EXT_CAPAB);
+       wpabuf_put_u8(buf, 4);
+       wpabuf_put_u8(buf, 0x00);
+       wpabuf_put_u8(buf, 0x00);
+       wpabuf_put_u8(buf, 0x00);
+       wpabuf_put_u8(buf, 0x80); /* Bit 31 - Interworking */
+
+       wpabuf_put_u8(buf, WLAN_EID_INTERWORKING);
+       wpabuf_put_u8(buf, is_zero_ether_addr(wpa_s->conf->hessid) ? 1 :
+                     1 + ETH_ALEN);
+       wpabuf_put_u8(buf, wpa_s->conf->access_network_type);
+       /* No Venue Info */
+       if (!is_zero_ether_addr(wpa_s->conf->hessid))
+               wpabuf_put_data(buf, wpa_s->conf->hessid, ETH_ALEN);
+}
+#endif /* CONFIG_INTERWORKING */
+
+
+static struct wpabuf *
+wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s,
+                        struct wpa_driver_scan_params *params)
+{
+       struct wpabuf *extra_ie = NULL;
 #ifdef CONFIG_WPS
        int wps = 0;
        enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
 #endif /* CONFIG_WPS */
+
+#ifdef CONFIG_INTERWORKING
+       if (wpa_s->conf->interworking &&
+           wpabuf_resize(&extra_ie, 100) == 0)
+               wpas_add_interworking_elements(wpa_s, extra_ie);
+#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_WPS
+       wps = wpas_wps_in_use(wpa_s, &req_type);
+
+       if (wps) {
+               struct wpabuf *wps_ie;
+               wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev,
+                                               wpa_s->wps->uuid, req_type,
+                                               0, NULL);
+               if (wps_ie) {
+                       if (wpabuf_resize(&extra_ie, wpabuf_len(wps_ie)) == 0)
+                               wpabuf_put_buf(extra_ie, wps_ie);
+                       wpabuf_free(wps_ie);
+               }
+       }
+
+#ifdef CONFIG_P2P
+       if (wps) {
+               size_t ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
+               if (wpabuf_resize(&extra_ie, ielen) == 0)
+                       wpas_p2p_scan_ie(wpa_s, extra_ie);
+       }
+#endif /* CONFIG_P2P */
+
+#endif /* CONFIG_WPS */
+
+       return extra_ie;
+}
+
+
+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;
        struct wpa_driver_scan_params params;
        size_t max_ssids;
        enum wpa_states prev_state;
 
+       if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
+               return;
+       }
+
        if (wpa_s->disconnected && !wpa_s->scan_req) {
                wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
-       /*
-        * Oct, 26th. 2011. TIZEN
-        * If scan after auth timeout is failed, wpa_s->associate_num should be initialized.
-        */
-               wpa_s->associate_num = 2;
                return;
        }
 
-       wpa_printf(MSG_DEBUG,"Current scan req is [%d]",wpa_s->scan_req);
        if (!wpa_supplicant_enabled_networks(wpa_s->conf) &&
            !wpa_s->scan_req) {
-               wpa_printf(MSG_DEBUG, "No enabled networks - do not scan");
+               wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
                wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
-               /*
-                * Oct, 26th. 2011. TIZEN
-                * If scan after auth timeout is failed, wpa_s->associate_num should be initialized.
-                */
-               wpa_s->associate_num = 2;
                return;
        }
 
        if (wpa_s->conf->ap_scan != 0 &&
            (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) {
-               wpa_printf(MSG_DEBUG, "Using wired authentication - "
-                          "overriding ap_scan configuration");
+               wpa_dbg(wpa_s, MSG_DEBUG, "Using wired authentication - "
+                       "overriding ap_scan configuration");
                wpa_s->conf->ap_scan = 0;
                wpas_notify_ap_scan_changed(wpa_s);
        }
@@ -287,8 +458,21 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                return;
        }
 
-       if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) ||
-           wpa_s->conf->ap_scan == 2)
+#ifdef CONFIG_P2P
+       if (wpas_p2p_in_progress(wpa_s)) {
+               if (wpa_s->wpa_state == WPA_SCANNING) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan "
+                               "while P2P operation is in progress");
+                       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;
+       }
+#endif /* CONFIG_P2P */
+
+       if (wpa_s->conf->ap_scan == 2)
                max_ssids = 1;
        else {
                max_ssids = wpa_s->max_scan_ssids;
@@ -296,10 +480,6 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                        max_ssids = WPAS_MAX_SCAN_SSIDS;
        }
 
-#ifdef CONFIG_WPS
-       wps = wpas_wps_in_use(wpa_s->conf, &req_type);
-#endif /* CONFIG_WPS */
-
        scan_req = wpa_s->scan_req;
        wpa_s->scan_req = 0;
 
@@ -310,14 +490,22 @@ 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) {
+               for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+                       if (ssid == wpa_s->connect_without_scan)
+                               break;
+               }
+               wpa_s->connect_without_scan = NULL;
+               if (ssid) {
+                       wpa_printf(MSG_DEBUG, "Start a pre-selected network "
+                                  "without scan step");
+                       wpa_supplicant_associate(wpa_s, NULL, ssid);
+                       return;
+               }
+       }
+
        /* Find the starting point from which to continue scanning */
        ssid = wpa_s->conf->ssid;
-       if(ssid != NULL)
-       {
-               wpa_printf(MSG_DEBUG, "==============================");
-               wpa_printf(MSG_DEBUG, "Check 1 wildcard ssid [%s]",ssid->ssid);
-               wpa_printf(MSG_DEBUG, "==============================");
-       }
        if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) {
                while (ssid) {
                        if (ssid == wpa_s->prev_scan_ssid) {
@@ -325,18 +513,11 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                                break;
                        }
                        ssid = ssid->next;
-                       if(ssid != NULL)
-                       {
-                               wpa_printf(MSG_DEBUG, "==============================");
-                               wpa_printf(MSG_DEBUG, "Check 2 wildcard ssid [%s]",ssid->ssid);
-                               wpa_printf(MSG_DEBUG, "==============================");
-                       }
                }
        }
 
-       if (scan_req != 2 && (wpa_s->conf->ap_scan == 2 ||
-                             wpa_s->connect_without_scan)) {
-               wpa_s->connect_without_scan = 0;
+       if (scan_req != 2 && wpa_s->conf->ap_scan == 2) {
+               wpa_s->connect_without_scan = NULL;
                wpa_supplicant_assoc_try(wpa_s, ssid);
                return;
        } else if (wpa_s->conf->ap_scan == 2) {
@@ -345,22 +526,11 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                 * wildcard SSID.
                 */
                ssid = NULL;
-               wpa_printf(MSG_DEBUG, "==============================");
-               wpa_printf(MSG_DEBUG, "Check 3 wildcard ssid is NULL");
-               wpa_printf(MSG_DEBUG, "==============================");
        } else {
                struct wpa_ssid *start = ssid, *tssid;
                int freqs_set = 0;
                if (ssid == NULL && max_ssids > 1)
-               {
                        ssid = wpa_s->conf->ssid;
-                       if(ssid != NULL)
-                       {
-                       wpa_printf(MSG_DEBUG, "==============================");
-                       wpa_printf(MSG_DEBUG, "Check 4 wildcard ssid [%s]",ssid->ssid);
-                       wpa_printf(MSG_DEBUG, "==============================");
-                       }
-               }
                while (ssid) {
                        if (!ssid->disabled && ssid->scan_ssid) {
                                wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID",
@@ -380,12 +550,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                            start != wpa_s->conf->ssid)
                                ssid = wpa_s->conf->ssid;
                }
-               if(ssid != NULL)
-               {
-                       wpa_printf(MSG_DEBUG, "==============================");
-                       wpa_printf(MSG_DEBUG, "Check 5 wildcard ssid [%s]",ssid->ssid);
-                       wpa_printf(MSG_DEBUG, "==============================");
-               }
+
                for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) {
                        if (tssid->disabled)
                                continue;
@@ -400,61 +565,59 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                }
                int_array_sort_unique(params.freqs);
        }
-       if(ssid != NULL)
-       {
-               wpa_printf(MSG_DEBUG, "==============================");
-               wpa_printf(MSG_DEBUG, "Check 6 wildcard ssid [%s]",ssid->ssid);
-               wpa_printf(MSG_DEBUG, "==============================");
-       }
+
        if (ssid) {
                wpa_s->prev_scan_ssid = ssid;
                if (max_ssids > 1) {
-                       wpa_printf(MSG_DEBUG, "Include wildcard SSID in the "
-                                  "scan request");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in "
+                               "the scan request");
                        params.num_ssids++;
                }
-               wpa_printf(MSG_DEBUG, "Starting AP scan for specific SSID(s)");
+               wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for specific "
+                       "SSID(s)");
        } else {
                wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
                params.num_ssids++;
-               wpa_printf(MSG_DEBUG, "Starting AP scan for wildcard SSID");
+               wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard "
+                       "SSID");
        }
 
-#ifdef CONFIG_WPS
-       if (params.freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) {
-               /*
-                * Optimize post-provisioning scan based on channel used
-                * during provisioning.
-                */
-               wpa_printf(MSG_DEBUG, "WPS: Scan only frequency %u MHz that "
-                          "was used during provisioning", wpa_s->wps_freq);
-               params.freqs = os_zalloc(2 * sizeof(int));
-               if (params.freqs)
-                       params.freqs[0] = wpa_s->wps_freq;
-               wpa_s->after_wps--;
-       }
+       wpa_supplicant_optimize_freqs(wpa_s, &params);
+       extra_ie = wpa_supplicant_extra_ies(wpa_s, &params);
 
-       if (wps) {
-               wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev,
-                                               wpa_s->wps->uuid, req_type);
-               if (wps_ie) {
-                       params.extra_ies = wpabuf_head(wps_ie);
-                       params.extra_ies_len = wpabuf_len(wps_ie);
-               }
-       }
-#endif /* CONFIG_WPS */
+       if (params.freqs == NULL && wpa_s->next_scan_freqs) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously "
+                       "generated frequency list");
+               params.freqs = wpa_s->next_scan_freqs;
+       } else
+               os_free(wpa_s->next_scan_freqs);
+       wpa_s->next_scan_freqs = NULL;
 
        params.filter_ssids = wpa_supplicant_build_filter_ssids(
                wpa_s->conf, &params.num_filter_ssids);
+       if (extra_ie) {
+               params.extra_ies = wpabuf_head(extra_ie);
+               params.extra_ies_len = wpabuf_len(extra_ie);
+       }
+
+#ifdef CONFIG_P2P
+       if (wpa_s->p2p_in_provisioning) {
+               /*
+                * The interface may not yet be in P2P mode, so we have to
+                * explicitly request P2P probe to disable CCK rates.
+                */
+               params.p2p_probe = 1;
+       }
+#endif /* CONFIG_P2P */
 
        ret = wpa_supplicant_trigger_scan(wpa_s, &params);
 
-       wpabuf_free(wps_ie);
+       wpabuf_free(extra_ie);
        os_free(params.freqs);
        os_free(params.filter_ssids);
 
        if (ret) {
-               wpa_printf(MSG_WARNING, "Failed to initiate AP scan.");
+               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);
                wpa_supplicant_req_scan(wpa_s, 1, 0);
@@ -489,13 +652,13 @@ void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
                        ssid = ssid->next;
                }
                if (ssid) {
-                       wpa_msg(wpa_s, MSG_DEBUG, "Not rescheduling scan to "
+                       wpa_dbg(wpa_s, MSG_DEBUG, "Not rescheduling scan to "
                                "ensure that specific SSID scans occur");
                        return;
                }
        }
 
-       wpa_msg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",
+       wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",
                sec, usec);
        eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
        eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL);
@@ -503,6 +666,215 @@ void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
 
 
 /**
+ * wpa_supplicant_delayed_sched_scan - Request a delayed scheduled scan
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @sec: Number of seconds after which to scan
+ * @usec: Number of microseconds after which to scan
+ *
+ * This function is used to schedule periodic scans for neighboring
+ * access points after the specified time.
+ */
+int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
+                                     int sec, int usec)
+{
+       if (!wpa_s->sched_scan_supported)
+               return -1;
+
+       eloop_register_timeout(sec, usec,
+                              wpa_supplicant_delayed_sched_scan_timeout,
+                              wpa_s, NULL);
+
+       return 0;
+}
+
+
+/**
+ * wpa_supplicant_req_sched_scan - Start a periodic scheduled scan
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to schedule periodic scans for neighboring
+ * access points repeating the scan continuously.
+ */
+int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_driver_scan_params params;
+       enum wpa_states prev_state;
+       struct wpa_ssid *ssid;
+       struct wpabuf *wps_ie = NULL;
+       int ret;
+       unsigned int max_sched_scan_ssids;
+       int wildcard = 0;
+       int need_ssids;
+
+       if (!wpa_s->sched_scan_supported)
+               return -1;
+
+       if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS)
+               max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS;
+       else
+               max_sched_scan_ssids = wpa_s->max_sched_scan_ssids;
+       if (max_sched_scan_ssids < 1)
+               return -1;
+
+       if (wpa_s->sched_scanning) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "Already sched scanning");
+               return 0;
+       }
+
+       need_ssids = 0;
+       for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+               if (!ssid->disabled && !ssid->scan_ssid) {
+                       /* Use wildcard SSID to find this network */
+                       wildcard = 1;
+               } else if (!ssid->disabled && ssid->ssid_len)
+                       need_ssids++;
+       }
+       if (wildcard)
+               need_ssids++;
+
+       if (wpa_s->normal_scans < 3 &&
+           (need_ssids <= wpa_s->max_scan_ssids ||
+            wpa_s->max_scan_ssids >= (int) max_sched_scan_ssids)) {
+               /*
+                * When normal scan can speed up operations, use that for the
+                * first operations before starting the sched_scan to allow
+                * user space sleep more. We do this only if the normal scan
+                * has functionality that is suitable for this or if the
+                * sched_scan does not have better support for multiple SSIDs.
+                */
+               wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of "
+                       "sched_scan for initial scans (normal_scans=%d)",
+                       wpa_s->normal_scans);
+               return -1;
+       }
+
+       os_memset(&params, 0, sizeof(params));
+
+       /* If we can't allocate space for the filters, we just don't filter */
+       params.filter_ssids = os_zalloc(wpa_s->max_match_sets *
+                                       sizeof(struct wpa_driver_scan_filter));
+
+       prev_state = wpa_s->wpa_state;
+       if (wpa_s->wpa_state == WPA_DISCONNECTED ||
+           wpa_s->wpa_state == WPA_INACTIVE)
+               wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
+
+       /* Find the starting point from which to continue scanning */
+       ssid = wpa_s->conf->ssid;
+       if (wpa_s->prev_sched_ssid) {
+               while (ssid) {
+                       if (ssid == wpa_s->prev_sched_ssid) {
+                               ssid = ssid->next;
+                               break;
+                       }
+                       ssid = ssid->next;
+               }
+       }
+
+       if (!ssid || !wpa_s->prev_sched_ssid) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list");
+
+               wpa_s->sched_scan_interval = 10;
+               wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
+               wpa_s->first_sched_scan = 1;
+               ssid = wpa_s->conf->ssid;
+               wpa_s->prev_sched_ssid = ssid;
+       }
+
+       if (wildcard) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "Add wildcard SSID to sched_scan");
+               params.num_ssids++;
+       }
+
+       while (ssid) {
+               if (ssid->disabled)
+                       goto next;
+
+               if (params.num_filter_ssids < wpa_s->max_match_sets &&
+                   params.filter_ssids && ssid->ssid && ssid->ssid_len) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "add to filter ssid: %s",
+                               wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+                       os_memcpy(params.filter_ssids[params.num_filter_ssids].ssid,
+                                 ssid->ssid, ssid->ssid_len);
+                       params.filter_ssids[params.num_filter_ssids].ssid_len =
+                               ssid->ssid_len;
+                       params.num_filter_ssids++;
+               } else if (params.filter_ssids && ssid->ssid && ssid->ssid_len)
+               {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "Not enough room for SSID "
+                               "filter for sched_scan - drop filter");
+                       os_free(params.filter_ssids);
+                       params.filter_ssids = NULL;
+                       params.num_filter_ssids = 0;
+               }
+
+               if (ssid->scan_ssid && ssid->ssid && ssid->ssid_len) {
+                       if (params.num_ssids == max_sched_scan_ssids)
+                               break; /* only room for broadcast SSID */
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "add to active scan ssid: %s",
+                               wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+                       params.ssids[params.num_ssids].ssid =
+                               ssid->ssid;
+                       params.ssids[params.num_ssids].ssid_len =
+                               ssid->ssid_len;
+                       params.num_ssids++;
+                       if (params.num_ssids >= max_sched_scan_ssids) {
+                               wpa_s->prev_sched_ssid = ssid;
+                               break;
+                       }
+               }
+
+       next:
+               wpa_s->prev_sched_ssid = ssid;
+               ssid = ssid->next;
+       }
+
+       if (params.num_filter_ssids == 0) {
+               os_free(params.filter_ssids);
+               params.filter_ssids = NULL;
+       }
+
+       if (wpa_s->wps)
+               wps_ie = wpa_supplicant_extra_ies(wpa_s, &params);
+
+       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);
+       }
+
+       ret = wpa_supplicant_start_sched_scan(wpa_s, &params,
+                                             wpa_s->sched_scan_interval);
+       wpabuf_free(wps_ie);
+       os_free(params.filter_ssids);
+       if (ret) {
+               wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan");
+               if (prev_state != wpa_s->wpa_state)
+                       wpa_supplicant_set_state(wpa_s, prev_state);
+               return ret;
+       }
+
+       /* If we have more SSIDs to scan, add a timeout so we scan them too */
+       if (ssid || !wpa_s->first_sched_scan) {
+               wpa_s->sched_scan_timed_out = 0;
+               eloop_register_timeout(wpa_s->sched_scan_timeout, 0,
+                                      wpa_supplicant_sched_scan_timeout,
+                                      wpa_s, NULL);
+               wpa_s->first_sched_scan = 0;
+               wpa_s->sched_scan_timeout /= 2;
+               wpa_s->sched_scan_interval *= 2;
+       }
+
+       return 0;
+}
+
+
+/**
  * wpa_supplicant_cancel_scan - Cancel a scheduled scan request
  * @wpa_s: Pointer to wpa_supplicant data
  *
@@ -511,11 +883,28 @@ void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
  */
 void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s)
 {
-       wpa_msg(wpa_s, MSG_DEBUG, "Cancelling scan request");
+       wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling scan request");
        eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
 }
 
 
+/**
+ * wpa_supplicant_cancel_sched_scan - Stop running scheduled scans
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to stop a periodic scheduled scan.
+ */
+void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s->sched_scanning)
+               return;
+
+       wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling sched scan");
+       eloop_cancel_timeout(wpa_supplicant_sched_scan_timeout, wpa_s, NULL);
+       wpa_supplicant_stop_sched_scan(wpa_s);
+}
+
+
 void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
                                    int scanning)
 {
@@ -619,15 +1008,62 @@ 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
+ * rule of thumb is that any SNR above 20 is good." This one
+ * http://www.cisco.com/en/US/tech/tk722/tk809/technologies_q_and_a_item09186a00805e9a96.shtml#qa23
+ * recommends 25 as a minimum SNR for 54 Mbps data rate. 30 is chosen here as a
+ * conservative value.
+ */
+#define GREAT_SNR 30
+
 /* Compare function for sorting scan results. Return >0 if @b is considered
  * better. */
 static int wpa_scan_result_compar(const void *a, const void *b)
 {
+#define IS_5GHZ(n) (n > 4000)
+#define MIN(a,b) a < b ? a : b
        struct wpa_scan_res **_wa = (void *) a;
        struct wpa_scan_res **_wb = (void *) b;
        struct wpa_scan_res *wa = *_wa;
        struct wpa_scan_res *wb = *_wb;
        int wpa_a, wpa_b, maxrate_a, maxrate_b;
+       int snr_a, snr_b;
 
        /* WPA/WPA2 support preferred */
        wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL ||
@@ -648,17 +1084,78 @@ static int wpa_scan_result_compar(const void *a, const void *b)
            (wb->caps & IEEE80211_CAP_PRIVACY) == 0)
                return -1;
 
-       /* best/max rate preferred if signal level close enough XXX */
-       if ((wa->level && wb->level && abs(wb->level - wa->level) < 5) ||
+       if ((wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) &&
+           !((wa->flags | wb->flags) & WPA_SCAN_NOISE_INVALID)) {
+               snr_a = MIN(wa->level - wa->noise, GREAT_SNR);
+               snr_b = MIN(wb->level - wb->noise, GREAT_SNR);
+       } else {
+               /* Not suitable information to calculate SNR, so use level */
+               snr_a = wa->level;
+               snr_b = wb->level;
+       }
+
+       /* best/max rate preferred if SNR close enough */
+        if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) ||
            (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {
                maxrate_a = wpa_scan_get_max_rate(wa);
                maxrate_b = wpa_scan_get_max_rate(wb);
                if (maxrate_a != maxrate_b)
                        return maxrate_b - maxrate_a;
+               if (IS_5GHZ(wa->freq) ^ IS_5GHZ(wb->freq))
+                       return IS_5GHZ(wa->freq) ? -1 : 1;
        }
 
        /* use freq for channel preference */
 
+       /* all things being equal, use SNR; if SNRs are
+        * identical, use quality values since some drivers may only report
+        * that value and leave the signal level zero */
+       if (snr_b == snr_a)
+               return wb->qual - wa->qual;
+       return snr_b - snr_a;
+#undef MIN
+#undef IS_5GHZ
+}
+
+
+#ifdef CONFIG_WPS
+/* Compare function for sorting scan results when searching a WPS AP for
+ * provisioning. Return >0 if @b is considered better. */
+static int wpa_scan_result_wps_compar(const void *a, const void *b)
+{
+       struct wpa_scan_res **_wa = (void *) a;
+       struct wpa_scan_res **_wb = (void *) b;
+       struct wpa_scan_res *wa = *_wa;
+       struct wpa_scan_res *wb = *_wb;
+       int uses_wps_a, uses_wps_b;
+       struct wpabuf *wps_a, *wps_b;
+       int res;
+
+       /* Optimization - check WPS IE existence before allocated memory and
+        * doing full reassembly. */
+       uses_wps_a = wpa_scan_get_vendor_ie(wa, WPS_IE_VENDOR_TYPE) != NULL;
+       uses_wps_b = wpa_scan_get_vendor_ie(wb, WPS_IE_VENDOR_TYPE) != NULL;
+       if (uses_wps_a && !uses_wps_b)
+               return -1;
+       if (!uses_wps_a && uses_wps_b)
+               return 1;
+
+       if (uses_wps_a && uses_wps_b) {
+               wps_a = wpa_scan_get_vendor_ie_multi(wa, WPS_IE_VENDOR_TYPE);
+               wps_b = wpa_scan_get_vendor_ie_multi(wb, WPS_IE_VENDOR_TYPE);
+               res = wps_ap_priority_compar(wps_a, wps_b);
+               wpabuf_free(wps_a);
+               wpabuf_free(wps_b);
+               if (res)
+                       return res;
+       }
+
+       /*
+        * Do not use current AP security policy as a sorting criteria during
+        * WPS provisioning step since the AP may get reconfigured at the
+        * completion of provisioning.
+        */
+
        /* all things being equal, use signal level; if signal levels are
         * identical, use quality values since some drivers may only report
         * that value and leave the signal level zero */
@@ -666,6 +1163,38 @@ static int wpa_scan_result_compar(const void *a, const void *b)
                return wb->qual - wa->qual;
        return wb->level - wa->level;
 }
+#endif /* CONFIG_WPS */
+
+
+static void dump_scan_res(struct wpa_scan_results *scan_res)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+       size_t i;
+
+       if (scan_res->res == NULL || scan_res->num == 0)
+               return;
+
+       wpa_printf(MSG_EXCESSIVE, "Sorted scan results");
+
+       for (i = 0; i < scan_res->num; i++) {
+               struct wpa_scan_res *r = scan_res->res[i];
+               if ((r->flags & (WPA_SCAN_LEVEL_DBM | WPA_SCAN_NOISE_INVALID))
+                   == WPA_SCAN_LEVEL_DBM) {
+                       int snr = r->level - r->noise;
+                       wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
+                                  "noise=%d level=%d snr=%d%s flags=0x%x",
+                                  MAC2STR(r->bssid), r->freq, r->qual,
+                                  r->noise, r->level, snr,
+                                  snr >= GREAT_SNR ? "*" : "", r->flags);
+               } else {
+                       wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
+                                  "noise=%d level=%d flags=0x%x",
+                                  MAC2STR(r->bssid), r->freq, r->qual,
+                                  r->noise, r->level, r->flags);
+               }
+       }
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
 
 
 /**
@@ -685,31 +1214,39 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
 {
        struct wpa_scan_results *scan_res;
        size_t i;
+       int (*compar)(const void *, const void *) = wpa_scan_result_compar;
 
-       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-               scan_res = ieee80211_sta_get_scan_results(wpa_s);
-       else
-               scan_res = wpa_drv_get_scan_results2(wpa_s);
+       scan_res = wpa_drv_get_scan_results2(wpa_s);
        if (scan_res == NULL) {
-               wpa_printf(MSG_DEBUG, "Failed to get scan results");
+               wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results");
                return NULL;
        }
 
+#ifdef CONFIG_WPS
+       if (wpas_wps_in_progress(wpa_s)) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Order scan results with WPS "
+                       "provisioning rules");
+               compar = wpa_scan_result_wps_compar;
+       }
+#endif /* CONFIG_WPS */
+
        qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *),
-             wpa_scan_result_compar);
-       wpa_printf(MSG_DEBUG,"current scan num is [%d]", scan_res->num);
+             compar);
+       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( scan_res->res[i]->level < 170)
+       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]);
        }
        wpa_bss_update_end(wpa_s, info, new_scan);
@@ -728,17 +1265,3 @@ int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s)
 
        return 0;
 }
-
-
-void wpa_scan_results_free(struct wpa_scan_results *res)
-{
-       size_t i;
-
-       if (res == NULL)
-               return;
-
-       for (i = 0; i < res->num; i++)
-               os_free(res->res[i]);
-       os_free(res->res);
-       os_free(res);
-}
index 441fdbb..7fb84e6 100644 (file)
 
 int wpa_supplicant_enabled_networks(struct wpa_config *conf);
 void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec);
+int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
+                                     int sec, int usec);
+int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
                                    int scanning);
 struct wpa_driver_scan_params;
@@ -32,6 +36,7 @@ const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
                                  u32 vendor_type);
 struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
                                             u32 vendor_type);
-void wpa_scan_results_free(struct wpa_scan_results *res);
+struct wpabuf * wpa_scan_get_vendor_ie_multi_beacon(
+       const struct wpa_scan_res *res, u32 vendor_type);
 
 #endif /* SCAN_H */
index 5604e97..c5e47d1 100644 (file)
@@ -15,6 +15,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "driver_i.h"
 #include "wpas_glue.h"
 #include "wps_supplicant.h"
+#include "p2p_supplicant.h"
 #include "notify.h"
-#include "blacklist.h"
 #include "bss.h"
 #include "scan.h"
 #include "sme.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);
+#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)
 {
@@ -46,8 +57,8 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
        int i, bssid_changed;
 
        if (bss == NULL) {
-               wpa_printf(MSG_ERROR, "SME: No scan result available for the "
-                          "network");
+               wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
+                       "the network");
                return;
        }
 
@@ -60,6 +71,7 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
        params.bssid = bss->bssid;
        params.ssid = bss->ssid;
        params.ssid_len = bss->ssid_len;
+       params.p2p = ssid->p2p_group;
 
        if (wpa_s->sme.ssid_len != params.ssid_len ||
            os_memcmp(wpa_s->sme.ssid, params.ssid, params.ssid_len) != 0)
@@ -80,12 +92,12 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
                }
        }
 #endif /* IEEE8021X_EAPOL */
-       wpa_printf(MSG_DEBUG, "Automatic auth_alg selection: 0x%x",
-                  params.auth_alg);
+       wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x",
+               params.auth_alg);
        if (ssid->auth_alg) {
                params.auth_alg = ssid->auth_alg;
-               wpa_printf(MSG_DEBUG, "Overriding auth_alg selection: 0x%x",
-                          params.auth_alg);
+               wpa_dbg(wpa_s, MSG_DEBUG, "Overriding auth_alg selection: "
+                       "0x%x", params.auth_alg);
        }
 
        for (i = 0; i < NUM_WEP_KEYS; i++) {
@@ -103,11 +115,7 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
 
        if ((wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
             wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
-           (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
-                              WPA_KEY_MGMT_FT_IEEE8021X |
-                              WPA_KEY_MGMT_FT_PSK |
-                              WPA_KEY_MGMT_IEEE8021X_SHA256 |
-                              WPA_KEY_MGMT_PSK_SHA256))) {
+           wpa_key_mgmt_wpa(ssid->key_mgmt)) {
                int try_opportunistic;
                try_opportunistic = ssid->proactive_key_caching &&
                        (ssid->proto & WPA_PROTO_RSN);
@@ -119,22 +127,18 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
                if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
                                              wpa_s->sme.assoc_req_ie,
                                              &wpa_s->sme.assoc_req_ie_len)) {
-                       wpa_printf(MSG_WARNING, "SME: Failed to set WPA key "
-                                  "management and encryption suites");
+                       wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
+                               "key management and encryption suites");
                        return;
                }
-       } else if (ssid->key_mgmt &
-                  (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
-                   WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK |
-                   WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 |
-                   WPA_KEY_MGMT_IEEE8021X_SHA256)) {
+       } else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
                wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
                if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
                                              wpa_s->sme.assoc_req_ie,
                                              &wpa_s->sme.assoc_req_ie_len)) {
-                       wpa_printf(MSG_WARNING, "SME: Failed to set WPA key "
-                                  "management and encryption suites (no scan "
-                                  "results)");
+                       wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
+                               "key management and encryption suites (no "
+                               "scan results)");
                        return;
                }
 #ifdef CONFIG_WPS
@@ -166,8 +170,7 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
                wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
        }
 
-       if (md && ssid->key_mgmt & (WPA_KEY_MGMT_FT_PSK |
-                                   WPA_KEY_MGMT_FT_IEEE8021X)) {
+       if (md && wpa_key_mgmt_ft(ssid->key_mgmt)) {
                if (wpa_s->sme.assoc_req_ie_len + 5 <
                    sizeof(wpa_s->sme.assoc_req_ie)) {
                        struct rsn_mdie *mdie;
@@ -185,8 +188,8 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
                if (wpa_s->sme.ft_used &&
                    os_memcmp(md, wpa_s->sme.mobility_domain, 2) == 0 &&
                    wpa_sm_has_ptk(wpa_s->wpa)) {
-                       wpa_printf(MSG_DEBUG, "SME: Trying to use FT "
-                                  "over-the-air");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying to use FT "
+                               "over-the-air");
                        params.auth_alg = WPA_AUTH_ALG_FT;
                        params.ie = wpa_s->sme.ft_ies;
                        params.ie_len = wpa_s->sme.ft_ies_len;
@@ -202,16 +205,50 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
                if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &_ie) == 0 &&
                    _ie.capabilities &
                    (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
-                       wpa_printf(MSG_DEBUG, "WPA: Selected AP supports MFP: "
-                                  "require MFP");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected AP supports "
+                               "MFP: require MFP");
                        wpa_s->sme.mfp = MGMT_FRAME_PROTECTION_REQUIRED;
                }
        }
 #endif /* CONFIG_IEEE80211W */
 
+#ifdef CONFIG_P2P
+       if (wpa_s->global->p2p) {
+               u8 *pos;
+               size_t len;
+               int res;
+               pos = wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len;
+               len = sizeof(wpa_s->sme.assoc_req_ie) -
+                       wpa_s->sme.assoc_req_ie_len;
+               res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len,
+                                           ssid->p2p_group);
+               if (res >= 0)
+                       wpa_s->sme.assoc_req_ie_len += res;
+       }
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_INTERWORKING
+       if (wpa_s->conf->interworking) {
+               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,
+                          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 */
+       }
+#endif /* CONFIG_INTERWORKING */
+
+       wpa_supplicant_cancel_sched_scan(wpa_s);
        wpa_supplicant_cancel_scan(wpa_s);
 
-       wpa_msg(wpa_s, MSG_INFO, "Trying to authenticate with " MACSTR
+       wpa_msg(wpa_s, MSG_INFO, "SME: Trying to authenticate with " MACSTR
                " (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid),
                wpa_ssid_txt(params.ssid, params.ssid_len), params.freq);
 
@@ -226,13 +263,15 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
 
        wpa_s->sme.auth_alg = params.auth_alg;
        if (wpa_drv_authenticate(wpa_s, &params) < 0) {
-               wpa_msg(wpa_s, MSG_INFO, "Authentication request to the "
+               wpa_msg(wpa_s, MSG_INFO, "SME: Authentication request to the "
                        "driver failed");
-               wpa_supplicant_req_scan(wpa_s, 1, 0);
+               wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+               wpas_connection_failed(wpa_s, bss->bssid);
                return;
        }
 
-       /* TODO: add timeout on authentication */
+       eloop_register_timeout(SME_AUTH_TIMEOUT, 0, sme_auth_timer, wpa_s,
+                              NULL);
 
        /*
         * Association will be started based on the authentication event from
@@ -246,46 +285,50 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
        struct wpa_ssid *ssid = wpa_s->current_ssid;
 
        if (ssid == NULL) {
-               wpa_printf(MSG_DEBUG, "SME: Ignore authentication event when "
-                          "network is not selected");
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: Ignore authentication event "
+                       "when network is not selected");
                return;
        }
 
        if (wpa_s->wpa_state != WPA_AUTHENTICATING) {
-               wpa_printf(MSG_DEBUG, "SME: Ignore authentication event when "
-                          "not in authenticating state");
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: Ignore authentication event "
+                       "when not in authenticating state");
                return;
        }
 
        if (os_memcmp(wpa_s->pending_bssid, data->auth.peer, ETH_ALEN) != 0) {
-               wpa_printf(MSG_DEBUG, "SME: Ignore authentication with "
-                          "unexpected peer " MACSTR,
-                          MAC2STR(data->auth.peer));
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: Ignore authentication with "
+                       "unexpected peer " MACSTR,
+                       MAC2STR(data->auth.peer));
                return;
        }
 
-       wpa_printf(MSG_DEBUG, "SME: Authentication response: peer=" MACSTR
-                  " auth_type=%d status_code=%d",
-                  MAC2STR(data->auth.peer), data->auth.auth_type,
-                  data->auth.status_code);
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication response: peer=" MACSTR
+               " auth_type=%d status_code=%d",
+               MAC2STR(data->auth.peer), data->auth.auth_type,
+               data->auth.status_code);
        wpa_hexdump(MSG_MSGDUMP, "SME: Authentication response IEs",
                    data->auth.ies, data->auth.ies_len);
 
+       eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
+
        if (data->auth.status_code != WLAN_STATUS_SUCCESS) {
-               wpa_printf(MSG_DEBUG, "SME: Authentication failed (status "
-                          "code %d)", data->auth.status_code);
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication failed (status "
+                       "code %d)", data->auth.status_code);
 
                if (data->auth.status_code !=
                    WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG ||
                    wpa_s->sme.auth_alg == data->auth.auth_type ||
-                   wpa_s->current_ssid->auth_alg == WPA_AUTH_ALG_LEAP)
+                   wpa_s->current_ssid->auth_alg == WPA_AUTH_ALG_LEAP) {
+                       wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
                        return;
+               }
 
                switch (data->auth.auth_type) {
                case WLAN_AUTH_OPEN:
                        wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_SHARED;
 
-                       wpa_printf(MSG_DEBUG, "SME: Trying SHARED auth");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying SHARED auth");
                        wpa_supplicant_associate(wpa_s, wpa_s->current_bss,
                                                 wpa_s->current_ssid);
                        return;
@@ -293,7 +336,7 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
                case WLAN_AUTH_SHARED_KEY:
                        wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_LEAP;
 
-                       wpa_printf(MSG_DEBUG, "SME: Trying LEAP auth");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying LEAP auth");
                        wpa_supplicant_associate(wpa_s, wpa_s->current_bss,
                                                 wpa_s->current_ssid);
                        return;
@@ -333,6 +376,8 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
        params.wpa_ie = wpa_s->sme.assoc_req_ie_len ?
                wpa_s->sme.assoc_req_ie : NULL;
        params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
+       params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher);
+       params.group_suite = cipher_suite2driver(wpa_s->group_cipher);
 #ifdef CONFIG_IEEE80211R
        if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) {
                params.wpa_ie = wpa_s->sme.ft_ies;
@@ -354,26 +399,37 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
        if (params.wpa_ie == NULL ||
            ieee802_11_parse_elems(params.wpa_ie, params.wpa_ie_len, &elems, 0)
            < 0) {
-               wpa_printf(MSG_DEBUG, "SME: Could not parse own IEs?!");
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: Could not parse own IEs?!");
                os_memset(&elems, 0, sizeof(elems));
        }
-       if (elems.rsn_ie)
+       if (elems.rsn_ie) {
+               params.wpa_proto = WPA_PROTO_RSN;
                wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.rsn_ie - 2,
                                        elems.rsn_ie_len + 2);
-       else if (elems.wpa_ie)
+       } else if (elems.wpa_ie) {
+               params.wpa_proto = WPA_PROTO_WPA;
                wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.wpa_ie - 2,
                                        elems.wpa_ie_len + 2);
-       else
+       else
                wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+       if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group)
+               params.p2p = 1;
+
+       if (wpa_s->parent->set_sta_uapsd)
+               params.uapsd = wpa_s->parent->sta_uapsd;
+       else
+               params.uapsd = -1;
 
        if (wpa_drv_associate(wpa_s, &params) < 0) {
-               wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
-                       "failed");
-               wpa_supplicant_req_scan(wpa_s, 5, 0);
+               wpa_msg(wpa_s, MSG_INFO, "SME: Association request to the "
+                       "driver failed");
+               wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+               os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
                return;
        }
 
-       /* TODO: add timeout on association */
+       eloop_register_timeout(SME_ASSOC_TIMEOUT, 0, sme_assoc_timer, wpa_s,
+                              NULL);
 }
 
 
@@ -381,7 +437,7 @@ int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
                      const u8 *ies, size_t ies_len)
 {
        if (md == NULL || ies == NULL) {
-               wpa_printf(MSG_DEBUG, "SME: Remove mobility domain");
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: Remove mobility domain");
                os_free(wpa_s->sme.ft_ies);
                wpa_s->sme.ft_ies = NULL;
                wpa_s->sme.ft_ies_len = 0;
@@ -401,90 +457,303 @@ int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
 }
 
 
-void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
-                           union wpa_event_data *data)
+static void sme_deauth(struct wpa_supplicant *wpa_s)
 {
        int bssid_changed;
-       int timeout = 5000;
-
-       wpa_printf(MSG_DEBUG, "SME: Association with " MACSTR " failed: "
-                  "status code %d", MAC2STR(wpa_s->pending_bssid),
-                  data->assoc_reject.status_code);
 
        bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
 
-       /*
-        * For now, unconditionally terminate the previous authentication. In
-        * theory, this should not be needed, but mac80211 gets quite confused
-        * if the authentication is left pending.. Some roaming cases might
-        * benefit from using the previous authentication, so this could be
-        * optimized in the future.
-        */
        if (wpa_drv_deauthenticate(wpa_s, wpa_s->pending_bssid,
                                   WLAN_REASON_DEAUTH_LEAVING) < 0) {
-               wpa_msg(wpa_s, MSG_INFO,
-                       "Deauth request to the driver failed");
+               wpa_msg(wpa_s, MSG_INFO, "SME: Deauth request to the driver "
+                       "failed");
        }
        wpa_s->sme.prev_bssid_set = 0;
 
-       if (wpa_blacklist_add(wpa_s, wpa_s->pending_bssid) == 0) {
-               struct wpa_blacklist *b;
-               b = wpa_blacklist_get(wpa_s, wpa_s->pending_bssid);
-               if (b && b->count < 3) {
-                       /*
-                        * Speed up next attempt if there could be other APs
-                        * that could accept association.
-                        */
-                       timeout = 100;
-               }
-       }
+       wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
        wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
        os_memset(wpa_s->bssid, 0, ETH_ALEN);
        os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
        if (bssid_changed)
                wpas_notify_bssid_changed(wpa_s);
+}
+
+
+void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
+                           union wpa_event_data *data)
+{
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Association with " MACSTR " failed: "
+               "status code %d", MAC2STR(wpa_s->pending_bssid),
+               data->assoc_reject.status_code);
+
+       eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
 
        /*
-        * TODO: if more than one possible AP is available in scan results,
-        * could try the other ones before requesting a new scan.
+        * For now, unconditionally terminate the previous authentication. In
+        * theory, this should not be needed, but mac80211 gets quite confused
+        * if the authentication is left pending.. Some roaming cases might
+        * benefit from using the previous authentication, so this could be
+        * optimized in the future.
         */
-       wpa_supplicant_req_scan(wpa_s, timeout / 1000,
-                               1000 * (timeout % 1000));
+       sme_deauth(wpa_s);
 }
 
 
 void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s,
                              union wpa_event_data *data)
 {
-       wpa_printf(MSG_DEBUG, "SME: Authentication timed out");
-       wpa_supplicant_req_scan(wpa_s, 5, 0);
+       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);
 }
 
 
 void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
                               union wpa_event_data *data)
 {
-       wpa_printf(MSG_DEBUG, "SME: Association timed out");
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Association timed out");
+       wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
        wpa_supplicant_mark_disassoc(wpa_s);
-       wpa_supplicant_req_scan(wpa_s, 5, 0);
 }
 
 
 void sme_event_disassoc(struct wpa_supplicant *wpa_s,
                        union wpa_event_data *data)
 {
-       wpa_printf(MSG_DEBUG, "SME: Disassociation event received");
-       if (wpa_s->sme.prev_bssid_set &&
-           !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)) {
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Disassociation event received");
+       if (wpa_s->sme.prev_bssid_set) {
                /*
                 * cfg80211/mac80211 can get into somewhat confused state if
                 * the AP only disassociates us and leaves us in authenticated
                 * state. For now, force the state to be cleared to avoid
                 * confusing errors if we try to associate with the AP again.
                 */
-               wpa_printf(MSG_DEBUG, "SME: Deauthenticate to clear driver "
-                          "state");
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: Deauthenticate to clear "
+                       "driver state");
                wpa_drv_deauthenticate(wpa_s, wpa_s->sme.prev_bssid,
                                       WLAN_REASON_DEAUTH_LEAVING);
        }
 }
+
+
+static void sme_auth_timer(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       if (wpa_s->wpa_state == WPA_AUTHENTICATING) {
+               wpa_msg(wpa_s, MSG_DEBUG, "SME: Authentication timeout");
+               sme_deauth(wpa_s);
+       }
+}
+
+
+static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       if (wpa_s->wpa_state == WPA_ASSOCIATING) {
+               wpa_msg(wpa_s, MSG_DEBUG, "SME: Association timeout");
+               sme_deauth(wpa_s);
+       }
+}
+
+
+void sme_state_changed(struct wpa_supplicant *wpa_s)
+{
+       /* Make sure timers are cleaned up appropriately. */
+       if (wpa_s->wpa_state != WPA_ASSOCIATING)
+               eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
+       if (wpa_s->wpa_state != WPA_AUTHENTICATING)
+               eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
+}
+
+
+void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
+                                      const u8 *prev_pending_bssid)
+{
+       /*
+        * mac80211-workaround to force deauth on failed auth cmd,
+        * requires us to remain in authenticating state to allow the
+        * second authentication attempt to be continued properly.
+        */
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Allow pending authentication "
+               "to proceed after disconnection event");
+       wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
+       os_memcpy(wpa_s->pending_bssid, prev_pending_bssid, ETH_ALEN);
+
+       /*
+        * Re-arm authentication timer in case auth fails for whatever reason.
+        */
+       eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
+       eloop_register_timeout(SME_AUTH_TIMEOUT, 0, sme_auth_timer, wpa_s,
+                              NULL);
+}
+
+
+void sme_deinit(struct wpa_supplicant *wpa_s)
+{
+       os_free(wpa_s->sme.ft_ies);
+       wpa_s->sme.ft_ies = NULL;
+       wpa_s->sme.ft_ies_len = 0;
+#ifdef CONFIG_IEEE80211W
+       sme_stop_sa_query(wpa_s);
+#endif /* CONFIG_IEEE80211W */
+
+       eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
+       eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
+}
+
+
+#ifdef CONFIG_IEEE80211W
+
+static const unsigned int sa_query_max_timeout = 1000;
+static const unsigned int sa_query_retry_timeout = 201;
+
+static int sme_check_sa_query_timeout(struct wpa_supplicant *wpa_s)
+{
+       u32 tu;
+       struct os_time now, passed;
+       os_get_time(&now);
+       os_time_sub(&now, &wpa_s->sme.sa_query_start, &passed);
+       tu = (passed.sec * 1000000 + passed.usec) / 1024;
+       if (sa_query_max_timeout < tu) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: SA Query timed out");
+               sme_stop_sa_query(wpa_s);
+               wpa_supplicant_deauthenticate(
+                       wpa_s, WLAN_REASON_PREV_AUTH_NOT_VALID);
+               return 1;
+       }
+
+       return 0;
+}
+
+
+static void sme_send_sa_query_req(struct wpa_supplicant *wpa_s,
+                                 const u8 *trans_id)
+{
+       u8 req[2 + WLAN_SA_QUERY_TR_ID_LEN];
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Sending SA Query Request to "
+               MACSTR, MAC2STR(wpa_s->bssid));
+       wpa_hexdump(MSG_DEBUG, "SME: SA Query Transaction ID",
+                   trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+       req[0] = WLAN_ACTION_SA_QUERY;
+       req[1] = WLAN_SA_QUERY_REQUEST;
+       os_memcpy(req + 2, trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+       if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+                               wpa_s->own_addr, wpa_s->bssid,
+                               req, sizeof(req), 0) < 0)
+               wpa_msg(wpa_s, MSG_INFO, "SME: Failed to send SA Query "
+                       "Request");
+}
+
+
+static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       unsigned int timeout, sec, usec;
+       u8 *trans_id, *nbuf;
+
+       if (wpa_s->sme.sa_query_count > 0 &&
+           sme_check_sa_query_timeout(wpa_s))
+               return;
+
+       nbuf = os_realloc(wpa_s->sme.sa_query_trans_id,
+                         (wpa_s->sme.sa_query_count + 1) *
+                         WLAN_SA_QUERY_TR_ID_LEN);
+       if (nbuf == NULL)
+               return;
+       if (wpa_s->sme.sa_query_count == 0) {
+               /* Starting a new SA Query procedure */
+               os_get_time(&wpa_s->sme.sa_query_start);
+       }
+       trans_id = nbuf + wpa_s->sme.sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
+       wpa_s->sme.sa_query_trans_id = nbuf;
+       wpa_s->sme.sa_query_count++;
+
+       os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+       timeout = sa_query_retry_timeout;
+       sec = ((timeout / 1000) * 1024) / 1000;
+       usec = (timeout % 1000) * 1024;
+       eloop_register_timeout(sec, usec, sme_sa_query_timer, wpa_s, NULL);
+
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Association SA Query attempt %d",
+               wpa_s->sme.sa_query_count);
+
+       sme_send_sa_query_req(wpa_s, trans_id);
+}
+
+
+static void sme_start_sa_query(struct wpa_supplicant *wpa_s)
+{
+       sme_sa_query_timer(wpa_s, NULL);
+}
+
+
+static void sme_stop_sa_query(struct wpa_supplicant *wpa_s)
+{
+       eloop_cancel_timeout(sme_sa_query_timer, wpa_s, NULL);
+       os_free(wpa_s->sme.sa_query_trans_id);
+       wpa_s->sme.sa_query_trans_id = NULL;
+       wpa_s->sme.sa_query_count = 0;
+}
+
+
+void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
+                                const u8 *da, u16 reason_code)
+{
+       struct wpa_ssid *ssid;
+
+       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
+               return;
+       if (wpa_s->wpa_state != WPA_COMPLETED)
+               return;
+       ssid = wpa_s->current_ssid;
+       if (ssid == NULL || ssid->ieee80211w == 0)
+               return;
+       if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0)
+               return;
+       if (reason_code != WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA &&
+           reason_code != WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA)
+               return;
+       if (wpa_s->sme.sa_query_count > 0)
+               return;
+
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Unprotected disconnect dropped - "
+               "possible AP/STA state mismatch - trigger SA Query");
+       sme_start_sa_query(wpa_s);
+}
+
+
+void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
+                    const u8 *data, size_t len)
+{
+       int i;
+
+       if (wpa_s->sme.sa_query_trans_id == NULL ||
+           len < 1 + WLAN_SA_QUERY_TR_ID_LEN ||
+           data[0] != WLAN_SA_QUERY_RESPONSE)
+               return;
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Received SA Query response from "
+               MACSTR " (trans_id %02x%02x)", MAC2STR(sa), data[1], data[2]);
+
+       if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0)
+               return;
+
+       for (i = 0; i < wpa_s->sme.sa_query_count; i++) {
+               if (os_memcmp(wpa_s->sme.sa_query_trans_id +
+                             i * WLAN_SA_QUERY_TR_ID_LEN,
+                             data + 1, WLAN_SA_QUERY_TR_ID_LEN) == 0)
+                       break;
+       }
+
+       if (i >= wpa_s->sme.sa_query_count) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: No matching SA Query "
+                       "transaction identifier found");
+               return;
+       }
+
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Reply to pending SA Query received "
+               "from " MACSTR, MAC2STR(sa));
+       sme_stop_sa_query(wpa_s);
+}
+
+#endif /* CONFIG_IEEE80211W */
index 3ec8cc9..a59b38d 100644 (file)
@@ -32,6 +32,14 @@ void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
                               union wpa_event_data *data);
 void sme_event_disassoc(struct wpa_supplicant *wpa_s,
                        union wpa_event_data *data);
+void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
+                                const u8 *da, u16 reason_code);
+void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
+                    const u8 *data, size_t len);
+void sme_state_changed(struct wpa_supplicant *wpa_s);
+void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
+                                      const u8 *prev_pending_bssid);
+void sme_deinit(struct wpa_supplicant *wpa_s);
 
 #else /* CONFIG_SME */
 
@@ -73,6 +81,26 @@ static inline void sme_event_disassoc(struct wpa_supplicant *wpa_s,
 {
 }
 
+static inline void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s,
+                                              const u8 *sa, const u8 *da,
+                                              u16 reason_code)
+{
+}
+
+static inline void sme_state_changed(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void
+sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
+                                 const u8 *prev_pending_bssid)
+{
+}
+
+static inline void sme_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
 #endif /* CONFIG_SME */
 
 #endif /* SME_H */
index 217908e..e018e05 100644 (file)
@@ -15,7 +15,7 @@ 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
+SOURCE         drivers.c driver_common.c
 SOURCEPATH     ..\..\src\common
 SOURCE         wpa_common.c
 SOURCEPATH     ..\..\src\utils
diff --git a/wpa_supplicant/systemd/wpa_supplicant-nl80211@.service.in b/wpa_supplicant/systemd/wpa_supplicant-nl80211@.service.in
new file mode 100644 (file)
index 0000000..4d9c146
--- /dev/null
@@ -0,0 +1,13 @@
+[Unit]
+Description=WPA supplicant daemon (interface- and nl80211 driver-specific version)
+Requires=sys-subsystem-net-devices-%i.device
+After=sys-subsystem-net-devices-%i.device
+
+# NetworkManager users will probably want the dbus version instead.
+
+[Service]
+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
diff --git a/wpa_supplicant/systemd/wpa_supplicant-wired@.service.in b/wpa_supplicant/systemd/wpa_supplicant-wired@.service.in
new file mode 100644 (file)
index 0000000..f2e7f11
--- /dev/null
@@ -0,0 +1,13 @@
+[Unit]
+Description=WPA supplicant daemon (interface- and wired driver-specific version)
+Requires=sys-subsystem-net-devices-%i.device
+After=sys-subsystem-net-devices-%i.device
+
+# NetworkManager users will probably want the dbus version instead.
+
+[Service]
+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
diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.in b/wpa_supplicant/systemd/wpa_supplicant.service.in
new file mode 100644 (file)
index 0000000..5b947ac
--- /dev/null
@@ -0,0 +1,11 @@
+[Unit]
+Description=WPA supplicant
+
+[Service]
+Type=dbus
+BusName=fi.epitest.hostap.WPASupplicant
+ExecStart=@BINDIR@/wpa_supplicant -u
+
+[Install]
+WantedBy=network.target
+Alias=dbus-fi.epitest.hostap.WPASupplicant.service
diff --git a/wpa_supplicant/systemd/wpa_supplicant@.service.in b/wpa_supplicant/systemd/wpa_supplicant@.service.in
new file mode 100644 (file)
index 0000000..0340b4d
--- /dev/null
@@ -0,0 +1,13 @@
+[Unit]
+Description=WPA supplicant daemon (interface-specific version)
+Requires=sys-subsystem-net-devices-%i.device
+After=sys-subsystem-net-devices-%i.device
+
+# NetworkManager users will probably want the dbus version instead.
+
+[Service]
+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
diff --git a/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj b/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj
new file mode 100755 (executable)
index 0000000..38b29c4
--- /dev/null
@@ -0,0 +1,469 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="eapol_test"\r
+       ProjectGUID="{0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}"\r
+       RootNamespace="eapol_test"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="$(SolutionDir)$(ConfigurationName)"\r
+                       IntermediateDirectory="$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;C:\dev\WpdPack\include;C:\dev\openssl\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="3"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               DisableSpecificWarnings="4244;4267;4311"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="$(SolutionDir)$(ConfigurationName)"\r
+                       IntermediateDirectory="$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="1"\r
+                       WholeProgramOptimization="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;C:\dev\WpdPack\include;C:\dev\openssl\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"\r
+                               RuntimeLibrary="2"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               DisableSpecificWarnings="4244;4267;4311"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib"\r
+                               LinkIncremental="1"\r
+                               AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\aes-cbc.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\aes-ctr.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\aes-eax.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\aes-encblock.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\aes-omac1.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\aes-unwrap.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\aes-wrap.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\utils\base64.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\blacklist.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\bss.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_common\chap.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\utils\common.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\config.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\config_file.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\crypto_openssl.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\ctrl_iface.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\ctrl_iface_named_pipe.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\drivers\driver_common.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_aka.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_common\eap_common.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_gtc.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_leap.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_md5.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_methods.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_mschapv2.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_otp.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_peap.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_common\eap_peap_common.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\eap_register.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_sim.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_common\eap_sim_common.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_tls.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_tls_common.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_tnc.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_ttls.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eapol_supp\eapol_supp_sm.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\eapol_test.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\utils\eloop_win.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\events.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\fips_prf_openssl.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\utils\ip_addr.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\l2_packet\l2_packet_winpcap.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\md5.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\ms_funcs.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\mschapv2.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\notify.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\utils\os_win32.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\utils\pcsc_funcs.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\rsn_supp\peerkey.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\rsn_supp\pmksa_cache.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\rsn_supp\preauth.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\radius\radius.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\radius\radius_client.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\scan.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\sha1.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\sha1-pbkdf2.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\sha1-tlsprf.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\tls_openssl.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\tncc.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\rsn_supp\wpa.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\common\wpa_common.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\utils\wpa_debug.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\rsn_supp\wpa_ie.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\wpa_supplicant.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\utils\wpabuf.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\wpas_glue.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj b/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj
new file mode 100755 (executable)
index 0000000..d2de768
--- /dev/null
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="wpa_cli"\r
+       ProjectGUID="{E3A7B181-22CC-4DA3-8410-6AD69879A9EC}"\r
+       RootNamespace="wpa_cli"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="$(SolutionDir)$(ConfigurationName)"\r
+                       IntermediateDirectory="$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="0"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..\..\..\src;..\..\..\src\utils"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="3"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               DisableSpecificWarnings="4244;4267"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="ws2_32.lib"\r
+                               LinkIncremental="2"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="$(SolutionDir)$(ConfigurationName)"\r
+                       IntermediateDirectory="$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="0"\r
+                       WholeProgramOptimization="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="..\..\..\src;..\..\..\src\utils"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"\r
+                               RuntimeLibrary="2"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               DisableSpecificWarnings="4244;4267"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="ws2_32.lib"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath="..\..\..\src\utils\common.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\utils\os_win32.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\wpa_cli.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\common\wpa_ctrl.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj b/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj
new file mode 100755 (executable)
index 0000000..b107842
--- /dev/null
@@ -0,0 +1,232 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="wpa_passphrase"\r
+       ProjectGUID="{ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}"\r
+       RootNamespace="wpa_passphrase"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="$(SolutionDir)$(ConfigurationName)"\r
+                       IntermediateDirectory="$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="0"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..\..\..\src;..\..\..\src\utils;C:\dev\openssl\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="3"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               DisableSpecificWarnings="4244;4267"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="ws2_32.lib"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories=""\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="$(SolutionDir)$(ConfigurationName)"\r
+                       IntermediateDirectory="$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="0"\r
+                       WholeProgramOptimization="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="..\..\..\src;..\..\..\src\utils;C:\dev\openssl\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"\r
+                               RuntimeLibrary="2"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               DisableSpecificWarnings="4244;4267"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="ws2_32.lib"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath="..\..\..\src\utils\common.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\md5.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\md5-internal.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\utils\os_win32.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\sha1.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\sha1-internal.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\sha1-pbkdf2.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\wpa_passphrase.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj b/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj
new file mode 100755 (executable)
index 0000000..e3886b7
--- /dev/null
@@ -0,0 +1,457 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="wpa_supplicant"\r
+       ProjectGUID="{8BCFDA77-AEDC-4168-8897-5B73105BBB87}"\r
+       RootNamespace="wpa_supplicant"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="$(SolutionDir)$(ConfigurationName)"\r
+                       IntermediateDirectory="$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="0"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;C:\dev\WpdPack\include;C:\dev\openssl\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="3"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               DisableSpecificWarnings="4244;4267;4311"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="wbemuuid.lib ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="$(SolutionDir)$(ConfigurationName)"\r
+                       IntermediateDirectory="$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="0"\r
+                       WholeProgramOptimization="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;C:\dev\WpdPack\include;C:\dev\openssl\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"\r
+                               RuntimeLibrary="2"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               DisableSpecificWarnings="4244;4267;4311"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="wbemuuid.lib ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib"\r
+                               LinkIncremental="1"\r
+                               AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\aes-cbc.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\aes-ctr.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\aes-eax.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\aes-encblock.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\aes-omac1.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\aes-unwrap.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\aes-wrap.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\utils\base64.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\blacklist.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\bss.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_common\chap.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\utils\common.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\config.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\config_file.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\crypto_openssl.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\ctrl_iface.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\ctrl_iface_named_pipe.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\drivers\driver_common.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\drivers\driver_ndis.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\drivers\driver_ndis_.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\drivers\drivers.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_common\eap_common.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_gtc.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_leap.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_md5.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_methods.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_mschapv2.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_otp.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_peap.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_common\eap_peap_common.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\eap_register.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_tls.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_tls_common.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_tnc.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\eap_ttls.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eapol_supp\eapol_supp_sm.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\utils\eloop_win.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\events.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\l2_packet\l2_packet_winpcap.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\main.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\md5.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\ms_funcs.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\mschapv2.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\drivers\ndis_events.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\notify.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\utils\os_win32.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\utils\pcsc_funcs.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\rsn_supp\peerkey.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\rsn_supp\pmksa_cache.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\rsn_supp\preauth.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\scan.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\sha1.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\sha1-pbkdf2.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\sha1-tlsprf.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\crypto\tls_openssl.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\eap_peer\tncc.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\rsn_supp\wpa.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\common\wpa_common.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\utils\wpa_debug.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\rsn_supp\wpa_ie.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\wpa_supplicant.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\utils\wpabuf.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\wpas_glue.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
index 4d402e5..1034891 100755 (executable)
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath="..\..\..\src\drivers\driver_common.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath="..\..\..\src\drivers\driver_ndis.c"\r
                                >\r
                        </File>\r
old mode 100644 (file)
new mode 100755 (executable)
index 162a0b8..6ca7939 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * 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
 #ifdef CONFIG_CTRL_IFACE_UNIX
 #include <dirent.h>
 #endif /* CONFIG_CTRL_IFACE_UNIX */
-#ifdef CONFIG_READLINE
-#include <readline/readline.h>
-#include <readline/history.h>
-#endif /* CONFIG_READLINE */
-#ifdef CONFIG_WPA_CLI_FORK
-#include <sys/wait.h>
-#endif /* CONFIG_WPA_CLI_FORK */
 
 #include "common/wpa_ctrl.h"
-#include "common.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/edit.h"
+#include "utils/list.h"
 #include "common/version.h"
+#ifdef ANDROID
+#include <cutils/properties.h>
+#endif /* ANDROID */
 
 
 static const char *wpa_cli_version =
 "wpa_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi> and contributors";
 
 
 static const char *wpa_cli_license =
@@ -91,22 +90,32 @@ static const char *wpa_cli_full_license =
 
 static struct wpa_ctrl *ctrl_conn;
 static struct wpa_ctrl *mon_conn;
-#ifdef CONFIG_WPA_CLI_FORK
-static pid_t mon_pid = 0;
-#endif /* CONFIG_WPA_CLI_FORK */
 static int wpa_cli_quit = 0;
 static int wpa_cli_attached = 0;
 static int wpa_cli_connected = 0;
 static int wpa_cli_last_id = 0;
-static const char *ctrl_iface_dir = "/var/run/wpa_supplicant";
+#ifndef CONFIG_CTRL_IFACE_DIR
+#define CONFIG_CTRL_IFACE_DIR "/var/run/wpa_supplicant"
+#endif /* CONFIG_CTRL_IFACE_DIR */
+static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
 static char *ctrl_ifname = NULL;
 static const char *pid_file = NULL;
 static const char *action_file = NULL;
 static int ping_interval = 5;
 static int interactive = 0;
 
+struct cli_txt_entry {
+       struct dl_list list;
+       char *txt;
+};
+
+static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */
+static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */
+static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
 
-static void print_help();
+
+static void print_help(void);
+static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx);
 
 
 static void usage(void)
@@ -121,63 +130,195 @@ static void usage(void)
               "events from\n"
               "       wpa_supplicant\n"
               "  -B = run a daemon in the background\n"
-              "  default path: /var/run/wpa_supplicant\n"
+              "  default path: " CONFIG_CTRL_IFACE_DIR "\n"
               "  default interface: first interface found in socket path\n");
        print_help();
 }
 
 
-#ifdef CONFIG_WPA_CLI_FORK
-static int in_query = 0;
+static void cli_txt_list_free(struct cli_txt_entry *e)
+{
+       dl_list_del(&e->list);
+       os_free(e->txt);
+       os_free(e);
+}
+
 
-static void wpa_cli_monitor_sig(int sig)
+static void cli_txt_list_flush(struct dl_list *list)
 {
-       if (sig == SIGUSR1)
-               in_query = 1;
-       else if (sig == SIGUSR2)
-               in_query = 0;
+       struct cli_txt_entry *e;
+       while ((e = dl_list_first(list, struct cli_txt_entry, list)))
+               cli_txt_list_free(e);
 }
 
-static void wpa_cli_monitor(void)
+
+static struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list,
+                                              const char *txt)
 {
-       char buf[256];
-       size_t len = sizeof(buf) - 1;
-       struct timeval tv;
-       fd_set rfds;
+       struct cli_txt_entry *e;
+       dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
+               if (os_strcmp(e->txt, txt) == 0)
+                       return e;
+       }
+       return NULL;
+}
 
-       signal(SIGUSR1, wpa_cli_monitor_sig);
-       signal(SIGUSR2, wpa_cli_monitor_sig);
 
-       while (mon_conn) {
-               int s = wpa_ctrl_get_fd(mon_conn);
-               tv.tv_sec = 5;
-               tv.tv_usec = 0;
-               FD_ZERO(&rfds);
-               FD_SET(s, &rfds);
-               if (select(s + 1, &rfds, NULL, NULL, &tv) < 0) {
-                       if (errno == EINTR)
-                               continue;
-                       perror("select");
-                       break;
-               }
-               if (mon_conn == NULL)
+static void cli_txt_list_del(struct dl_list *txt_list, const char *txt)
+{
+       struct cli_txt_entry *e;
+       e = cli_txt_list_get(txt_list, txt);
+       if (e)
+               cli_txt_list_free(e);
+}
+
+
+static void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt)
+{
+       u8 addr[ETH_ALEN];
+       char buf[18];
+       if (hwaddr_aton(txt, addr) < 0)
+               return;
+       os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+       cli_txt_list_del(txt_list, buf);
+}
+
+
+#ifdef CONFIG_P2P
+static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt)
+{
+       const char *end;
+       char *buf;
+       end = os_strchr(txt, ' ');
+       if (end == NULL)
+               end = txt + os_strlen(txt);
+       buf = os_malloc(end - txt + 1);
+       if (buf == NULL)
+               return;
+       os_memcpy(buf, txt, end - txt);
+       buf[end - txt] = '\0';
+       cli_txt_list_del(txt_list, buf);
+       os_free(buf);
+}
+#endif /* CONFIG_P2P */
+
+
+static int cli_txt_list_add(struct dl_list *txt_list, const char *txt)
+{
+       struct cli_txt_entry *e;
+       e = cli_txt_list_get(txt_list, txt);
+       if (e)
+               return 0;
+       e = os_zalloc(sizeof(*e));
+       if (e == NULL)
+               return -1;
+       e->txt = os_strdup(txt);
+       if (e->txt == NULL) {
+               os_free(e);
+               return -1;
+       }
+       dl_list_add(txt_list, &e->list);
+       return 0;
+}
+
+
+#ifdef CONFIG_P2P
+static int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt)
+{
+       u8 addr[ETH_ALEN];
+       char buf[18];
+       if (hwaddr_aton(txt, addr) < 0)
+               return -1;
+       os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+       return cli_txt_list_add(txt_list, buf);
+}
+
+
+static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt)
+{
+       const char *end;
+       char *buf;
+       int ret;
+       end = os_strchr(txt, ' ');
+       if (end == NULL)
+               end = txt + os_strlen(txt);
+       buf = os_malloc(end - txt + 1);
+       if (buf == NULL)
+               return -1;
+       os_memcpy(buf, txt, end - txt);
+       buf[end - txt] = '\0';
+       ret = cli_txt_list_add(txt_list, buf);
+       os_free(buf);
+       return ret;
+}
+#endif /* CONFIG_P2P */
+
+
+static char ** cli_txt_list_array(struct dl_list *txt_list)
+{
+       unsigned int i, count = dl_list_len(txt_list);
+       char **res;
+       struct cli_txt_entry *e;
+
+       res = os_zalloc((count + 1) * sizeof(char *));
+       if (res == NULL)
+               return NULL;
+
+       i = 0;
+       dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
+               res[i] = os_strdup(e->txt);
+               if (res[i] == NULL)
                        break;
-               if (FD_ISSET(s, &rfds)) {
-                       len = sizeof(buf) - 1;
-                       int res = wpa_ctrl_recv(mon_conn, buf, &len);
-                       if (res < 0) {
-                               perror("wpa_ctrl_recv");
-                               break;
-                       }
-                       buf[len] = '\0';
-                       if (in_query)
-                               printf("\r");
-                       printf("%s\n", buf);
-                       kill(getppid(), SIGUSR1);
+               i++;
+       }
+
+       return res;
+}
+
+
+static int get_cmd_arg_num(const char *str, int pos)
+{
+       int arg = 0, i;
+
+       for (i = 0; i <= pos; i++) {
+               if (str[i] != ' ') {
+                       arg++;
+                       while (i <= pos && str[i] != ' ')
+                               i++;
                }
        }
+
+       if (arg > 0)
+               arg--;
+       return arg;
+}
+
+
+static int str_starts(const char *src, const char *match)
+{
+       return os_strncmp(src, match, os_strlen(match)) == 0;
+}
+
+
+static int wpa_cli_show_event(const char *event)
+{
+       const char *start;
+
+       start = os_strchr(event, '>');
+       if (start == NULL)
+               return 1;
+
+       start++;
+       /*
+        * Skip BSS added/removed events since they can be relatively frequent
+        * and are likely of not much use for an interactive user.
+        */
+       if (str_starts(start, WPA_EVENT_BSS_ADDED) ||
+           str_starts(start, WPA_EVENT_BSS_REMOVED))
+               return 0;
+
+       return 1;
 }
-#endif /* CONFIG_WPA_CLI_FORK */
 
 
 static int wpa_cli_open_connection(const char *ifname, int attach)
@@ -192,20 +333,31 @@ static int wpa_cli_open_connection(const char *ifname, int attach)
        else
                mon_conn = NULL;
 #else /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
-       char *cfile;
+       char *cfile = NULL;
        int flen, res;
 
        if (ifname == NULL)
                return -1;
 
-       flen = os_strlen(ctrl_iface_dir) + os_strlen(ifname) + 2;
-       cfile = os_malloc(flen);
-       if (cfile == NULL)
-               return -1L;
-       res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
-       if (res < 0 || res >= flen) {
-               os_free(cfile);
-               return -1;
+#ifdef ANDROID
+       if (access(ctrl_iface_dir, F_OK) < 0) {
+               cfile = os_strdup(ifname);
+               if (cfile == NULL)
+                       return -1;
+       }
+#endif /* ANDROID */
+
+       if (cfile == NULL) {
+               flen = os_strlen(ctrl_iface_dir) + os_strlen(ifname) + 2;
+               cfile = os_malloc(flen);
+               if (cfile == NULL)
+                       return -1;
+               res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir,
+                                 ifname);
+               if (res < 0 || res >= flen) {
+                       os_free(cfile);
+                       return -1;
+               }
        }
 
        ctrl_conn = wpa_ctrl_open(cfile);
@@ -224,26 +376,15 @@ static int wpa_cli_open_connection(const char *ifname, int attach)
        if (mon_conn) {
                if (wpa_ctrl_attach(mon_conn) == 0) {
                        wpa_cli_attached = 1;
+                       if (interactive)
+                               eloop_register_read_sock(
+                                       wpa_ctrl_get_fd(mon_conn),
+                                       wpa_cli_mon_receive, NULL, NULL);
                } else {
                        printf("Warning: Failed to attach to "
                               "wpa_supplicant.\n");
                        return -1;
                }
-
-#ifdef CONFIG_WPA_CLI_FORK
-               {
-                       pid_t p = fork();
-                       if (p < 0) {
-                               perror("fork");
-                               return -1;
-                       }
-                       if (p == 0) {
-                               wpa_cli_monitor();
-                               exit(0);
-                       } else
-                               mon_pid = p;
-               }
-#endif /* CONFIG_WPA_CLI_FORK */
        }
 
        return 0;
@@ -255,15 +396,6 @@ static void wpa_cli_close_connection(void)
        if (ctrl_conn == NULL)
                return;
 
-#ifdef CONFIG_WPA_CLI_FORK
-       if (mon_pid) {
-               int status;
-               kill(mon_pid, SIGPIPE);
-               wait(&status);
-               mon_pid = 0;
-       }
-#endif /* CONFIG_WPA_CLI_FORK */
-
        if (wpa_cli_attached) {
                wpa_ctrl_detach(interactive ? mon_conn : ctrl_conn);
                wpa_cli_attached = 0;
@@ -271,6 +403,7 @@ static void wpa_cli_close_connection(void)
        wpa_ctrl_close(ctrl_conn);
        ctrl_conn = NULL;
        if (mon_conn) {
+               eloop_unregister_read_sock(wpa_ctrl_get_fd(mon_conn));
                wpa_ctrl_close(mon_conn);
                mon_conn = NULL;
        }
@@ -306,6 +439,8 @@ static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
        if (print) {
                buf[len] = '\0';
                printf("%s", buf);
+               if (interactive && len > 0 && buf[len - 1] != '\n')
+                       printf("\n");
        }
        return 0;
 }
@@ -319,8 +454,11 @@ static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
 
 static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-       int verbose = argc > 0 && os_strcmp(argv[0], "verbose") == 0;
-       return wpa_ctrl_command(ctrl, verbose ? "STATUS-VERBOSE" : "STATUS");
+       if (argc > 0 && os_strcmp(argv[0], "verbose") == 0)
+               return wpa_ctrl_command(ctrl, "STATUS-VERBOSE");
+       if (argc > 0 && os_strcmp(argv[0], "wps") == 0)
+               return wpa_ctrl_command(ctrl, "STATUS-WPS");
+       return wpa_ctrl_command(ctrl, "STATUS");
 }
 
 
@@ -330,6 +468,25 @@ static int wpa_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
+static int wpa_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "RELOG");
+}
+
+
+static int wpa_cli_cmd_note(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       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);
+}
+
+
 static int wpa_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        return wpa_ctrl_command(ctrl, "MIB");
@@ -359,6 +516,8 @@ static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[])
 static int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        wpa_cli_quit = 1;
+       if (interactive)
+               eloop_terminate();
        return 0;
 }
 
@@ -393,13 +552,17 @@ static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
                return 0;
        }
 
-       if (argc != 2) {
+       if (argc != 1 && argc != 2) {
                printf("Invalid SET command: needs two arguments (variable "
                       "name and value)\n");
                return -1;
        }
 
-       res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
+       if (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;
@@ -408,6 +571,26 @@ static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
+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);
+}
+
+
 static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        return wpa_ctrl_command(ctrl, "LOGOFF");
@@ -467,6 +650,66 @@ static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *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);
+}
+
+
+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);
+}
+
+
+static int wpa_cli_cmd_bss_expire_count(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 (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long BSS_EXPIRE_COUNT command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
 static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc,
                                char *argv[])
 {
@@ -561,6 +804,39 @@ static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *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);
+}
+
+
+static int wpa_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
+                                 char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "WPS_CANCEL");
+}
+
+
 #ifdef CONFIG_WPS_OOB
 static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
@@ -602,7 +878,7 @@ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
        if (argc == 2)
                res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s",
                                  argv[0], argv[1]);
-       else if (argc == 6) {
+       else if (argc == 5 || argc == 6) {
                char ssid_hex[2 * 32 + 1];
                char key_hex[2 * 64 + 1];
                int i;
@@ -615,10 +891,13 @@ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
                }
 
                key_hex[0] = '\0';
-               for (i = 0; i < 64; i++) {
-                       if (argv[5][i] == '\0')
-                               break;
-                       os_snprintf(&key_hex[i * 2], 3, "%02x", argv[5][i]);
+               if (argc == 6) {
+                       for (i = 0; i < 64; i++) {
+                               if (argv[5][i] == '\0')
+                                       break;
+                               os_snprintf(&key_hex[i * 2], 3, "%02x",
+                                           argv[5][i]);
+                       }
                }
 
                res = os_snprintf(cmd, sizeof(cmd),
@@ -627,11 +906,11 @@ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
                                  key_hex);
        } else {
                printf("Invalid WPS_REG command: need two arguments:\n"
-                      "- BSSID: use 'any' to select any\n"
+                      "- BSSID of the target AP\n"
                       "- AP PIN\n");
                printf("Alternatively, six arguments can be used to "
                       "reconfigure the AP:\n"
-                      "- BSSID: use 'any' to select any\n"
+                      "- BSSID of the target AP\n"
                       "- AP PIN\n"
                       "- new SSID\n"
                       "- new auth (OPEN, WPAPSK, WPA2PSK)\n"
@@ -648,11 +927,44 @@ 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);
+}
+
+
 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");
-
 }
 
 
@@ -670,15 +982,21 @@ static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc,
        char cmd[256];
        int res;
 
-       if (argc != 2) {
-               printf("Invalid WPS_ER_PIN command: need two arguments:\n"
+       if (argc < 2) {
+               printf("Invalid WPS_ER_PIN command: need at least two "
+                      "arguments:\n"
                       "- UUID: use 'any' to select any\n"
-                      "- PIN: Enrollee PIN\n");
+                      "- PIN: Enrollee PIN\n"
+                      "optional: - Enrollee MAC address\n");
                return -1;
        }
 
-       res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s",
-                         argv[0], argv[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;
@@ -732,43 +1050,118 @@ static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc,
 }
 
 
-static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *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 != 1) {
-               printf("Invalid IBSS_RSN command: needs one argument "
-                      "(Peer STA MAC address)\n");
+       if (argc != 2) {
+               printf("Invalid WPS_ER_SET_CONFIG command: need two "
+                      "arguments:\n"
+                      "- UUID: specify which AP to use\n"
+                      "- Network configuration id\n");
                return -1;
        }
 
-       res = os_snprintf(cmd, sizeof(cmd), "IBSS_RSN %s", argv[0]);
+       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 IBSS_RSN command.\n");
+               printf("Too long WPS_ER_SET_CONFIG command.\n");
                return -1;
        }
        return wpa_ctrl_command(ctrl, cmd);
 }
 
 
-static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_cli_cmd_wps_er_config(struct wpa_ctrl *ctrl, int argc,
+                                    char *argv[])
 {
        char cmd[256];
        int res;
 
-       if (argc != 1) {
-               printf("Invalid LEVEL command: needs one argument (debug "
-                      "level)\n");
-               return -1;
-       }
-       res = os_snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-               printf("Too long LEVEL command.\n");
-               return -1;
-       }
-       return wpa_ctrl_command(ctrl, cmd);
-}
+       if (argc == 5 || argc == 6) {
+               char ssid_hex[2 * 32 + 1];
+               char key_hex[2 * 64 + 1];
+               int i;
+
+               ssid_hex[0] = '\0';
+               for (i = 0; i < 32; i++) {
+                       if (argv[2][i] == '\0')
+                               break;
+                       os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]);
+               }
+
+               key_hex[0] = '\0';
+               if (argc == 6) {
+                       for (i = 0; i < 64; i++) {
+                               if (argv[5][i] == '\0')
+                                       break;
+                               os_snprintf(&key_hex[i * 2], 3, "%02x",
+                                           argv[5][i]);
+                       }
+               }
+
+               res = os_snprintf(cmd, sizeof(cmd),
+                                 "WPS_ER_CONFIG %s %s %s %s %s %s",
+                                 argv[0], argv[1], ssid_hex, argv[3], argv[4],
+                                 key_hex);
+       } else {
+               printf("Invalid WPS_ER_CONFIG command: need six arguments:\n"
+                      "- AP UUID\n"
+                      "- AP PIN\n"
+                      "- new SSID\n"
+                      "- new auth (OPEN, WPAPSK, WPA2PSK)\n"
+                      "- new encr (NONE, WEP, TKIP, CCMP)\n"
+                      "- new key\n");
+               return -1;
+       }
+
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long WPS_ER_CONFIG command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       char cmd[256];
+       int res;
+
+       if (argc != 1) {
+               printf("Invalid IBSS_RSN command: needs one argument "
+                      "(Peer STA MAC address)\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "IBSS_RSN %s", argv[0]);
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long IBSS_RSN command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       char cmd[256];
+       int res;
+
+       if (argc != 1) {
+               printf("Invalid LEVEL command: needs one argument (debug "
+                      "level)\n");
+               return -1;
+       }
+       res = os_snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long LEVEL command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
 
 
 static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[])
@@ -1002,6 +1395,58 @@ static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
+static int wpa_cli_cmd_blacklist(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       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);
+}
+
+
+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);
+}
+
+
 static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc,
                                     char *argv[])
 {
@@ -1229,6 +1674,21 @@ static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
+static char ** wpa_cli_complete_bss(const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       char **res = NULL;
+
+       switch (arg) {
+       case 1:
+               res = cli_txt_list_array(&bsses);
+               break;
+       }
+
+       return res;
+}
+
+
 static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
                                      char *argv[])
 {
@@ -1398,68 +1858,825 @@ static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
                return -1;
        printf("%s", buf);
 
-       pos = buf;
-       while (*pos != '\0' && *pos != '\n')
-               pos++;
-       *pos = '\0';
-       os_strlcpy(addr, buf, addr_len);
-       return 0;
+       pos = buf;
+       while (*pos != '\0' && *pos != '\n')
+               pos++;
+       *pos = '\0';
+       os_strlcpy(addr, buf, addr_len);
+       return 0;
+}
+
+
+static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       char addr[32], cmd[64];
+
+       if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
+               return 0;
+       do {
+               os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
+       } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
+
+       return -1;
+}
+#endif /* CONFIG_AP */
+
+
+static int wpa_cli_cmd_suspend(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "SUSPEND");
+}
+
+
+static int wpa_cli_cmd_resume(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "RESUME");
+}
+
+
+static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "DROP_SA");
+}
+
+
+static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       char cmd[128];
+       int res;
+
+       if (argc != 1) {
+               printf("Invalid ROAM command: needs one argument "
+                      "(target AP's BSSID)\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "ROAM %s", argv[0]);
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long ROAM command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+#ifdef CONFIG_P2P
+
+static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       char cmd[128];
+       int res;
+
+       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 int wpa_cli_cmd_p2p_stop_find(struct wpa_ctrl *ctrl, int argc,
+                                    char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "P2P_STOP_FIND");
+}
+
+
+static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc,
+                                  char *argv[])
+{
+       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);
+}
+
+
+static char ** wpa_cli_complete_p2p_connect(const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       char **res = NULL;
+
+       switch (arg) {
+       case 1:
+               res = cli_txt_list_array(&p2p_peers);
+               break;
+       }
+
+       return res;
+}
+
+
+static int wpa_cli_cmd_p2p_listen(struct wpa_ctrl *ctrl, int argc,
+                                 char *argv[])
+{
+       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);
+}
+
+
+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);
+}
+
+
+static char ** wpa_cli_complete_p2p_group_remove(const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       char **res = NULL;
+
+       switch (arg) {
+       case 1:
+               res = cli_txt_list_array(&p2p_groups);
+               break;
+       }
+
+       return res;
+}
+
+
+static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc,
+                                       char *argv[])
+{
+       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);
+}
+
+
+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"
+                      "(display, keypad, or pbc) and an optional join\n");
+               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);
+}
+
+
+static int wpa_cli_cmd_p2p_get_passphrase(struct wpa_ctrl *ctrl, int argc,
+                                         char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "P2P_GET_PASSPHRASE");
+}
+
+
+static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc,
+                                        char *argv[])
+{
+       char cmd[4096];
+       int res;
+
+       if (argc != 2 && argc != 4) {
+               printf("Invalid P2P_SERV_DISC_REQ command: needs two "
+                      "arguments (address and TLVs) or four arguments "
+                      "(address, \"upnp\", version, search target "
+                      "(SSDP ST:)\n");
+               return -1;
+       }
+
+       if (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))
+               return -1;
+       cmd[sizeof(cmd) - 1] = '\0';
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+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);
+}
+
+
+static int wpa_cli_cmd_p2p_serv_disc_resp(struct wpa_ctrl *ctrl, int argc,
+                                         char *argv[])
+{
+       char cmd[4096];
+       int res;
+
+       if (argc != 4) {
+               printf("Invalid P2P_SERV_DISC_RESP command: needs four "
+                      "arguments (freq, address, dialog token, and TLVs)\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_RESP %s %s %s %s",
+                         argv[0], argv[1], argv[2], argv[3]);
+       if (res < 0 || (size_t) res >= sizeof(cmd))
+               return -1;
+       cmd[sizeof(cmd) - 1] = '\0';
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_p2p_service_update(struct wpa_ctrl *ctrl, int argc,
+                                         char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "P2P_SERVICE_UPDATE");
+}
+
+
+static int wpa_cli_cmd_p2p_serv_disc_external(struct wpa_ctrl *ctrl,
+                                             int argc, char *argv[])
+{
+       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);
+}
+
+
+static int wpa_cli_cmd_p2p_service_flush(struct wpa_ctrl *ctrl, int argc,
+                                        char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "P2P_SERVICE_FLUSH");
+}
+
+
+static int wpa_cli_cmd_p2p_service_add(struct wpa_ctrl *ctrl, int argc,
+                                      char *argv[])
+{
+       char cmd[4096];
+       int res;
+
+       if (argc != 3 && argc != 4) {
+               printf("Invalid P2P_SERVICE_ADD command: needs three or four "
+                      "arguments\n");
+               return -1;
+       }
+
+       if (argc == 4)
+               res = os_snprintf(cmd, sizeof(cmd),
+                                 "P2P_SERVICE_ADD %s %s %s %s",
+                                 argv[0], argv[1], argv[2], argv[3]);
+       else
+               res = os_snprintf(cmd, sizeof(cmd),
+                                 "P2P_SERVICE_ADD %s %s %s",
+                                 argv[0], argv[1], argv[2]);
+       if (res < 0 || (size_t) res >= sizeof(cmd))
+               return -1;
+       cmd[sizeof(cmd) - 1] = '\0';
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_p2p_service_del(struct wpa_ctrl *ctrl, int argc,
+                                      char *argv[])
+{
+       char cmd[4096];
+       int res;
+
+       if (argc != 2 && argc != 3) {
+               printf("Invalid P2P_SERVICE_DEL command: needs two or three "
+                      "arguments\n");
+               return -1;
+       }
+
+       if (argc == 3)
+               res = os_snprintf(cmd, sizeof(cmd),
+                                 "P2P_SERVICE_DEL %s %s %s",
+                                 argv[0], argv[1], argv[2]);
+       else
+               res = os_snprintf(cmd, sizeof(cmd),
+                                 "P2P_SERVICE_DEL %s %s",
+                                 argv[0], argv[1]);
+       if (res < 0 || (size_t) res >= sizeof(cmd))
+               return -1;
+       cmd[sizeof(cmd) - 1] = '\0';
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_p2p_reject(struct wpa_ctrl *ctrl,
+                                 int argc, char *argv[])
+{
+       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);
+}
+
+
+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);
+}
+
+
+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);
+}
+
+
+static char ** wpa_cli_complete_p2p_peer(const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       char **res = NULL;
+
+       switch (arg) {
+       case 1:
+               res = cli_txt_list_array(&p2p_peers);
+               break;
+       }
+
+       return res;
+}
+
+
+static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, char *cmd,
+                                    char *addr, size_t addr_len,
+                                    int discovered)
+{
+       char buf[4096], *pos;
+       size_t len;
+       int ret;
+
+       if (ctrl_conn == NULL)
+               return -1;
+       len = sizeof(buf) - 1;
+       ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
+                              wpa_cli_msg_cb);
+       if (ret == -2) {
+               printf("'%s' command timed out.\n", cmd);
+               return -2;
+       } else if (ret < 0) {
+               printf("'%s' command failed.\n", cmd);
+               return -1;
+       }
+
+       buf[len] = '\0';
+       if (memcmp(buf, "FAIL", 4) == 0)
+               return -1;
+
+       pos = buf;
+       while (*pos != '\0' && *pos != '\n')
+               pos++;
+       *pos++ = '\0';
+       os_strlcpy(addr, buf, addr_len);
+       if (!discovered || os_strstr(pos, "[PROBE_REQ_ONLY]") == NULL)
+               printf("%s\n", addr);
+       return 0;
+}
+
+
+static int wpa_cli_cmd_p2p_peers(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       char addr[32], cmd[64];
+       int discovered;
+
+       discovered = argc > 0 && os_strcmp(argv[0], "discovered") == 0;
+
+       if (wpa_ctrl_command_p2p_peer(ctrl, "P2P_PEER FIRST",
+                                     addr, sizeof(addr), discovered))
+               return -1;
+       do {
+               os_snprintf(cmd, sizeof(cmd), "P2P_PEER NEXT-%s", addr);
+       } while (wpa_ctrl_command_p2p_peer(ctrl, cmd, addr, sizeof(addr),
+                        discovered) == 0);
+
+       return 0;
+}
+
+
+static int wpa_cli_cmd_p2p_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       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);
+}
+
+
+static int wpa_cli_cmd_p2p_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "P2P_FLUSH");
+}
+
+
+static int wpa_cli_cmd_p2p_cancel(struct wpa_ctrl *ctrl, int argc,
+                                 char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "P2P_CANCEL");
+}
+
+
+static int wpa_cli_cmd_p2p_unauthorize(struct wpa_ctrl *ctrl, int argc,
+                                      char *argv[])
+{
+       char cmd[100];
+       int res;
+
+       if (argc != 1) {
+               printf("Invalid P2P_UNAUTHORIZE command: needs one argument "
+                      "(peer address)\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "P2P_UNAUTHORIZE %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_p2p_presence_req(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");
+               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");
+       if (res < 0 || (size_t) res >= sizeof(cmd))
+               return -1;
+       cmd[sizeof(cmd) - 1] = '\0';
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_p2p_ext_listen(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");
+               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");
+       if (res < 0 || (size_t) res >= sizeof(cmd))
+               return -1;
+       cmd[sizeof(cmd) - 1] = '\0';
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+#endif /* CONFIG_P2P */
+
+
+#ifdef CONFIG_INTERWORKING
+static int wpa_cli_cmd_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
+                                 char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "FETCH_ANQP");
+}
+
+
+static int wpa_cli_cmd_stop_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
+                                      char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "STOP_FETCH_ANQP");
+}
+
+
+static int wpa_cli_cmd_interworking_select(struct wpa_ctrl *ctrl, int argc,
+                                          char *argv[])
+{
+       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);
+}
+
+
+static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc,
+                                           char *argv[])
+{
+       char cmd[100];
+       int res;
+
+       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_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-       char addr[32], cmd[64];
+       char cmd[100];
+       int res;
 
-       if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
-               return 0;
-       do {
-               os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
-       } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
+       if (argc != 2) {
+               printf("Invalid ANQP_GET command: needs two arguments "
+                      "(addr and info id list)\n");
+               return -1;
+       }
 
-       return -1;
+       res = os_snprintf(cmd, sizeof(cmd), "ANQP_GET %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);
 }
-#endif /* CONFIG_AP */
+#endif /* CONFIG_INTERWORKING */
 
 
-static int wpa_cli_cmd_suspend(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc,
+                                      char *argv[])
 {
-       return wpa_ctrl_command(ctrl, "SUSPEND");
+       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);
 }
 
 
-static int wpa_cli_cmd_resume(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_cli_cmd_tdls_discover(struct wpa_ctrl *ctrl, int argc,
+                                    char *argv[])
 {
-       return wpa_ctrl_command(ctrl, "RESUME");
+       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);
 }
 
 
-static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_cli_cmd_tdls_setup(struct wpa_ctrl *ctrl, int argc,
+                                 char *argv[])
 {
-       return wpa_ctrl_command(ctrl, "DROP_SA");
+       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);
 }
 
 
-static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_cli_cmd_tdls_teardown(struct wpa_ctrl *ctrl, int argc,
+                                    char *argv[])
 {
-       char cmd[128];
+       char cmd[256];
        int res;
 
        if (argc != 1) {
-               printf("Invalid ROAM command: needs one argument "
-                      "(target AP's BSSID)\n");
+               printf("Invalid TDLS_TEARDOWN command: needs one argument "
+                      "(Peer STA MAC address)\n");
                return -1;
        }
 
-       res = os_snprintf(cmd, sizeof(cmd), "ROAM %s", argv[0]);
+       res = os_snprintf(cmd, sizeof(cmd), "TDLS_TEARDOWN %s", argv[0]);
        if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-               printf("Too long ROAM command.\n");
+               printf("Too long TDLS_TEARDOWN command.\n");
                return -1;
        }
        return wpa_ctrl_command(ctrl, cmd);
 }
 
 
+static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc,
+                                  char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "SIGNAL_POLL");
+}
+
+
+static int wpa_cli_cmd_reauthenticate(struct wpa_ctrl *ctrl, int argc,
+                                     char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "REAUTHENTICATE");
+}
+
+
 enum wpa_cli_cmd_flags {
        cli_cmd_flag_none               = 0x00,
        cli_cmd_flag_sensitive          = 0x01
@@ -1479,6 +2696,12 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "ping", wpa_cli_cmd_ping,
          cli_cmd_flag_none,
          "= pings wpa_supplicant" },
+       { "relog", wpa_cli_cmd_relog,
+         cli_cmd_flag_none,
+         "= re-open log-file (allow rolling logs)" },
+       { "note", wpa_cli_cmd_note,
+         cli_cmd_flag_none,
+         "<text> = add a note to wpa_supplicant debug log" },
        { "mib", wpa_cli_cmd_mib,
          cli_cmd_flag_none,
          "= get MIB variables (dot1x, dot11)" },
@@ -1501,6 +2724,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
          cli_cmd_flag_none,
          "= set variables (shows list of variables when run without "
          "arguments)" },
+       { "get", wpa_cli_cmd_get,
+         cli_cmd_flag_none,
+         "<name> = get information" },
        { "logon", wpa_cli_cmd_logon,
          cli_cmd_flag_none,
          "= IEEE 802.1X EAPOL state machine logon" },
@@ -1539,6 +2765,15 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "bssid", wpa_cli_cmd_bssid,
          cli_cmd_flag_none,
          "<network id> <BSSID> = set preferred BSSID for an SSID" },
+       { "blacklist", wpa_cli_cmd_blacklist,
+         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,
+         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,
          cli_cmd_flag_none,
          "= list configured networks" },
@@ -1607,6 +2842,15 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "ap_scan", wpa_cli_cmd_ap_scan,
          cli_cmd_flag_none,
          "<value> = set ap_scan parameter" },
+       { "scan_interval", wpa_cli_cmd_scan_interval,
+         cli_cmd_flag_none,
+         "<value> = set scan_interval parameter (in seconds)" },
+       { "bss_expire_age", wpa_cli_cmd_bss_expire_age,
+         cli_cmd_flag_none,
+         "<value> = set BSS expiration age parameter" },
+       { "bss_expire_count", wpa_cli_cmd_bss_expire_count,
+         cli_cmd_flag_none,
+         "<value> = set BSS expiration scan count parameter" },
        { "stkstart", wpa_cli_cmd_stkstart,
          cli_cmd_flag_none,
          "<addr> = request STK negotiation with <addr>" },
@@ -1620,6 +2864,11 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
          cli_cmd_flag_sensitive,
          "<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
          "hardcoded)" },
+       { "wps_check_pin", wpa_cli_cmd_wps_check_pin,
+         cli_cmd_flag_sensitive,
+         "<PIN> = verify PIN checksum" },
+       { "wps_cancel", wpa_cli_cmd_wps_cancel, cli_cmd_flag_none,
+         "Cancels the pending WPS operation" },
 #ifdef CONFIG_WPS_OOB
        { "wps_oob", wpa_cli_cmd_wps_oob,
          cli_cmd_flag_sensitive,
@@ -1628,9 +2877,12 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "wps_reg", wpa_cli_cmd_wps_reg,
          cli_cmd_flag_sensitive,
          "<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
+       { "wps_ap_pin", wpa_cli_cmd_wps_ap_pin,
+         cli_cmd_flag_sensitive,
+         "[params..] = enable/disable AP PIN" },
        { "wps_er_start", wpa_cli_cmd_wps_er_start,
          cli_cmd_flag_none,
-         "= start Wi-Fi Protected Setup External Registrar" },
+         "[IP address] = start Wi-Fi Protected Setup External Registrar" },
        { "wps_er_stop", wpa_cli_cmd_wps_er_stop,
          cli_cmd_flag_none,
          "= stop Wi-Fi Protected Setup External Registrar" },
@@ -1643,6 +2895,12 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "wps_er_learn", wpa_cli_cmd_wps_er_learn,
          cli_cmd_flag_sensitive,
          "<UUID> <PIN> = learn AP configuration" },
+       { "wps_er_set_config", wpa_cli_cmd_wps_er_set_config,
+         cli_cmd_flag_none,
+         "<UUID> <network id> = set AP configuration for enrolling" },
+       { "wps_er_config", wpa_cli_cmd_wps_er_config,
+         cli_cmd_flag_sensitive,
+         "<UUID> <PIN> <SSID> <auth> <encr> <key> = configure AP" },
        { "ibss_rsn", wpa_cli_cmd_ibss_rsn,
          cli_cmd_flag_none,
          "<addr> = request RSN authentication with <addr> in IBSS" },
@@ -1663,6 +2921,106 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "roam", wpa_cli_cmd_roam,
          cli_cmd_flag_none,
          "<addr> = roam to the specified BSS" },
+#ifdef CONFIG_P2P
+       { "p2p_find", wpa_cli_cmd_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,
+         "= 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,
+         "[timeout] = listen for P2P Devices for up-to timeout seconds" },
+       { "p2p_group_remove", wpa_cli_cmd_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,
+         "<addr> <method> = request provisioning discovery" },
+       { "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase,
+         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,
+         "<addr> <TLVs> = schedule service discovery request" },
+       { "p2p_serv_disc_cancel_req", wpa_cli_cmd_p2p_serv_disc_cancel_req,
+         cli_cmd_flag_none,
+         "<id> = cancel pending service discovery request" },
+       { "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp,
+         cli_cmd_flag_none,
+         "<freq> <addr> <dialog token> <TLVs> = service discovery response" },
+       { "p2p_service_update", wpa_cli_cmd_p2p_service_update,
+         cli_cmd_flag_none,
+         "= indicate change in local services" },
+       { "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external,
+         cli_cmd_flag_none,
+         "<external> = set external processing of service discovery" },
+       { "p2p_service_flush", wpa_cli_cmd_p2p_service_flush,
+         cli_cmd_flag_none,
+         "= remove all stored service entries" },
+       { "p2p_service_add", wpa_cli_cmd_p2p_service_add,
+         cli_cmd_flag_none,
+         "<bonjour|upnp> <query|version> <response|service> = add a local "
+         "service" },
+       { "p2p_service_del", wpa_cli_cmd_p2p_service_del,
+         cli_cmd_flag_none,
+         "<bonjour|upnp> <query|version> [|service] = remove a local "
+         "service" },
+       { "p2p_reject", wpa_cli_cmd_p2p_reject,
+         cli_cmd_flag_none,
+         "<addr> = reject connection attempts from a specific peer" },
+       { "p2p_invite", wpa_cli_cmd_p2p_invite,
+         cli_cmd_flag_none,
+         "<cmd> [peer=addr] = invite peer" },
+       { "p2p_peers", wpa_cli_cmd_p2p_peers, cli_cmd_flag_none,
+         "[discovered] = list known (optionally, only fully discovered) P2P "
+         "peers" },
+       { "p2p_peer", wpa_cli_cmd_p2p_peer, cli_cmd_flag_none,
+         "<address> = show information about known P2P peer" },
+       { "p2p_set", wpa_cli_cmd_p2p_set, cli_cmd_flag_none,
+         "<field> <value> = set a P2P parameter" },
+       { "p2p_flush", wpa_cli_cmd_p2p_flush, cli_cmd_flag_none,
+         "= flush P2P state" },
+       { "p2p_cancel", wpa_cli_cmd_p2p_cancel, cli_cmd_flag_none,
+         "= cancel P2P group formation" },
+       { "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize, cli_cmd_flag_none,
+         "<address> = unauthorize a peer" },
+       { "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, cli_cmd_flag_none,
+         "[<duration> <interval>] [<duration> <interval>] = request GO "
+         "presence" },
+       { "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, cli_cmd_flag_none,
+         "[<period> <interval>] = set extended listen timing" },
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_INTERWORKING
+       { "fetch_anqp", wpa_cli_cmd_fetch_anqp, 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 operation" },
+       { "interworking_select", wpa_cli_cmd_interworking_select,
+         cli_cmd_flag_none,
+         "[auto] = perform Interworking network selection" },
+       { "interworking_connect", wpa_cli_cmd_interworking_connect,
+         cli_cmd_flag_none,
+         "<BSSID> = connect using Interworking credentials" },
+       { "anqp_get", wpa_cli_cmd_anqp_get, cli_cmd_flag_none,
+         "<addr> <info id>[,<info id>]... = request ANQP information" },
+#endif /* CONFIG_INTERWORKING */
+       { "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, cli_cmd_flag_none,
+         "<0/1> = disable/enable automatic reconnection" },
+       { "tdls_discover", wpa_cli_cmd_tdls_discover,
+         cli_cmd_flag_none,
+         "<addr> = request TDLS discovery with <addr>" },
+       { "tdls_setup", wpa_cli_cmd_tdls_setup,
+         cli_cmd_flag_none,
+         "<addr> = request TDLS setup with <addr>" },
+       { "tdls_teardown", wpa_cli_cmd_tdls_teardown,
+         cli_cmd_flag_none,
+         "<addr> = tear down TDLS with <addr>" },
+       { "signal_poll", wpa_cli_cmd_signal_poll,
+         cli_cmd_flag_none,
+         "= get signal parameters" },
+       { "reauthenticate", wpa_cli_cmd_reauthenticate, cli_cmd_flag_none,
+         "= trigger IEEE 802.1X/EAPOL reauthentication" },
        { NULL, NULL, cli_cmd_flag_none, NULL }
 };
 
@@ -1694,8 +3052,7 @@ static void print_help(void)
 }
 
 
-#ifdef CONFIG_READLINE
-static int cmd_has_sensitive_data(const char *cmd)
+static int wpa_cli_edit_filter_history_cb(void *ctx, const char *cmd)
 {
        const char *c, *delim;
        int n;
@@ -1714,7 +3071,76 @@ static int cmd_has_sensitive_data(const char *cmd)
        }
        return 0;
 }
-#endif /* CONFIG_READLINE */
+
+
+static char ** wpa_list_cmd_list(void)
+{
+       char **res;
+       int i, count;
+
+       count = sizeof(wpa_cli_commands) / sizeof(wpa_cli_commands[0]);
+       res = os_zalloc(count * sizeof(char *));
+       if (res == NULL)
+               return NULL;
+
+       for (i = 0; wpa_cli_commands[i].cmd; i++) {
+               res[i] = os_strdup(wpa_cli_commands[i].cmd);
+               if (res[i] == NULL)
+                       break;
+       }
+
+       return res;
+}
+
+
+static char ** wpa_cli_cmd_completion(const char *cmd, const char *str,
+                                     int pos)
+{
+       int i;
+
+       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) {
+                       edit_clear_line();
+                       printf("\r%s\n", wpa_cli_commands[i].usage);
+                       edit_redraw();
+                       break;
+               }
+       }
+
+       return NULL;
+}
+
+
+static char ** wpa_cli_edit_completion_cb(void *ctx, const char *str, int pos)
+{
+       char **res;
+       const char *end;
+       char *cmd;
+
+       end = os_strchr(str, ' ');
+       if (end == NULL || str + pos < end)
+               return wpa_list_cmd_list();
+
+       cmd = os_malloc(pos + 1);
+       if (cmd == NULL)
+               return NULL;
+       os_memcpy(cmd, str, pos);
+       cmd[end - str] = '\0';
+       res = wpa_cli_cmd_completion(cmd, str, pos);
+       os_free(cmd);
+       return res;
+}
 
 
 static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
@@ -1852,6 +3278,24 @@ static void wpa_cli_action_process(const char *msg)
                        wpa_cli_connected = 0;
                        wpa_cli_exec(action_file, ctrl_ifname, "DISCONNECTED");
                }
+       } else if (str_match(pos, P2P_EVENT_GROUP_STARTED)) {
+               wpa_cli_exec(action_file, ctrl_ifname, pos);
+       } else if (str_match(pos, P2P_EVENT_GROUP_REMOVED)) {
+               wpa_cli_exec(action_file, ctrl_ifname, pos);
+       } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) {
+               wpa_cli_exec(action_file, ctrl_ifname, pos);
+       } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
+               wpa_cli_exec(action_file, ctrl_ifname, pos);
+       } else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) {
+               wpa_cli_exec(action_file, ctrl_ifname, pos);
+       } else if (str_match(pos, WPS_EVENT_SUCCESS)) {
+               wpa_cli_exec(action_file, ctrl_ifname, pos);
+       } else if (str_match(pos, WPS_EVENT_FAIL)) {
+               wpa_cli_exec(action_file, ctrl_ifname, pos);
+       } else if (str_match(pos, AP_STA_CONNECTED)) {
+               wpa_cli_exec(action_file, ctrl_ifname, pos);
+       } else if (str_match(pos, AP_STA_DISCONNECTED)) {
+               wpa_cli_exec(action_file, ctrl_ifname, pos);
        } else if (str_match(pos, WPA_EVENT_TERMINATING)) {
                printf("wpa_supplicant is terminating - stop monitoring\n");
                wpa_cli_quit = 1;
@@ -1874,10 +3318,76 @@ static void wpa_cli_reconnect(void)
 }
 
 
-static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
-                                int action_monitor)
+static void cli_event(const char *str)
+{
+       const char *start, *s;
+
+       start = os_strchr(str, '>');
+       if (start == NULL)
+               return;
+
+       start++;
+
+       if (str_starts(start, WPA_EVENT_BSS_ADDED)) {
+               s = os_strchr(start, ' ');
+               if (s == NULL)
+                       return;
+               s = os_strchr(s + 1, ' ');
+               if (s == NULL)
+                       return;
+               cli_txt_list_add(&bsses, s + 1);
+               return;
+       }
+
+       if (str_starts(start, WPA_EVENT_BSS_REMOVED)) {
+               s = os_strchr(start, ' ');
+               if (s == NULL)
+                       return;
+               s = os_strchr(s + 1, ' ');
+               if (s == NULL)
+                       return;
+               cli_txt_list_del_addr(&bsses, s + 1);
+               return;
+       }
+
+#ifdef CONFIG_P2P
+       if (str_starts(start, P2P_EVENT_DEVICE_FOUND)) {
+               s = os_strstr(start, " p2p_dev_addr=");
+               if (s == NULL)
+                       return;
+               cli_txt_list_add_addr(&p2p_peers, s + 14);
+               return;
+       }
+
+       if (str_starts(start, P2P_EVENT_DEVICE_LOST)) {
+               s = os_strstr(start, " p2p_dev_addr=");
+               if (s == NULL)
+                       return;
+               cli_txt_list_del_addr(&p2p_peers, s + 14);
+               return;
+       }
+
+       if (str_starts(start, P2P_EVENT_GROUP_STARTED)) {
+               s = os_strchr(start, ' ');
+               if (s == NULL)
+                       return;
+               cli_txt_list_add_word(&p2p_groups, s + 1);
+               return;
+       }
+
+       if (str_starts(start, P2P_EVENT_GROUP_REMOVED)) {
+               s = os_strchr(start, ' ');
+               if (s == NULL)
+                       return;
+               cli_txt_list_del_word(&p2p_groups, s + 1);
+               return;
+       }
+#endif /* CONFIG_P2P */
+}
+
+
+static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
 {
-       int first = 1;
        if (ctrl_conn == NULL) {
                wpa_cli_reconnect();
                return;
@@ -1890,14 +3400,12 @@ static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
                        if (action_monitor)
                                wpa_cli_action_process(buf);
                        else {
-                               if (in_read && first)
-                                       printf("\r");
-                               first = 0;
-                               printf("%s\n", buf);
-#ifdef CONFIG_READLINE
-                               rl_on_new_line();
-                               rl_redisplay();
-#endif /* CONFIG_READLINE */
+                               cli_event(buf);
+                               if (wpa_cli_show_event(buf)) {
+                                       edit_clear_line();
+                                       printf("\r%s\n", buf);
+                                       edit_redraw();
+                               }
                        }
                } else {
                        printf("Could not read pending message.\n");
@@ -1912,214 +3420,108 @@ static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
        }
 }
 
+#define max_args 10
 
-#ifdef CONFIG_READLINE
-static char * wpa_cli_cmd_gen(const char *text, int state)
+static int tokenize_cmd(char *cmd, char *argv[])
 {
-       static int i, len;
-       const char *cmd;
-
-       if (state == 0) {
-               i = 0;
-               len = os_strlen(text);
-       }
+       char *pos;
+       int argc = 0;
 
-       while ((cmd = wpa_cli_commands[i].cmd)) {
-               i++;
-               if (os_strncasecmp(cmd, text, len) == 0)
-                       return strdup(cmd);
+       pos = cmd;
+       for (;;) {
+               while (*pos == ' ')
+                       pos++;
+               if (*pos == '\0')
+                       break;
+               argv[argc] = pos;
+               argc++;
+               if (argc == max_args)
+                       break;
+               if (*pos == '"') {
+                       char *pos2 = os_strrchr(pos, '"');
+                       if (pos2)
+                               pos = pos2 + 1;
+               }
+               while (*pos != '\0' && *pos != ' ')
+                       pos++;
+               if (*pos == ' ')
+                       *pos++ = '\0';
        }
 
-       return NULL;
+       return argc;
 }
 
 
-static char * wpa_cli_dummy_gen(const char *text, int state)
+static void wpa_cli_ping(void *eloop_ctx, void *timeout_ctx)
 {
-       int i;
-
-       for (i = 0; wpa_cli_commands[i].cmd; i++) {
-               const char *cmd = wpa_cli_commands[i].cmd;
-               size_t len = os_strlen(cmd);
-               if (os_strncasecmp(rl_line_buffer, cmd, len) == 0 &&
-                   rl_line_buffer[len] == ' ') {
-                       printf("\n%s\n", wpa_cli_commands[i].usage);
-                       rl_on_new_line();
-                       rl_redisplay();
-                       break;
-               }
+       if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
+               printf("Connection to wpa_supplicant lost - trying to "
+                      "reconnect\n");
+               wpa_cli_close_connection();
        }
-
-       rl_attempted_completion_over = 1;
-       return NULL;
+       if (!ctrl_conn)
+               wpa_cli_reconnect();
+       eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL);
 }
 
 
-static char * wpa_cli_status_gen(const char *text, int state)
+static void wpa_cli_eloop_terminate(int sig, void *signal_ctx)
 {
-       static int i, len;
-       char *options[] = {
-               "verbose", NULL
-       };
-       char *t;
-
-       if (state == 0) {
-               i = 0;
-               len = os_strlen(text);
-       }
+       eloop_terminate();
+}
 
-       while ((t = options[i])) {
-               i++;
-               if (os_strncasecmp(t, text, len) == 0)
-                       return strdup(t);
-       }
 
-       rl_attempted_completion_over = 1;
-       return NULL;
+static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+       wpa_cli_recv_pending(mon_conn, 0);
 }
 
 
-static char ** wpa_cli_completion(const char *text, int start, int end)
+static void wpa_cli_edit_cmd_cb(void *ctx, char *cmd)
 {
-       char * (*func)(const char *text, int state);
+       char *argv[max_args];
+       int argc;
+       argc = tokenize_cmd(cmd, argv);
+       if (argc)
+               wpa_request(ctrl_conn, argc, argv);
+}
 
-       if (start == 0)
-               func = wpa_cli_cmd_gen;
-       else if (os_strncasecmp(rl_line_buffer, "status ", 7) == 0)
-               func = wpa_cli_status_gen;
-       else
-               func = wpa_cli_dummy_gen;
-       return rl_completion_matches(text, func);
+
+static void wpa_cli_edit_eof_cb(void *ctx)
+{
+       eloop_terminate();
 }
-#endif /* CONFIG_READLINE */
 
 
 static void wpa_cli_interactive(void)
 {
-#define max_args 10
-       char cmdbuf[256], *cmd, *argv[max_args], *pos;
-       int argc;
-#ifdef CONFIG_READLINE
        char *home, *hfile = NULL;
-#endif /* CONFIG_READLINE */
 
        printf("\nInteractive mode\n\n");
 
-#ifdef CONFIG_READLINE
-       rl_attempted_completion_function = wpa_cli_completion;
        home = getenv("HOME");
        if (home) {
                const char *fname = ".wpa_cli_history";
                int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
                hfile = os_malloc(hfile_len);
-               if (hfile) {
-                       int res;
-                       res = os_snprintf(hfile, hfile_len, "%s/%s", home,
-                                         fname);
-                       if (res >= 0 && res < hfile_len) {
-                               hfile[hfile_len - 1] = '\0';
-                               read_history(hfile);
-                               stifle_history(100);
-                       }
-               }
+               if (hfile)
+                       os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
        }
-#endif /* CONFIG_READLINE */
 
-       do {
-               wpa_cli_recv_pending(mon_conn, 0, 0);
-#ifndef CONFIG_NATIVE_WINDOWS
-               alarm(ping_interval);
-#endif /* CONFIG_NATIVE_WINDOWS */
-#ifdef CONFIG_WPA_CLI_FORK
-               if (mon_pid)
-                       kill(mon_pid, SIGUSR1);
-#endif /* CONFIG_WPA_CLI_FORK */
-#ifdef CONFIG_READLINE
-               cmd = readline("> ");
-               if (cmd && *cmd) {
-                       HIST_ENTRY *h;
-                       while (next_history())
-                               ;
-                       h = previous_history();
-                       if (h == NULL || os_strcmp(cmd, h->line) != 0)
-                               add_history(cmd);
-                       next_history();
-               }
-#else /* CONFIG_READLINE */
-               printf("> ");
-               cmd = fgets(cmdbuf, sizeof(cmdbuf), stdin);
-#endif /* CONFIG_READLINE */
-#ifndef CONFIG_NATIVE_WINDOWS
-               alarm(0);
-#endif /* CONFIG_NATIVE_WINDOWS */
-               if (cmd == NULL)
-                       break;
-               wpa_cli_recv_pending(mon_conn, 0, 0);
-               pos = cmd;
-               while (*pos != '\0') {
-                       if (*pos == '\n') {
-                               *pos = '\0';
-                               break;
-                       }
-                       pos++;
-               }
-               argc = 0;
-               pos = cmd;
-               for (;;) {
-                       while (*pos == ' ')
-                               pos++;
-                       if (*pos == '\0')
-                               break;
-                       argv[argc] = pos;
-                       argc++;
-                       if (argc == max_args)
-                               break;
-                       if (*pos == '"') {
-                               char *pos2 = os_strrchr(pos, '"');
-                               if (pos2)
-                                       pos = pos2 + 1;
-                       }
-                       while (*pos != '\0' && *pos != ' ')
-                               pos++;
-                       if (*pos == ' ')
-                               *pos++ = '\0';
-               }
-               if (argc)
-                       wpa_request(ctrl_conn, argc, argv);
-
-               if (cmd != cmdbuf)
-                       free(cmd);
-#ifdef CONFIG_WPA_CLI_FORK
-               if (mon_pid)
-                       kill(mon_pid, SIGUSR2);
-#endif /* CONFIG_WPA_CLI_FORK */
-       } while (!wpa_cli_quit);
-
-#ifdef CONFIG_READLINE
-       if (hfile) {
-               /* Save command history, excluding lines that may contain
-                * passwords. */
-               HIST_ENTRY *h;
-               history_set_pos(0);
-               while ((h = current_history())) {
-                       char *p = h->line;
-                       while (*p == ' ' || *p == '\t')
-                               p++;
-                       if (cmd_has_sensitive_data(p)) {
-                               h = remove_history(where_history());
-                               if (h) {
-                                       os_free(h->line);
-                                       os_free(h->data);
-                                       os_free(h);
-                               } else
-                                       next_history();
-                       } else
-                               next_history();
-               }
-               write_history(hfile);
-               os_free(hfile);
-       }
-#endif /* CONFIG_READLINE */
+       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);
+       eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL);
+
+       eloop_run();
+
+       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);
+       os_free(hfile);
+       eloop_cancel_timeout(wpa_cli_ping, NULL, NULL);
+       wpa_cli_close_connection();
 }
 
 
@@ -2149,7 +3551,7 @@ static void wpa_cli_action(struct wpa_ctrl *ctrl)
                }
 
                if (FD_ISSET(fd, &rfds))
-                       wpa_cli_recv_pending(ctrl, 0, 1);
+                       wpa_cli_recv_pending(ctrl, 1);
                else {
                        /* verify that connection is still working */
                        len = sizeof(buf) - 1;
@@ -2182,34 +3584,6 @@ static void wpa_cli_terminate(int sig)
 }
 
 
-#ifdef CONFIG_WPA_CLI_FORK
-static void wpa_cli_usr1(int sig)
-{
-#ifdef CONFIG_READLINE
-       rl_on_new_line();
-       rl_redisplay();
-#endif /* CONFIG_READLINE */
-}
-#endif /* CONFIG_WPA_CLI_FORK */
-
-
-#ifndef CONFIG_NATIVE_WINDOWS
-static void wpa_cli_alarm(int sig)
-{
-       if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
-               printf("Connection to wpa_supplicant lost - trying to "
-                      "reconnect\n");
-               wpa_cli_close_connection();
-       }
-       if (!ctrl_conn)
-               wpa_cli_reconnect();
-       if (mon_conn)
-               wpa_cli_recv_pending(mon_conn, 1, 0);
-       alarm(ping_interval);
-}
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-
 static char * wpa_cli_get_default_ifname(void)
 {
        char *ifname = NULL;
@@ -2217,8 +3591,17 @@ static char * wpa_cli_get_default_ifname(void)
 #ifdef CONFIG_CTRL_IFACE_UNIX
        struct dirent *dent;
        DIR *dir = opendir(ctrl_iface_dir);
-       if (!dir)
+       if (!dir) {
+#ifdef ANDROID
+               char ifprop[PROPERTY_VALUE_MAX];
+               if (property_get("wifi.interface", ifprop, NULL) != 0) {
+                       ifname = os_strdup(ifprop);
+                       printf("Using interface '%s'\n", ifname);
+                       return ifname;
+               }
+#endif /* ANDROID */
                return NULL;
+       }
        while ((dent = readdir(dir))) {
 #ifdef _DIRENT_HAVE_D_TYPE
                /*
@@ -2320,6 +3703,9 @@ int main(int argc, char *argv[])
        if (interactive)
                printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license);
 
+       if (eloop_init())
+               return -1;
+
        if (global) {
 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
                ctrl_conn = wpa_ctrl_open(NULL);
@@ -2337,12 +3723,6 @@ int main(int argc, char *argv[])
        signal(SIGINT, wpa_cli_terminate);
        signal(SIGTERM, wpa_cli_terminate);
 #endif /* _WIN32_WCE */
-#ifndef CONFIG_NATIVE_WINDOWS
-       signal(SIGALRM, wpa_cli_alarm);
-#endif /* CONFIG_NATIVE_WINDOWS */
-#ifdef CONFIG_WPA_CLI_FORK
-       signal(SIGUSR1, wpa_cli_usr1);
-#endif /* CONFIG_WPA_CLI_FORK */
 
        if (ctrl_ifname == NULL)
                ctrl_ifname = wpa_cli_get_default_ifname();
@@ -2393,6 +3773,7 @@ int main(int argc, char *argv[])
                ret = wpa_request(ctrl_conn, argc - optind, &argv[optind]);
 
        os_free(ctrl_ifname);
+       eloop_destroy();
        wpa_cli_cleanup();
 
        return ret;
diff --git a/wpa_supplicant/wpa_gui-qt4/.gitignore b/wpa_supplicant/wpa_gui-qt4/.gitignore
deleted file mode 100644 (file)
index efcb666..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-.moc
-.obj
-.ui
-Makefile
-wpa_gui
-qrc_icons.cpp
index 316ee89..dd72c7e 100644 (file)
@@ -3,5 +3,7 @@
   <file alias="wpa_gui.svg">icons/wpa_gui.svg</file>
   <file alias="ap.svg">icons/ap.svg</file>
   <file alias="laptop.svg">icons/laptop.svg</file>
+  <file alias="group.svg">icons/group.svg</file>
+  <file alias="invitation.svg">icons/invitation.svg</file>
  </qresource>
 </RCC>
diff --git a/wpa_supplicant/wpa_gui-qt4/icons/Makefile b/wpa_supplicant/wpa_gui-qt4/icons/Makefile
new file mode 100644 (file)
index 0000000..709514c
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/make -f
+
+NAMES := wpa_gui ap laptop group invitation
+SIZES := 16x16 22x22 32x32 48x48 64x64 128x128
+ICONS := $(addsuffix .png, $(foreach name, $(NAMES), $(foreach size, $(SIZES), $(size)/$(name))))
+ICONS += $(addsuffix .xpm, $(NAMES))
+
+all: $(ICONS)
+
+%.png:
+       mkdir -p hicolor/$(word 1, $(subst /, ,$(@)))/apps/
+       inkscape $(subst .png,.svg, $(word 2, $(subst /, , $(@)))) --without-gui \
+               --export-width=$(word 1, $(subst x, , $(@)))  \
+               --export-height=$(word 2, $(subst x, , $(subst /, , $(@)))) \
+               --export-png=hicolor/$(word 1, $(subst /, ,$(@)))/apps/$(word 2, $(subst /, , $@))
+
+%.xpm:
+       mkdir -p pixmaps/
+       convert hicolor/16x16/apps/$(@:.xpm=.png) pixmaps/$(@:.xpm=-16.xpm)
+       convert hicolor/32x32/apps/$(@:.xpm=.png) pixmaps/$@
+
+clean:
+       $(RM) -r pixmaps hicolor
index d73eed5..3953238 100644 (file)
@@ -37,3 +37,38 @@ by:      metalmarious
 last change:    May 18, 2008 07:04 pm (File added)
 date:   August 27, 2007 04:44 am
 license: PD
+
+
+group.svg
+---------
+
+http://www.openclipart.org/detail/25428
+http://www.openclipart.org/people/Anonymous/Anonymous_Network.svg
+Uploader:
+    Anonymous
+Drawn by:
+    Andrew Fitzsimon / Anonymous
+Created:
+    2009-04-29 04:07:37
+Description:
+    A network icon by Andrew Fitzsimon. Etiquette Icon set.
+    From 0.18 OCAL database.
+
+Public Domain
+
+
+
+invitation.svg
+--------------
+
+http://www.openclipart.org/detail/974
+http://www.openclipart.org/people/jean_victor_balin/jean_victor_balin_unknown_green.svg
+Uploader:
+    jean_victor_balin
+Drawn by:
+    jean_victor_balin
+Created:
+    2006-10-27 02:12:13
+Description:
+
+Public Domain
diff --git a/wpa_supplicant/wpa_gui-qt4/icons/group.svg b/wpa_supplicant/wpa_gui-qt4/icons/group.svg
new file mode 100644 (file)
index 0000000..4ea959b
--- /dev/null
@@ -0,0 +1,616 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   height="160.00000"
+   id="Andysvg"
+   inkscape:version="0.46"
+   sodipodi:docbase="/home/andy/Desktop/etiquette-icons-0.4/scalable/filesystems"
+   sodipodi:docname="gnome-fs-network.svg"
+   sodipodi:version="0.32"
+   version="1.0"
+   width="160.00000"
+   x="0.00000000"
+   y="0.00000000"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-filename="C:\Documents and Settings\All Users\Documents\Ubuntu Brig\Andy Fitzsimon\gnome-fs-network.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <metadata
+     id="metadata3">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:title>Etiquette Icons</dc:title>
+        <dc:description />
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>hash</rdf:li>
+            <rdf:li />
+            <rdf:li>filesystem</rdf:li>
+            <rdf:li>computer</rdf:li>
+            <rdf:li>icons</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+        <dc:publisher>
+          <cc:Agent
+             rdf:about="http://www.openclipart.org">
+            <dc:title>Andy Fitzsimon</dc:title>
+          </cc:Agent>
+        </dc:publisher>
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Andy Fitzsimon</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:rights>
+          <cc:Agent>
+            <dc:title>Andy Fitzsimon</dc:title>
+          </cc:Agent>
+        </dc:rights>
+        <dc:date />
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <cc:license
+           rdf:resource="http://web.resource.org/cc/PublicDomain" />
+        <dc:language>en</dc:language>
+      </cc:Work>
+      <cc:License
+         rdf:about="http://web.resource.org/cc/PublicDomain">
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Reproduction" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Distribution" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs3">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 80 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="160 : 80 : 1"
+       inkscape:persp3d-origin="80 : 53.333333 : 1"
+       id="perspective97" />
+    <linearGradient
+       id="linearGradient4894">
+      <stop
+         id="stop4895"
+         offset="0.0000000"
+         style="stop-color:#ffffff;stop-opacity:1.0000000;" />
+      <stop
+         id="stop4896"
+         offset="0.47000000"
+         style="stop-color:#ffffff;stop-opacity:0.85567009;" />
+      <stop
+         id="stop4897"
+         offset="1.0000000"
+         style="stop-color:#ffffff;stop-opacity:0.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient1853">
+      <stop
+         id="stop1854"
+         offset="0.0000000"
+         style="stop-color:#ffffff;stop-opacity:1.0000000;" />
+      <stop
+         id="stop1855"
+         offset="0.47000000"
+         style="stop-color:#ffffff;stop-opacity:0.85567009;" />
+      <stop
+         id="stop1856"
+         offset="1.0000000"
+         style="stop-color:#ffffff;stop-opacity:0.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient1806">
+      <stop
+         id="stop1807"
+         offset="0.0000000"
+         style="stop-color:#000000;stop-opacity:0.35051546;" />
+      <stop
+         id="stop3276"
+         offset="0.64999998"
+         style="stop-color:#000000;stop-opacity:0.13402061;" />
+      <stop
+         id="stop1808"
+         offset="1.0000000"
+         style="stop-color:#000000;stop-opacity:0.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient893">
+      <stop
+         id="stop895"
+         offset="0"
+         style="stop-color:#000;stop-opacity:1;" />
+      <stop
+         id="stop896"
+         offset="1"
+         style="stop-color:#fff;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient1317">
+      <stop
+         id="stop1318"
+         offset="0.00000000"
+         style="stop-color:#000000;stop-opacity:0.52892560;" />
+      <stop
+         id="stop1320"
+         offset="0.50000000"
+         style="stop-color:#000000;stop-opacity:0.17355372;" />
+      <stop
+         id="stop1319"
+         offset="1.0000000"
+         style="stop-color:#000000;stop-opacity:0.00000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient1133">
+      <stop
+         id="stop1134"
+         offset="0.00000000"
+         style="stop-color:#8bb7df;stop-opacity:1.0000000;" />
+      <stop
+         id="stop1136"
+         offset="0.76209301"
+         style="stop-color:#2a6092;stop-opacity:1.0000000;" />
+      <stop
+         id="stop1135"
+         offset="1.0000000"
+         style="stop-color:#375e82;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient1098">
+      <stop
+         id="stop1099"
+         offset="0.00000000"
+         style="stop-color:#ffffff;stop-opacity:1.0000000;" />
+      <stop
+         id="stop1101"
+         offset="0.50000000"
+         style="stop-color:#ffffff;stop-opacity:0.22314049;" />
+      <stop
+         id="stop1102"
+         offset="0.59930235"
+         style="stop-color:#ffffff;stop-opacity:0.00000000;" />
+      <stop
+         id="stop1100"
+         offset="1.0000000"
+         style="stop-color:#ffffff;stop-opacity:0.60330576;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient902">
+      <stop
+         id="stop903"
+         offset="0.00000000"
+         style="stop-color:#000000;stop-opacity:0.00000000;" />
+      <stop
+         id="stop904"
+         offset="1.0000000"
+         style="stop-color:#000000;stop-opacity:0.22000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient892">
+      <stop
+         id="stop893"
+         offset="0.0000000"
+         style="stop-color:#ffffff;stop-opacity:0.0000000;" />
+      <stop
+         id="stop894"
+         offset="1"
+         style="stop-color:#fff;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient888">
+      <stop
+         id="stop889"
+         offset="0.0000000"
+         style="stop-color:#626262;stop-opacity:1.0000000;" />
+      <stop
+         id="stop890"
+         offset="1"
+         style="stop-color:#fff;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient891"
+       x1="1.3485916"
+       x2="0.024647888"
+       xlink:href="#linearGradient888"
+       y1="-0.85185188"
+       y2="1.0899471" />
+    <linearGradient
+       id="linearGradient901"
+       spreadMethod="pad"
+       x1="1.5803921"
+       x2="0.14117648"
+       xlink:href="#linearGradient888"
+       y1="2.4285715"
+       y2="-0.38571429" />
+    <linearGradient
+       id="linearGradient905"
+       x1="-1.5389611"
+       x2="1.0909091"
+       xlink:href="#linearGradient888"
+       y1="2.7890625"
+       y2="-0.19531250" />
+    <radialGradient
+       cx="0.10362694"
+       cy="0.093750000"
+       fx="0.10362694"
+       fy="0.093750000"
+       id="radialGradient1132"
+       r="1.2958785"
+       xlink:href="#linearGradient1133" />
+    <linearGradient
+       id="linearGradient1138"
+       xlink:href="#linearGradient4894" />
+    <linearGradient
+       id="linearGradient1140"
+       x1="0.54117650"
+       x2="0.57647061"
+       xlink:href="#linearGradient888"
+       y1="-2.4210527"
+       y2="4.6315789" />
+    <linearGradient
+       id="linearGradient1141"
+       x1="1.8281938"
+       x2="-0.0088105723"
+       xlink:href="#linearGradient888"
+       y1="3.0546875"
+       y2="-0.44531250" />
+    <linearGradient
+       id="linearGradient1144"
+       x1="0.21960784"
+       x2="0.59607846"
+       xlink:href="#linearGradient1853"
+       y1="-11.111111"
+       y2="5.2777777" />
+    <linearGradient
+       id="linearGradient1146"
+       x1="0.51351351"
+       x2="-0.076576576"
+       xlink:href="#linearGradient892"
+       y1="0.55468750"
+       y2="1.1875000" />
+    <linearGradient
+       id="linearGradient1148"
+       x1="0.23245615"
+       x2="1.0789474"
+       xlink:href="#linearGradient892"
+       y1="0.15625000"
+       y2="-0.64843750" />
+    <linearGradient
+       id="linearGradient1150"
+       x1="0.25221238"
+       x2="-0.57522124"
+       xlink:href="#linearGradient892"
+       y1="0.57812500"
+       y2="1.4765625" />
+    <linearGradient
+       id="linearGradient1156"
+       x1="0.48260871"
+       x2="0.48260871"
+       xlink:href="#linearGradient888"
+       y1="-0.40000001"
+       y2="1.8750000" />
+    <linearGradient
+       id="linearGradient1157"
+       x1="1.5528169"
+       x2="-1.2077465"
+       xlink:href="#linearGradient888"
+       y1="3.3265307"
+       y2="-0.48979592" />
+    <linearGradient
+       id="linearGradient1166"
+       x1="0.52941179"
+       x2="0.57647061"
+       xlink:href="#linearGradient1317"
+       y1="-3.5714285"
+       y2="4.6315789" />
+    <linearGradient
+       id="linearGradient1167"
+       x1="1.6111112"
+       x2="-0.083333336"
+       xlink:href="#linearGradient888"
+       y1="3.0703125"
+       y2="0.046875000" />
+    <linearGradient
+       id="linearGradient1169"
+       x1="1.4780220"
+       x2="-0.13028169"
+       xlink:href="#linearGradient893"
+       y1="2.9218750"
+       y2="-0.26732674" />
+    <linearGradient
+       gradientTransform="scale(0.998371,1.001632)"
+       id="linearGradient1170"
+       x1="0.47284532"
+       x2="0.48655096"
+       xlink:href="#linearGradient902"
+       y1="-0.016295359"
+       y2="1.8378206" />
+    <linearGradient
+       id="linearGradient1171"
+       x1="0.83050847"
+       x2="0.56355929"
+       xlink:href="#linearGradient902"
+       y1="0.57812500"
+       y2="0.36718750" />
+    <radialGradient
+       cx="0.088082902"
+       cy="0.093750000"
+       fx="0.090673581"
+       fy="0.10937500"
+       id="radialGradient1315"
+       r="1.1765809"
+       xlink:href="#linearGradient1133" />
+    <radialGradient
+       cx="0.50000000"
+       cy="0.50000006"
+       fx="0.50352114"
+       fy="0.18269235"
+       id="radialGradient1316"
+       r="0.34964636"
+       xlink:href="#linearGradient1317" />
+    <linearGradient
+       id="linearGradient1404"
+       x1="0.53169012"
+       x2="0.54577464"
+       xlink:href="#linearGradient892"
+       y1="0.28888890"
+       y2="1.1000000" />
+    <linearGradient
+       gradientTransform="scale(0.997825,1.002180)"
+       id="linearGradient1505"
+       x1="0.47157744"
+       x2="0.48548824"
+       xlink:href="#linearGradient902"
+       y1="-0.024853170"
+       y2="1.8570156" />
+    <linearGradient
+       gradientTransform="scale(0.995847,1.004170)"
+       id="linearGradient1506"
+       x1="0.47042510"
+       x2="0.48481107"
+       xlink:href="#linearGradient902"
+       y1="-0.043652620"
+       y2="1.9025002" />
+    <linearGradient
+       gradientTransform="scale(0.997153,1.002855)"
+       id="linearGradient2740"
+       x1="0.47041038"
+       x2="0.48453596"
+       xlink:href="#linearGradient902"
+       y1="-0.033741195"
+       y2="1.8771822" />
+    <linearGradient
+       id="linearGradient4283"
+       x1="-0.77314812"
+       x2="0.99074072"
+       xlink:href="#linearGradient893"
+       y1="2.0837989"
+       y2="-0.033519555" />
+    <linearGradient
+       id="linearGradient4284"
+       x1="-2.3960868e-17"
+       x2="0.92957747"
+       xlink:href="#linearGradient893"
+       y1="3.3012049"
+       y2="-0.45783132" />
+    <radialGradient
+       cx="0.50000000"
+       cy="0.50000000"
+       fx="0.50000000"
+       fy="0.50000000"
+       id="radialGradient1977"
+       r="0.50000000"
+       xlink:href="#linearGradient1853" />
+  </defs>
+  <sodipodi:namedview
+     bordercolor="#666666"
+     borderopacity="1.0"
+     id="base"
+     inkscape:cx="62.122256"
+     inkscape:cy="81.091465"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:window-height="667"
+     inkscape:window-width="573"
+     inkscape:window-x="380"
+     inkscape:window-y="151"
+     inkscape:zoom="2"
+     pagecolor="#ffffff"
+     showborder="true"
+     showgrid="false"
+     inkscape:current-layer="Andysvg" />
+  <path
+     d="M 26.564473,83.749649 L 26.564473,121.41271 L 57.756286,121.41271"
+     id="path3723"
+     sodipodi:nodetypes="ccc"
+     style="fill:none;fill-rule:evenodd;stroke:#9c9c9c;stroke-width:5.7184987;stroke-linecap:round;stroke-linejoin:round;" />
+  <g
+     id="g2843"
+     transform="matrix(0.999379,0.000000,0.000000,0.999379,1.227893e-3,3.986513)">
+    <rect
+       height="8.3153667"
+       id="rect1906"
+       style="fill:url(#linearGradient1156);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient1157);stroke-width:1.4473482pt;"
+       transform="matrix(0.716224,0.000000,0.000000,0.716224,-12.57051,-9.652832)"
+       width="57.567924"
+       x="33.326111"
+       y="78.658051" />
+    <rect
+       height="60.126495"
+       id="rect1907"
+       rx="5.4369707"
+       ry="5.4369707"
+       style="fill:url(#linearGradient905);fill-opacity:1;fill-rule:evenodd;stroke-width:1.6282668;"
+       transform="matrix(0.716224,0.000000,0.000000,0.716224,-12.57051,-9.652832)"
+       width="72.279724"
+       x="26.015469"
+       y="22.413721" />
+    <rect
+       height="38.044163"
+       id="rect1908"
+       style="fill:url(#radialGradient1315);fill-rule:evenodd;stroke:url(#linearGradient891);stroke-width:1.4649456pt;"
+       transform="matrix(0.716224,0.000000,0.000000,0.716224,-12.57051,-9.652832)"
+       width="58.178177"
+       x="33.386066"
+       y="31.695871" />
+    <path
+       d="M 27.690431,52.841444 L 27.370609,74.749236 C 27.319624,78.241665 29.310209,80.477938 32.807578,80.506029 L 72.625393,80.825852 L 76.463254,71.870840 L 32.008024,71.551020 L 31.688202,52.681533 L 27.690431,52.841444 z "
+       id="path1909"
+       sodipodi:nodetypes="czzccccc"
+       style="fill:url(#linearGradient1146);fill-opacity:1;fill-rule:evenodd;stroke-width:1.0000000pt;"
+       transform="matrix(0.716224,0.000000,0.000000,0.716224,-12.57051,-9.652832)" />
+    <rect
+       height="26.147448"
+       id="rect1913"
+       rx="7.4449978"
+       ry="7.4449978"
+       style="fill:url(#linearGradient901);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient1157);stroke-width:2.3625000;"
+       transform="matrix(0.571582,0.000000,0.000000,0.571582,-77.72566,72.35541)"
+       width="104.09673"
+       x="140.62315"
+       y="-34.316952" />
+    <rect
+       height="15.829688"
+       id="rect1914"
+       rx="3.7576280"
+       ry="3.7576280"
+       style="fill:url(#linearGradient901);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient1157);stroke-width:1.3591428;"
+       transform="matrix(0.571582,0.000000,0.000000,0.571582,-77.72566,72.35541)"
+       width="56.908955"
+       x="184.04552"
+       y="-28.539845" />
+    <rect
+       height="15.829688"
+       id="rect1915"
+       rx="2.9970589"
+       ry="2.9970589"
+       style="fill:url(#linearGradient1141);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient1157);stroke-width:0.96249998;"
+       transform="matrix(0.571582,0.000000,0.000000,0.571582,-77.72566,72.35541)"
+       width="28.796961"
+       x="145.28902"
+       y="-28.227346" />
+    <rect
+       height="3.3627598"
+       id="rect1916"
+       rx="1.6813799"
+       ry="1.6813799"
+       style="fill-opacity:0.13836475;fill-rule:evenodd;stroke-width:0.46326005;"
+       transform="matrix(0.571582,0.000000,0.000000,0.571582,-77.72566,72.35541)"
+       width="49.231453"
+       x="187.88426"
+       y="-21.681381" />
+  </g>
+  <path
+     style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:helvetica"
+     d="M 7.0612345,-14.660837 L 7.0612345,-23.250681 L 8.2272501,-23.250681 L 12.738969,-16.50654 L 12.738969,-23.250681 L 13.828813,-23.250681 L 13.828813,-14.660837 L 12.662797,-14.660837 L 8.1510782,-21.410837 L 8.1510782,-14.660837 L 7.0612345,-14.660837 z M 19.869828,-16.664743 L 20.959672,-16.529978 C 20.787791,-15.893258 20.469432,-15.399118 20.004594,-15.047556 C 19.539745,-14.695993 18.945996,-14.520212 18.223344,-14.520212 C 17.313185,-14.520212 16.591506,-14.800485 16.058305,-15.361032 C 15.525101,-15.921578 15.2585,-16.70771 15.2585,-17.719431 C 15.2585,-18.766302 15.528031,-19.578801 16.067094,-20.156931 C 16.606155,-20.73505 17.305373,-21.024112 18.16475,-21.024118 C 18.996777,-21.024112 19.676464,-20.740909 20.203813,-20.174509 C 20.73115,-19.608098 20.994822,-18.811224 20.994828,-17.783884 C 20.994822,-17.721381 20.992869,-17.627631 20.988969,-17.502634 L 16.348344,-17.502634 C 16.387405,-16.819038 16.580764,-16.295601 16.928422,-15.932322 C 17.276076,-15.569039 17.709669,-15.387399 18.229203,-15.3874 C 18.615918,-15.387399 18.945996,-15.488961 19.219438,-15.692087 C 19.49287,-15.895211 19.709667,-16.219429 19.869828,-16.664743 L 19.869828,-16.664743 z M 16.406938,-18.369822 L 19.881547,-18.369822 C 19.834667,-18.893255 19.701855,-19.285833 19.483109,-19.547556 C 19.147168,-19.953801 18.711621,-20.156925 18.176469,-20.156931 C 17.692091,-20.156925 17.284865,-19.994816 16.954789,-19.670603 C 16.624709,-19.346379 16.442092,-18.912786 16.406938,-18.369822 L 16.406938,-18.369822 z M 24.592484,-15.604197 L 24.744828,-14.672556 C 24.44795,-14.610056 24.182326,-14.578806 23.947953,-14.578806 C 23.565139,-14.578806 23.268264,-14.639353 23.057328,-14.760447 C 22.846389,-14.88154 22.697952,-15.04072 22.612016,-15.237986 C 22.526077,-15.43525 22.483108,-15.850289 22.483109,-16.483103 L 22.483109,-20.063181 L 21.709672,-20.063181 L 21.709672,-20.883493 L 22.483109,-20.883493 L 22.483109,-22.424509 L 23.531938,-23.057322 L 23.531938,-20.883493 L 24.592484,-20.883493 L 24.592484,-20.063181 L 23.531938,-20.063181 L 23.531938,-16.424509 C 23.531936,-16.123726 23.55049,-15.930367 23.587602,-15.844431 C 23.624709,-15.758492 23.685256,-15.690133 23.769242,-15.639353 C 23.853224,-15.588571 23.973341,-15.56318 24.129594,-15.563181 C 24.246779,-15.56318 24.401075,-15.576852 24.592484,-15.604197 L 24.592484,-15.604197 z M 26.766313,-14.660837 L 24.862016,-20.883493 L 25.951859,-20.883493 L 26.942094,-17.291697 L 27.311234,-15.955759 C 27.326857,-16.022164 27.434279,-16.449898 27.6335,-17.238962 L 28.623734,-20.883493 L 29.707719,-20.883493 L 30.639359,-17.274118 L 30.949906,-16.084665 L 31.307328,-17.285837 L 32.373734,-20.883493 L 33.399125,-20.883493 L 31.453813,-14.660837 L 30.358109,-14.660837 L 29.367875,-18.3874 L 29.127641,-19.447947 L 27.867875,-14.660837 L 26.766313,-14.660837 z M 33.897172,-17.772165 C 33.897172,-18.924505 34.217484,-19.77802 34.858109,-20.332712 C 35.393264,-20.793644 36.045607,-21.024112 36.815141,-21.024118 C 37.670605,-21.024112 38.369823,-20.743839 38.912797,-20.183298 C 39.45576,-19.622746 39.727244,-18.848333 39.72725,-17.860056 C 39.727244,-17.059272 39.607127,-16.42939 39.366899,-15.970407 C 39.126659,-15.511422 38.77705,-15.154977 38.31807,-14.901072 C 37.859082,-14.647165 37.358106,-14.520212 36.815141,-14.520212 C 35.944045,-14.520212 35.239944,-14.799509 34.702836,-15.358103 C 34.165726,-15.916695 33.897172,-16.721382 33.897172,-17.772165 L 33.897172,-17.772165 z M 34.981156,-17.772165 C 34.981155,-16.975288 35.154983,-16.378609 35.502641,-15.982126 C 35.850295,-15.585641 36.287794,-15.387399 36.815141,-15.3874 C 37.338574,-15.387399 37.774121,-15.586617 38.121781,-15.985056 C 38.469433,-16.383492 38.643261,-16.990913 38.643266,-17.807322 C 38.643261,-18.576849 38.468456,-19.159856 38.118852,-19.556345 C 37.769238,-19.952824 37.334668,-20.151066 36.815141,-20.151072 C 36.287794,-20.151066 35.850295,-19.953801 35.502641,-19.559275 C 35.154983,-19.164739 34.981155,-18.569036 34.981156,-17.772165 L 34.981156,-17.772165 z M 40.957719,-14.660837 L 40.957719,-20.883493 L 41.906938,-20.883493 L 41.906938,-19.940134 C 42.149123,-20.381535 42.372756,-20.67255 42.577836,-20.813181 C 42.782912,-20.9538 43.008497,-21.024112 43.254594,-21.024118 C 43.610059,-21.024112 43.971387,-20.910831 44.338578,-20.684275 L 43.975297,-19.705759 C 43.717481,-19.858098 43.459669,-19.934269 43.201859,-19.934275 C 42.971388,-19.934269 42.764357,-19.864934 42.580766,-19.726267 C 42.39717,-19.58759 42.266311,-19.395207 42.188188,-19.149118 C 42.070998,-18.774114 42.012405,-18.363958 42.012406,-17.91865 L 42.012406,-14.660837 L 40.957719,-14.660837 z M 44.983109,-14.660837 L 44.983109,-23.250681 L 46.037797,-23.250681 L 46.037797,-18.352243 L 48.533891,-20.883493 L 49.899125,-20.883493 L 47.520219,-18.5749 L 50.139359,-14.660837 L 48.838578,-14.660837 L 46.781938,-17.842478 L 46.037797,-17.127634 L 46.037797,-14.660837 L 44.983109,-14.660837 z"
+     id="text1232" />
+  <path
+     transform="scale(0.246729,0.246729)"
+     style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:helvetica"
+     d="M 91.619637,-37.962852 L 92.756355,-37.675743 C 92.518066,-36.742148 92.089356,-36.030234 91.470222,-35.540001 C 90.851076,-35.049766 90.09424,-34.804649 89.199715,-34.804649 C 88.27393,-34.804649 87.521001,-34.993126 86.940926,-35.370079 C 86.360846,-35.747031 85.91944,-36.292929 85.616707,-37.007774 C 85.313972,-37.722615 85.162605,-38.490193 85.162605,-39.310509 C 85.162605,-40.205035 85.333503,-40.985307 85.675301,-41.651329 C 86.017096,-42.317337 86.503424,-42.823196 87.134285,-43.168907 C 87.765141,-43.514602 88.459476,-43.687453 89.217293,-43.687462 C 90.076662,-43.687453 90.799318,-43.468703 91.385262,-43.031212 C 91.971192,-42.593704 92.379394,-41.97847 92.609871,-41.185509 L 91.49073,-40.921837 C 91.291505,-41.54683 91.002443,-42.001908 90.623543,-42.287071 C 90.244631,-42.57222 89.768069,-42.714798 89.193855,-42.714806 C 88.533695,-42.714798 87.981938,-42.556595 87.538582,-42.240196 C 87.09522,-41.923783 86.783697,-41.498979 86.604012,-40.965782 C 86.424322,-40.432574 86.334479,-39.882769 86.33448,-39.316368 C 86.334479,-38.585896 86.440924,-37.948201 86.653816,-37.403282 C 86.866705,-36.858358 87.197759,-36.451132 87.64698,-36.181602 C 88.096196,-35.91207 88.582523,-35.777305 89.105965,-35.777306 C 89.742678,-35.777305 90.28174,-35.960898 90.723152,-36.328087 C 91.164552,-36.695273 91.46338,-37.240194 91.619637,-37.962852 L 91.619637,-37.962852 z M 94.016121,-34.951134 L 94.016121,-41.17379 L 94.96534,-41.17379 L 94.96534,-40.230431 C 95.207525,-40.671831 95.431158,-40.962846 95.636238,-41.103477 C 95.841314,-41.244096 96.066899,-41.314409 96.312996,-41.314415 C 96.668461,-41.314409 97.029789,-41.201127 97.39698,-40.974571 L 97.033699,-39.996056 C 96.775883,-40.148394 96.518071,-40.224566 96.260262,-40.224571 C 96.02979,-40.224566 95.822759,-40.15523 95.639168,-40.016563 C 95.455572,-39.877887 95.324713,-39.685504 95.24659,-39.439415 C 95.1294,-39.064411 95.070807,-38.654255 95.070808,-38.208946 L 95.070808,-34.951134 L 94.016121,-34.951134 z M 102.29542,-36.95504 L 103.38526,-36.820274 C 103.21338,-36.183554 102.89502,-35.689414 102.43018,-35.337852 C 101.96533,-34.98629 101.37159,-34.810509 100.64893,-34.810509 C 99.738775,-34.810509 99.017096,-35.090782 98.483894,-35.651329 C 97.950691,-36.211875 97.684089,-36.998007 97.68409,-38.009727 C 97.684089,-39.056598 97.95362,-39.869098 98.492683,-40.447227 C 99.031744,-41.025346 99.730962,-41.314409 100.59034,-41.314415 C 101.42237,-41.314409 102.10205,-41.031206 102.6294,-40.464806 C 103.15674,-39.898394 103.42041,-39.10152 103.42042,-38.074181 C 103.42041,-38.011678 103.41846,-37.917928 103.41456,-37.792931 L 98.773933,-37.792931 C 98.812994,-37.109335 99.006354,-36.585898 99.354012,-36.222618 C 99.701665,-35.859336 100.13526,-35.677696 100.65479,-35.677696 C 101.04151,-35.677696 101.37159,-35.779258 101.64503,-35.982384 C 101.91846,-36.185507 102.13526,-36.509726 102.29542,-36.95504 L 102.29542,-36.95504 z M 98.832527,-38.660118 L 102.30714,-38.660118 C 102.26026,-39.183551 102.12744,-39.576129 101.9087,-39.837852 C 101.57276,-40.244097 101.13721,-40.447222 100.60206,-40.447227 C 100.11768,-40.447222 99.710454,-40.285113 99.380379,-39.960899 C 99.050299,-39.636676 98.867682,-39.203083 98.832527,-38.660118 L 98.832527,-38.660118 z M 108.77589,-35.718712 C 108.38526,-35.38668 108.00928,-35.152305 107.64796,-35.015587 C 107.28663,-34.878868 106.89893,-34.810509 106.48487,-34.810509 C 105.80128,-34.810509 105.27589,-34.977501 104.9087,-35.311485 C 104.54151,-35.645469 104.35792,-36.072226 104.35792,-36.591759 C 104.35792,-36.896444 104.42725,-37.174764 104.56593,-37.42672 C 104.7046,-37.67867 104.88624,-37.880818 105.11085,-38.033165 C 105.33546,-38.185505 105.58838,-38.30074 105.86964,-38.378868 C 106.07667,-38.433552 106.38917,-38.486286 106.80714,-38.537071 C 107.6587,-38.63863 108.28565,-38.759724 108.688,-38.900352 C 108.6919,-39.04488 108.69385,-39.136676 108.69386,-39.175743 C 108.69385,-39.605426 108.59424,-39.90816 108.39503,-40.083946 C 108.12549,-40.322222 107.7251,-40.441363 107.19386,-40.441368 C 106.69776,-40.441363 106.33155,-40.354449 106.09522,-40.180626 C 105.85889,-40.006793 105.68409,-39.699176 105.57081,-39.257774 L 104.53956,-39.398399 C 104.63331,-39.839801 104.7876,-40.196246 105.00245,-40.467735 C 105.21729,-40.739214 105.52784,-40.948198 105.93409,-41.094688 C 106.34034,-41.241167 106.81104,-41.314409 107.3462,-41.314415 C 107.87745,-41.314409 108.30909,-41.251909 108.64112,-41.126915 C 108.97315,-41.001909 109.21729,-40.844683 109.37354,-40.655235 C 109.52979,-40.465777 109.63916,-40.226519 109.70167,-39.937462 C 109.73682,-39.75777 109.7544,-39.433551 109.7544,-38.964806 L 109.7544,-37.558556 C 109.7544,-36.578085 109.77686,-35.957969 109.82178,-35.698204 C 109.8667,-35.438438 109.95557,-35.189415 110.08839,-34.951134 L 108.98682,-34.951134 C 108.87744,-35.169884 108.80713,-35.425743 108.77589,-35.718712 L 108.77589,-35.718712 z M 108.688,-38.074181 C 108.30518,-37.917928 107.73096,-37.785115 106.96534,-37.675743 C 106.53174,-37.61324 106.2251,-37.542928 106.04542,-37.464806 C 105.86573,-37.386678 105.72706,-37.27242 105.6294,-37.122032 C 105.53174,-36.97164 105.48292,-36.804647 105.48292,-36.621056 C 105.48292,-36.339804 105.58936,-36.105429 105.80225,-35.917931 C 106.01514,-35.73043 106.32667,-35.63668 106.73682,-35.636681 C 107.14307,-35.63668 107.5044,-35.725547 107.82081,-35.903282 C 108.13721,-36.081015 108.36963,-36.324179 108.51807,-36.632774 C 108.63135,-36.871054 108.68799,-37.222616 108.688,-37.687462 L 108.688,-38.074181 z M 113.69776,-35.894493 L 113.85011,-34.962852 C 113.55323,-34.900353 113.2876,-34.869103 113.05323,-34.869102 C 112.67042,-34.869103 112.37354,-34.929649 112.16261,-35.050743 C 111.95167,-35.171837 111.80323,-35.331016 111.71729,-35.528282 C 111.63135,-35.725547 111.58839,-36.140586 111.58839,-36.773399 L 111.58839,-40.353477 L 110.81495,-40.353477 L 110.81495,-41.17379 L 111.58839,-41.17379 L 111.58839,-42.714806 L 112.63721,-43.347618 L 112.63721,-41.17379 L 113.69776,-41.17379 L 113.69776,-40.353477 L 112.63721,-40.353477 L 112.63721,-36.714806 C 112.63721,-36.414023 112.65577,-36.220664 112.69288,-36.134727 C 112.72999,-36.048789 112.79053,-35.98043 112.87452,-35.929649 C 112.9585,-35.878867 113.07862,-35.853477 113.23487,-35.853477 C 113.35206,-35.853477 113.50635,-35.867148 113.69776,-35.894493 L 113.69776,-35.894493 z M 118.98292,-36.95504 L 120.07276,-36.820274 C 119.90088,-36.183554 119.58252,-35.689414 119.11768,-35.337852 C 118.65283,-34.98629 118.05909,-34.810509 117.33643,-34.810509 C 116.42627,-34.810509 115.7046,-35.090782 115.17139,-35.651329 C 114.63819,-36.211875 114.37159,-36.998007 114.37159,-38.009727 C 114.37159,-39.056598 114.64112,-39.869098 115.18018,-40.447227 C 115.71924,-41.025346 116.41846,-41.314409 117.27784,-41.314415 C 118.10987,-41.314409 118.78955,-41.031206 119.3169,-40.464806 C 119.84424,-39.898394 120.10791,-39.10152 120.10792,-38.074181 C 120.10791,-38.011678 120.10596,-37.917928 120.10206,-37.792931 L 115.46143,-37.792931 C 115.50049,-37.109335 115.69385,-36.585898 116.04151,-36.222618 C 116.38917,-35.859336 116.82276,-35.677696 117.34229,-35.677696 C 117.72901,-35.677696 118.05909,-35.779258 118.33253,-35.982384 C 118.60596,-36.185507 118.82276,-36.509726 118.98292,-36.95504 L 118.98292,-36.95504 z M 115.52003,-38.660118 L 118.99464,-38.660118 C 118.94776,-39.183551 118.81494,-39.576129 118.5962,-39.837852 C 118.26026,-40.244097 117.82471,-40.447222 117.28956,-40.447227 C 116.80518,-40.447222 116.39795,-40.285113 116.06788,-39.960899 C 115.7378,-39.636676 115.55518,-39.203083 115.52003,-38.660118 L 115.52003,-38.660118 z M 125.43995,-34.951134 L 125.43995,-35.73629 C 125.04541,-35.119102 124.46534,-34.810509 123.69971,-34.810509 C 123.20362,-34.810509 122.74756,-34.947227 122.33155,-35.220665 C 121.91553,-35.494102 121.59327,-35.875937 121.36475,-36.366173 C 121.13624,-36.856405 121.02198,-37.419881 121.02198,-38.056602 C 121.02198,-38.677693 121.1255,-39.241169 121.33253,-39.747032 C 121.53956,-40.252886 121.8501,-40.640581 122.26417,-40.910118 C 122.67823,-41.179643 123.14112,-41.314409 123.65284,-41.314415 C 124.02784,-41.314409 124.36182,-41.235307 124.65479,-41.07711 C 124.94776,-40.918901 125.18604,-40.712847 125.36964,-40.458946 L 125.36964,-43.540977 L 126.41846,-43.540977 L 126.41846,-34.951134 L 125.43995,-34.951134 z M 122.10596,-38.056602 C 122.10596,-37.259725 122.27393,-36.664023 122.60987,-36.269493 C 122.94581,-35.874961 123.34229,-35.677696 123.79932,-35.677696 C 124.26026,-35.677696 124.65186,-35.866172 124.97413,-36.243126 C 125.29639,-36.620077 125.45752,-37.195272 125.45753,-37.968712 C 125.45752,-38.82027 125.29346,-39.44527 124.96534,-39.843712 C 124.63721,-40.242144 124.23291,-40.441363 123.75245,-40.441368 C 123.2837,-40.441363 122.8921,-40.249957 122.57764,-39.867149 C 122.26319,-39.484332 122.10596,-38.880817 122.10596,-38.056602 L 122.10596,-38.056602 z M 132.38331,-34.951134 L 131.40479,-34.951134 L 131.40479,-43.540977 L 132.45948,-43.540977 L 132.45948,-40.476524 C 132.90479,-41.035112 133.47315,-41.314409 134.16456,-41.314415 C 134.54737,-41.314409 134.90967,-41.23726 135.25147,-41.08297 C 135.59326,-40.928667 135.87451,-40.71187 136.09522,-40.432579 C 136.31592,-40.153277 136.48877,-39.816363 136.61378,-39.421837 C 136.73877,-39.027302 136.80127,-38.605427 136.80128,-38.156212 C 136.80127,-37.089803 136.5376,-36.265586 136.01026,-35.683556 C 135.48291,-35.101524 134.8501,-34.810509 134.11182,-34.810509 C 133.37745,-34.810509 132.80127,-35.117149 132.38331,-35.730431 L 132.38331,-34.951134 z M 132.37159,-38.109337 C 132.37159,-37.363241 132.47315,-36.824179 132.67628,-36.492149 C 133.00831,-35.94918 133.45752,-35.677696 134.02393,-35.677696 C 134.48487,-35.677696 134.8833,-35.877891 135.21925,-36.278282 C 135.55518,-36.678671 135.72315,-37.27535 135.72315,-38.068321 C 135.72315,-38.880817 135.56201,-39.480426 135.23975,-39.867149 C 134.91748,-40.253863 134.52784,-40.447222 134.07081,-40.447227 C 133.60987,-40.447222 133.21143,-40.247027 132.8755,-39.846642 C 132.53956,-39.446246 132.37159,-38.867145 132.37159,-38.109337 L 132.37159,-38.109337 z M 138.04346,-32.554649 L 137.92628,-33.544884 C 138.15675,-33.482385 138.35792,-33.451135 138.52979,-33.451134 C 138.76417,-33.451135 138.95167,-33.490198 139.09229,-33.568321 C 139.23292,-33.646448 139.34815,-33.755822 139.438,-33.896446 C 139.5044,-34.001916 139.61182,-34.263634 139.76026,-34.681602 C 139.77979,-34.740196 139.81104,-34.826134 139.85401,-34.939415 L 137.49268,-41.17379 L 138.6294,-41.17379 L 139.92432,-37.570274 C 140.09229,-37.113241 140.24268,-36.632773 140.3755,-36.128868 C 140.49659,-36.613241 140.64112,-37.085897 140.80909,-37.546837 L 142.13917,-41.17379 L 143.19386,-41.17379 L 140.82667,-34.845665 C 140.57276,-34.162072 140.37549,-33.691369 140.23487,-33.433556 C 140.04737,-33.085901 139.83252,-32.831019 139.59034,-32.668907 C 139.34815,-32.5068 139.05909,-32.425746 138.72315,-32.425743 C 138.52003,-32.425746 138.29346,-32.468714 138.04346,-32.554649 L 138.04346,-32.554649 z M 146.60987,-34.951134 L 149.9087,-43.540977 L 151.13331,-43.540977 L 154.64893,-34.951134 L 153.35401,-34.951134 L 152.35206,-37.552696 L 148.76026,-37.552696 L 147.8169,-34.951134 L 146.60987,-34.951134 z M 149.08839,-38.478477 L 152.0005,-38.478477 L 151.10401,-40.857384 C 150.83057,-41.580033 150.62745,-42.173783 150.49464,-42.638634 C 150.38526,-42.087845 150.23096,-41.540971 150.03175,-40.998009 L 149.08839,-38.478477 z M 155.43409,-34.951134 L 155.43409,-41.17379 L 156.38331,-41.17379 L 156.38331,-40.289024 C 156.84034,-40.972612 157.50049,-41.314409 158.36378,-41.314415 C 158.73877,-41.314409 159.0835,-41.247026 159.39796,-41.112267 C 159.7124,-40.977495 159.94776,-40.800737 160.10401,-40.581993 C 160.26026,-40.363238 160.36963,-40.103472 160.43214,-39.802696 C 160.47119,-39.607379 160.49072,-39.265583 160.49073,-38.777306 L 160.49073,-34.951134 L 159.43604,-34.951134 L 159.43604,-38.73629 C 159.43604,-39.165973 159.39502,-39.487262 159.313,-39.700157 C 159.23096,-39.913043 159.08545,-40.082965 158.87647,-40.209923 C 158.66748,-40.336871 158.42237,-40.400347 158.14112,-40.400352 C 157.6919,-40.400347 157.3042,-40.257769 156.97803,-39.972618 C 156.65186,-39.687457 156.48878,-39.146442 156.48878,-38.349571 L 156.48878,-34.951134 L 155.43409,-34.951134 z M 166.15089,-34.951134 L 166.15089,-35.73629 C 165.75635,-35.119102 165.17627,-34.810509 164.41065,-34.810509 C 163.91456,-34.810509 163.4585,-34.947227 163.04249,-35.220665 C 162.62647,-35.494102 162.30421,-35.875937 162.07569,-36.366173 C 161.84718,-36.856405 161.73292,-37.419881 161.73292,-38.056602 C 161.73292,-38.677693 161.83643,-39.241169 162.04346,-39.747032 C 162.25049,-40.252886 162.56104,-40.640581 162.97511,-40.910118 C 163.38917,-41.179643 163.85206,-41.314409 164.36378,-41.314415 C 164.73877,-41.314409 165.07276,-41.235307 165.36573,-41.07711 C 165.65869,-40.918901 165.89698,-40.712847 166.08057,-40.458946 L 166.08057,-43.540977 L 167.1294,-43.540977 L 167.1294,-34.951134 L 166.15089,-34.951134 z M 162.8169,-38.056602 C 162.8169,-37.259725 162.98487,-36.664023 163.32081,-36.269493 C 163.65674,-35.874961 164.05323,-35.677696 164.51026,-35.677696 C 164.9712,-35.677696 165.3628,-35.866172 165.68507,-36.243126 C 166.00733,-36.620077 166.16846,-37.195272 166.16846,-37.968712 C 166.16846,-38.82027 166.0044,-39.44527 165.67628,-39.843712 C 165.34815,-40.242144 164.94385,-40.441363 164.46339,-40.441368 C 163.99463,-40.441363 163.60303,-40.249957 163.28858,-39.867149 C 162.97413,-39.484332 162.8169,-38.880817 162.8169,-38.056602 L 162.8169,-38.056602 z M 168.78175,-34.951134 L 168.78175,-41.17379 L 169.73096,-41.17379 L 169.73096,-40.230431 C 169.97315,-40.671831 170.19678,-40.962846 170.40186,-41.103477 C 170.60694,-41.244096 170.83252,-41.314409 171.07862,-41.314415 C 171.43409,-41.314409 171.79541,-41.201127 172.16261,-40.974571 L 171.79932,-39.996056 C 171.54151,-40.148394 171.2837,-40.224566 171.02589,-40.224571 C 170.79541,-40.224566 170.58838,-40.15523 170.40479,-40.016563 C 170.2212,-39.877887 170.09034,-39.685504 170.01221,-39.439415 C 169.89503,-39.064411 169.83643,-38.654255 169.83643,-38.208946 L 169.83643,-34.951134 L 168.78175,-34.951134 z M 177.06104,-36.95504 L 178.15089,-36.820274 C 177.97901,-36.183554 177.66065,-35.689414 177.19581,-35.337852 C 176.73096,-34.98629 176.13721,-34.810509 175.41456,-34.810509 C 174.5044,-34.810509 173.78272,-35.090782 173.24952,-35.651329 C 172.71632,-36.211875 172.44971,-36.998007 172.44971,-38.009727 C 172.44971,-39.056598 172.71925,-39.869098 173.25831,-40.447227 C 173.79737,-41.025346 174.49659,-41.314409 175.35596,-41.314415 C 176.18799,-41.314409 176.86768,-41.031206 177.39503,-40.464806 C 177.92236,-39.898394 178.18604,-39.10152 178.18604,-38.074181 C 178.18604,-38.011678 178.18408,-37.917928 178.18018,-37.792931 L 173.53956,-37.792931 C 173.57862,-37.109335 173.77198,-36.585898 174.11964,-36.222618 C 174.46729,-35.859336 174.90088,-35.677696 175.42042,-35.677696 C 175.80713,-35.677696 176.13721,-35.779258 176.41065,-35.982384 C 176.68408,-36.185507 176.90088,-36.509726 177.06104,-36.95504 L 177.06104,-36.95504 z M 173.59815,-38.660118 L 177.07276,-38.660118 C 177.02588,-39.183551 176.89307,-39.576129 176.67432,-39.837852 C 176.33838,-40.244097 175.90284,-40.447222 175.36768,-40.447227 C 174.88331,-40.447222 174.47608,-40.285113 174.146,-39.960899 C 173.81592,-39.636676 173.63331,-39.203083 173.59815,-38.660118 L 173.59815,-38.660118 z M 180.6294,-34.951134 L 178.72511,-41.17379 L 179.81495,-41.17379 L 180.80518,-37.581993 L 181.17432,-36.246056 C 181.18995,-36.31246 181.29737,-36.740194 181.49659,-37.529259 L 182.48682,-41.17379 L 183.57081,-41.17379 L 184.50245,-37.564415 L 184.813,-36.374962 L 185.17042,-37.576134 L 186.23682,-41.17379 L 187.26221,-41.17379 L 185.3169,-34.951134 L 184.2212,-34.951134 L 183.23096,-38.677696 L 182.99073,-39.738243 L 181.73096,-34.951134 L 180.6294,-34.951134 z M 191.67432,-34.951134 L 191.67432,-43.540977 L 197.46925,-43.540977 L 197.46925,-42.527306 L 192.81104,-42.527306 L 192.81104,-39.867149 L 196.84229,-39.867149 L 196.84229,-38.853477 L 192.81104,-38.853477 L 192.81104,-34.951134 L 191.67432,-34.951134 z M 198.82276,-42.328087 L 198.82276,-43.540977 L 199.87745,-43.540977 L 199.87745,-42.328087 L 198.82276,-42.328087 z M 198.82276,-34.951134 L 198.82276,-41.17379 L 199.87745,-41.17379 L 199.87745,-34.951134 L 198.82276,-34.951134 z M 203.79151,-35.894493 L 203.94386,-34.962852 C 203.64698,-34.900353 203.38135,-34.869103 203.14698,-34.869102 C 202.76417,-34.869103 202.46729,-34.929649 202.25636,-35.050743 C 202.04542,-35.171837 201.89698,-35.331016 201.81104,-35.528282 C 201.7251,-35.725547 201.68214,-36.140586 201.68214,-36.773399 L 201.68214,-40.353477 L 200.9087,-40.353477 L 200.9087,-41.17379 L 201.68214,-41.17379 L 201.68214,-42.714806 L 202.73096,-43.347618 L 202.73096,-41.17379 L 203.79151,-41.17379 L 203.79151,-40.353477 L 202.73096,-40.353477 L 202.73096,-36.714806 C 202.73096,-36.414023 202.74952,-36.220664 202.78663,-36.134727 C 202.82374,-36.048789 202.88428,-35.98043 202.96827,-35.929649 C 203.05225,-35.878867 203.17237,-35.853477 203.32862,-35.853477 C 203.44581,-35.853477 203.6001,-35.867148 203.79151,-35.894493 L 203.79151,-35.894493 z M 204.26026,-34.951134 L 204.26026,-35.806602 L 208.2212,-40.353477 C 207.77198,-40.330035 207.37549,-40.318316 207.03175,-40.318321 L 204.49464,-40.318321 L 204.49464,-41.17379 L 209.58057,-41.17379 L 209.58057,-40.476524 L 206.21143,-36.527306 L 205.56104,-35.806602 C 206.0337,-35.841758 206.47706,-35.859336 206.89112,-35.859337 L 209.76807,-35.859337 L 209.76807,-34.951134 L 204.26026,-34.951134 z M 210.39503,-36.808556 L 211.438,-36.972618 C 211.49659,-36.554648 211.65967,-36.234336 211.92725,-36.011681 C 212.19483,-35.789024 212.56885,-35.677696 213.04932,-35.677696 C 213.5337,-35.677696 213.89307,-35.776328 214.12745,-35.973595 C 214.36182,-36.170859 214.47901,-36.402304 214.47901,-36.667931 C 214.47901,-36.90621 214.37549,-37.09371 214.16846,-37.230431 C 214.02393,-37.324178 213.66455,-37.443319 213.09034,-37.587852 C 212.3169,-37.783162 211.78077,-37.952107 211.48194,-38.094688 C 211.18311,-38.237263 210.95655,-38.434529 210.80225,-38.686485 C 210.64796,-38.938434 210.57081,-39.216754 210.57081,-39.521446 C 210.57081,-39.798785 210.63428,-40.055621 210.76124,-40.291954 C 210.88819,-40.528277 211.06104,-40.724565 211.27979,-40.880821 C 211.44385,-41.001909 211.66749,-41.104448 211.95069,-41.188438 C 212.23389,-41.272416 212.5376,-41.314409 212.86182,-41.314415 C 213.3501,-41.314409 213.77881,-41.244096 214.14796,-41.103477 C 214.51709,-40.962846 214.78955,-40.772417 214.96534,-40.532188 C 215.14112,-40.291949 215.26221,-39.97066 215.32862,-39.568321 L 214.29737,-39.427696 C 214.25049,-39.748004 214.11475,-39.998004 213.89014,-40.177696 C 213.66553,-40.357378 213.34815,-40.447222 212.938,-40.447227 C 212.45362,-40.447222 212.10792,-40.367144 211.90089,-40.206993 C 211.69385,-40.046832 211.59034,-39.859332 211.59034,-39.644493 C 211.59034,-39.50777 211.63331,-39.384723 211.71925,-39.275352 C 211.80518,-39.162067 211.93995,-39.068317 212.12354,-38.994102 C 212.22901,-38.955036 212.53956,-38.865192 213.05518,-38.724571 C 213.80127,-38.525349 214.32178,-38.362263 214.61671,-38.235313 C 214.91162,-38.108357 215.14307,-37.923787 215.31104,-37.681602 C 215.47901,-37.439412 215.56299,-37.138632 215.563,-36.779259 C 215.56299,-36.427695 215.46045,-36.09664 215.25538,-35.786095 C 215.0503,-35.475547 214.7544,-35.235313 214.36768,-35.065392 C 213.98096,-34.89547 213.54346,-34.810509 213.05518,-34.810509 C 212.24659,-34.810509 211.63038,-34.978477 211.20655,-35.314415 C 210.78272,-35.650352 210.51221,-36.148398 210.39503,-36.808556 L 210.39503,-36.808556 z M 216.82276,-42.328087 L 216.82276,-43.540977 L 217.87745,-43.540977 L 217.87745,-42.328087 L 216.82276,-42.328087 z M 216.82276,-34.951134 L 216.82276,-41.17379 L 217.87745,-41.17379 L 217.87745,-34.951134 L 216.82276,-34.951134 z M 219.48878,-34.951134 L 219.48878,-41.17379 L 220.43214,-41.17379 L 220.43214,-40.300743 C 220.62745,-40.605425 220.88721,-40.850542 221.21143,-41.036095 C 221.53565,-41.221635 221.90479,-41.314409 222.31886,-41.314415 C 222.77979,-41.314409 223.15772,-41.218706 223.45264,-41.027306 C 223.74756,-40.835893 223.95557,-40.568316 224.07667,-40.224571 C 224.56885,-40.951128 225.20947,-41.314409 225.99854,-41.314415 C 226.61572,-41.314409 227.09033,-41.14351 227.42237,-40.80172 C 227.75439,-40.459917 227.92041,-39.933551 227.92042,-39.222618 L 227.92042,-34.951134 L 226.87159,-34.951134 L 226.87159,-38.871056 C 226.87158,-39.292926 226.8374,-39.596637 226.76905,-39.782188 C 226.70068,-39.96773 226.57666,-40.117144 226.39698,-40.230431 C 226.21729,-40.343706 226.00635,-40.400347 225.76417,-40.400352 C 225.32666,-40.400347 224.96338,-40.254839 224.67432,-39.963829 C 224.38526,-39.672809 224.24072,-39.206989 224.24073,-38.566368 L 224.24073,-34.951134 L 223.18604,-34.951134 L 223.18604,-38.994102 C 223.18604,-39.462848 223.1001,-39.81441 222.92823,-40.04879 C 222.75635,-40.28316 222.4751,-40.400347 222.08448,-40.400352 C 221.7876,-40.400347 221.51319,-40.322222 221.26124,-40.165977 C 221.00928,-40.009722 220.82667,-39.781207 220.71339,-39.480431 C 220.6001,-39.179645 220.54346,-38.746052 220.54346,-38.179649 L 220.54346,-34.951134 L 219.48878,-34.951134 z M 229.10401,-38.062462 C 229.10401,-39.214801 229.42432,-40.068316 230.06495,-40.623009 C 230.6001,-41.08394 231.25245,-41.314409 232.02198,-41.314415 C 232.87744,-41.314409 233.57666,-41.034135 234.11964,-40.473595 C 234.6626,-39.913043 234.93408,-39.13863 234.93409,-38.150352 C 234.93408,-37.349569 234.81397,-36.719687 234.57374,-36.260704 C 234.3335,-35.801719 233.98389,-35.445274 233.52491,-35.191368 C 233.06592,-34.937462 232.56495,-34.810509 232.02198,-34.810509 C 231.15088,-34.810509 230.44678,-35.089805 229.90968,-35.648399 C 229.37257,-36.206992 229.10401,-37.011679 229.10401,-38.062462 L 229.10401,-38.062462 z M 230.188,-38.062462 C 230.18799,-37.265585 230.36182,-36.668905 230.70948,-36.272423 C 231.05713,-35.875937 231.49463,-35.677696 232.02198,-35.677696 C 232.54541,-35.677696 232.98096,-35.876914 233.32862,-36.275352 C 233.67627,-36.673788 233.8501,-37.28121 233.85011,-38.097618 C 233.8501,-38.867145 233.6753,-39.450153 233.32569,-39.846642 C 232.97608,-40.243121 232.54151,-40.441363 232.02198,-40.441368 C 231.49463,-40.441363 231.05713,-40.244097 230.70948,-39.849571 C 230.36182,-39.455035 230.18799,-38.859333 230.188,-38.062462 L 230.188,-38.062462 z M 236.17628,-34.951134 L 236.17628,-41.17379 L 237.1255,-41.17379 L 237.1255,-40.289024 C 237.58252,-40.972612 238.24268,-41.314409 239.10596,-41.314415 C 239.48096,-41.314409 239.82569,-41.247026 240.14014,-41.112267 C 240.45459,-40.977495 240.68994,-40.800737 240.8462,-40.581993 C 241.00244,-40.363238 241.11182,-40.103472 241.17432,-39.802696 C 241.21338,-39.607379 241.23291,-39.265583 241.23292,-38.777306 L 241.23292,-34.951134 L 240.17823,-34.951134 L 240.17823,-38.73629 C 240.17823,-39.165973 240.13721,-39.487262 240.05518,-39.700157 C 239.97315,-39.913043 239.82764,-40.082965 239.61866,-40.209923 C 239.40967,-40.336871 239.16455,-40.400347 238.88331,-40.400352 C 238.43409,-40.400347 238.04639,-40.257769 237.72022,-39.972618 C 237.39405,-39.687457 237.23096,-39.146442 237.23096,-38.349571 L 237.23096,-34.951134 L 236.17628,-34.951134 z"
+     id="text1235" />
+  <g
+     id="g2852"
+     transform="matrix(1.018857,0.000000,0.000000,1.018857,-4.481650,2.131177)">
+    <rect
+       height="8.3153667"
+       id="rect1866"
+       style="fill:url(#linearGradient1156);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient1157);stroke-width:1.4473482pt;"
+       transform="matrix(1.150066,0.000000,0.000000,1.150066,38.98882,26.86863)"
+       width="57.567924"
+       x="33.326111"
+       y="78.658051" />
+    <rect
+       height="60.126495"
+       id="rect1867"
+       rx="5.4369707"
+       ry="5.4369707"
+       style="fill:url(#linearGradient905);fill-opacity:1;fill-rule:evenodd;stroke-width:1.6282668;"
+       transform="matrix(1.150066,0.000000,0.000000,1.150066,38.98882,26.86863)"
+       width="72.279724"
+       x="26.015469"
+       y="22.413721" />
+    <rect
+       height="38.044163"
+       id="rect1868"
+       style="fill:url(#radialGradient1132);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient891);stroke-width:1.4649456pt;"
+       transform="matrix(1.150066,0.000000,0.000000,1.150066,38.98882,26.86863)"
+       width="58.178177"
+       x="33.386066"
+       y="31.695871" />
+    <path
+       d="M 27.690431,52.841444 L 27.370609,74.749236 C 27.319624,78.241665 29.310209,80.477938 32.807578,80.506029 L 72.625393,80.825852 L 76.463254,71.870840 L 32.008024,71.551020 L 31.688202,52.681533 L 27.690431,52.841444 z "
+       id="path1869"
+       sodipodi:nodetypes="czzccccc"
+       style="fill:url(#linearGradient1146);fill-opacity:1;fill-rule:evenodd;stroke-width:1.0000000pt;"
+       transform="matrix(1.150066,0.000000,0.000000,1.150066,38.98882,26.86863)" />
+    <g
+       id="g1870"
+       transform="matrix(1.150066,0.000000,0.000000,1.150066,38.98882,26.86863)">
+      <path
+         d="M 42.062098,33.460351 L 77.341205,33.008055 C 82.787126,32.938235 89.553204,38.416797 89.553204,43.863165 L 89.553204,60.145830 L 41.609801,59.693534 L 42.062098,33.460351 z "
+         id="path1871"
+         sodipodi:nodetypes="czzccc"
+         style="fill:url(#linearGradient1148);fill-opacity:1;fill-rule:evenodd;stroke-width:1.0000000pt;" />
+      <path
+         d="M 78.337784,67.629235 L 46.723745,67.724544 C 41.843589,67.739257 35.829319,62.771024 35.877168,57.891081 L 36.020221,43.301821 L 78.973514,44.128288 L 78.337784,67.629235 z "
+         id="path1872"
+         sodipodi:nodetypes="czzccc"
+         style="fill:url(#linearGradient1150);fill-opacity:1;fill-rule:evenodd;stroke-width:1.0000000pt;" />
+    </g>
+    <rect
+       height="26.147448"
+       id="rect1888"
+       rx="7.4449978"
+       ry="7.4449978"
+       style="fill:url(#linearGradient901);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient1157);stroke-width:2.3625000;"
+       transform="matrix(0.917809,0.000000,0.000000,0.917809,-65.63305,158.5521)"
+       width="104.09673"
+       x="140.62315"
+       y="-34.316952" />
+    <rect
+       height="15.829688"
+       id="rect1889"
+       rx="3.7576280"
+       ry="3.7576280"
+       style="fill:url(#linearGradient901);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient1157);stroke-width:1.3591428;"
+       transform="matrix(0.917809,0.000000,0.000000,0.917809,-65.63305,158.5521)"
+       width="56.908955"
+       x="184.04552"
+       y="-28.539845" />
+    <rect
+       height="15.829688"
+       id="rect1890"
+       rx="2.9970589"
+       ry="2.9970589"
+       style="fill:url(#linearGradient1141);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient1157);stroke-width:0.96249998;"
+       transform="matrix(0.917809,0.000000,0.000000,0.917809,-65.63305,158.5521)"
+       width="28.796961"
+       x="145.28902"
+       y="-28.227346" />
+    <rect
+       height="3.3627598"
+       id="rect1891"
+       rx="1.6813799"
+       ry="1.6813799"
+       style="fill-opacity:0.16981132;fill-rule:evenodd;stroke-width:0.46326005;"
+       transform="matrix(0.917809,0.000000,0.000000,0.917809,-65.63305,158.5521)"
+       width="49.231453"
+       x="187.88426"
+       y="-21.681381" />
+  </g>
+</svg>
diff --git a/wpa_supplicant/wpa_gui-qt4/icons/invitation.svg b/wpa_supplicant/wpa_gui-qt4/icons/invitation.svg
new file mode 100644 (file)
index 0000000..1a02d13
--- /dev/null
@@ -0,0 +1,374 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="64.000000px"
+   height="64.000000px"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.42"
+   sodipodi:docbase="G:\Projs\Cliparts Stocker\released"
+   sodipodi:docname="unknown_green.svg"
+   inkscape:export-filename="/datas/wiki/unknown_green.png"
+   inkscape:export-xdpi="90.000000"
+   inkscape:export-ydpi="90.000000">
+  <defs
+     id="defs4">
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2842"
+       id="linearGradient1363"
+       x1="25.403513"
+       y1="19.175573"
+       x2="35.541985"
+       y2="49.068703"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-2.402975,4.759656e-3)" />
+    <linearGradient
+       id="linearGradient2900">
+      <stop
+         id="stop2902"
+         offset="0.0000000"
+         style="stop-color:#ffffff;stop-opacity:1.0000000;" />
+      <stop
+         id="stop2904"
+         offset="1.0000000"
+         style="stop-color:#ffffff;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2842">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop2844" />
+      <stop
+         style="stop-color:#c8c8c8;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop2846" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2814">
+      <stop
+         id="stop2816"
+         offset="0.0000000"
+         style="stop-color:#e6e6e6;stop-opacity:1.0000000;" />
+      <stop
+         id="stop2818"
+         offset="1.0000000"
+         style="stop-color:#11661d;stop-opacity:0.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2171">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop2173" />
+      <stop
+         style="stop-color:#a3a5ee;stop-opacity:0.0000000;"
+         offset="1.0000000"
+         id="stop2175" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2160">
+      <stop
+         id="stop2162"
+         offset="0.0000000"
+         style="stop-color:#d3cece;stop-opacity:1.0000000;" />
+      <stop
+         id="stop2164"
+         offset="1.0000000"
+         style="stop-color:#474240;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient1367">
+      <stop
+         id="stop1369"
+         offset="0.0000000"
+         style="stop-color:#f67e36;stop-opacity:1.0000000;" />
+      <stop
+         id="stop1371"
+         offset="1.0000000"
+         style="stop-color:#602604;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient1347">
+      <stop
+         style="stop-color:#f0da27;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop1349" />
+      <stop
+         style="stop-color:#bf4d09;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop1351" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient1315">
+      <stop
+         style="stop-color:#97ff82;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop1317" />
+      <stop
+         style="stop-color:#ceff24;stop-opacity:0.0000000;"
+         offset="1.0000000"
+         id="stop1319" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2122">
+      <stop
+         style="stop-color:#2edc32;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop2124" />
+      <stop
+         style="stop-color:#11661d;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop2126" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient1364">
+      <stop
+         style="stop-color:#236b0d;stop-opacity:1.0000000;"
+         offset="0.00000000"
+         id="stop1366" />
+      <stop
+         style="stop-color:#0a2205;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop1368" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient1367"
+       id="radialGradient1402"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.211118e-16,1.330643,-1.347411,2.027373e-5,44.09678,-13.39507)"
+       cx="21.959658"
+       cy="14.921703"
+       fx="21.959658"
+       fy="14.921703"
+       r="27.500000" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2122"
+       id="radialGradient1404"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.211118e-16,1.330643,-1.347411,2.027373e-5,44.09678,-13.39507)"
+       cx="21.959658"
+       cy="14.921703"
+       fx="21.959658"
+       fy="14.921703"
+       r="27.500000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient1364"
+       id="linearGradient1419"
+       gradientUnits="userSpaceOnUse"
+       x1="74.910713"
+       y1="32.362179"
+       x2="84.910713"
+       y2="47.451466" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2122"
+       id="linearGradient1421"
+       gradientUnits="userSpaceOnUse"
+       x1="73.839287"
+       y1="34.428566"
+       x2="76.875000"
+       y2="43.714283" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient1315"
+       id="linearGradient1423"
+       gradientUnits="userSpaceOnUse"
+       x1="72.946426"
+       y1="35.589287"
+       x2="85.000000"
+       y2="47.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2171"
+       id="linearGradient2177"
+       x1="24.916031"
+       y1="28.824427"
+       x2="39.816792"
+       y2="49.099239"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2122"
+       id="radialGradient2184"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(9.909149e-17,1.088708,-1.102427,1.658760e-5,41.48828,-4.732338)"
+       cx="21.959658"
+       cy="14.921703"
+       fx="21.959658"
+       fy="14.921703"
+       r="27.500000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient1364"
+       id="linearGradient2189"
+       x1="10.018247"
+       y1="8.6306763"
+       x2="63.487556"
+       y2="63.660282"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2171"
+       id="linearGradient1339"
+       gradientUnits="userSpaceOnUse"
+       x1="24.916031"
+       y1="28.824427"
+       x2="39.816792"
+       y2="49.099239" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2122"
+       id="radialGradient1343"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.521415e-2,1.026125,-0.978137,2.404729e-2,38.83024,-3.575704)"
+       cx="24.764277"
+       cy="16.361967"
+       fx="24.764277"
+       fy="16.361967"
+       r="27.500000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient1364"
+       id="linearGradient1346"
+       gradientUnits="userSpaceOnUse"
+       x1="10.018247"
+       y1="8.6306763"
+       x2="63.487556"
+       y2="63.660282" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2814"
+       id="radialGradient2812"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.142398e-2,1.098850,-1.843995,1.878760e-2,52.15051,-5.667446)"
+       cx="18.387238"
+       cy="14.046815"
+       fx="18.387238"
+       fy="14.046815"
+       r="27.500000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient1364"
+       id="linearGradient2832"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-2.841000e-3,-2.841000e-3)"
+       x1="10.018247"
+       y1="8.6306763"
+       x2="63.487556"
+       y2="63.660282" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2842"
+       id="linearGradient2848"
+       x1="-0.56685609"
+       y1="22.651009"
+       x2="-0.33713850"
+       y2="23.858734"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2842"
+       id="linearGradient2864"
+       gradientUnits="userSpaceOnUse"
+       x1="-0.82287467"
+       y1="22.444542"
+       x2="-0.33713850"
+       y2="23.858734" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="8.2031250"
+     inkscape:cx="32.000000"
+     inkscape:cy="32.000000"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:grid-bbox="true"
+     inkscape:grid-points="true"
+     inkscape:window-width="1156"
+     inkscape:window-height="693"
+     inkscape:window-x="0"
+     inkscape:window-y="25"
+     showguides="false" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title>Green Unknown</dc:title>
+        <dc:date>2005-11-01</dc:date>
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Jean-Victor Balin</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:description>jean.victor.balin@gmail.com</dc:description>
+        <cc:license
+           rdf:resource="http://web.resource.org/cc/PublicDomain" />
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>icon</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+      </cc:Work>
+      <cc:License
+         rdf:about="http://web.resource.org/cc/PublicDomain">
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Reproduction" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Distribution" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <g
+       id="g1354">
+      <path
+         id="path1373"
+         d="M 32.000000,8.6306766 C 19.113097,8.6306766 8.6306766,19.113097 8.6306766,32.000000 C 8.6306766,44.886903 19.113097,55.369323 32.000000,55.369323 C 44.886903,55.369323 55.369323,44.886903 55.369323,32.000000 C 55.369323,19.113097 44.886903,8.6306766 32.000000,8.6306766 z "
+         style="fill:url(#linearGradient1346);fill-opacity:1.0000000;stroke:none;stroke-width:2.0000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+      <path
+         id="path1339"
+         d="M 54.500005,32.000000 C 54.500005,44.420003 44.420003,54.500005 32.000000,54.500005 C 19.579997,54.500005 9.4999950,44.420003 9.4999950,32.000000 C 9.4999950,19.579997 19.579997,9.4999950 32.000000,9.4999950 C 44.420003,9.4999950 54.500005,19.579997 54.500005,32.000000 z "
+         style="fill:url(#radialGradient1343);fill-opacity:1.0000000;stroke:none;stroke-width:2.0000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+      <path
+         id="path1341"
+         d="M 32.016991,9.1562500 C 22.574792,9.1562500 14.505423,14.865048 11.062500,22.968750 C 16.006322,25.801817 21.393258,27.855853 27.181339,27.593750 C 32.755311,27.279922 37.553510,23.530916 43.236968,23.812500 C 47.451058,23.716455 52.244330,25.294372 54.488550,29.000000 C 53.142630,17.846718 43.657640,9.1562500 32.016991,9.1562500 z "
+         style="fill:url(#radialGradient2812);fill-opacity:1.0000000;stroke:none;stroke-width:2.0000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+      <path
+         id="path2827"
+         d="M 32.000000,8.6250000 C 19.113098,8.6250000 8.6250000,19.113097 8.6250000,32.000000 C 8.6250000,44.886904 19.113097,55.375000 32.000000,55.375000 C 44.886904,55.375000 55.375000,44.886903 55.375000,32.000000 C 55.375000,19.113098 44.886903,8.6250000 32.000000,8.6250000 z M 32.000000,9.5000000 C 44.420004,9.4999998 54.500000,19.579997 54.500000,32.000000 C 54.499998,44.420004 44.420003,54.500000 32.000000,54.500000 C 19.579998,54.499998 9.5000000,44.420003 9.5000000,32.000000 C 9.5000000,19.579998 19.579997,9.5000000 32.000000,9.5000000 z "
+         style="fill:url(#linearGradient2832);fill-opacity:1.0000000;stroke:none;stroke-width:2.0000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+      <path
+         id="text1353"
+         d="M 32.556888,39.006317 C 32.692760,35.835967 33.100380,35.066018 35.908404,32.892064 C 39.395790,30.219911 39.803410,29.902873 40.120445,29.631129 C 41.705621,28.272407 42.611437,26.189029 42.611437,24.015074 C 42.611437,19.078386 38.625844,15.953318 32.285143,15.953318 C 26.306768,15.953318 22.094721,18.851931 22.094721,23.018677 C 22.094721,25.464376 23.906354,27.230718 26.397344,27.230718 C 28.707171,27.230718 30.292350,25.736121 30.292350,23.607457 C 30.292350,22.384608 29.794150,21.388209 28.843045,20.663558 C 28.027812,20.029488 27.982521,19.984196 27.982521,19.667161 C 27.982521,19.033091 28.978919,18.534892 30.382931,18.534892 C 33.100374,18.534892 34.640263,20.346525 34.640263,23.516876 C 34.640263,25.373795 33.960900,27.683628 32.828632,29.721710 C 30.337643,34.160201 29.975314,35.066023 29.975314,37.104105 C 29.975314,37.557012 30.020605,38.281665 30.111187,39.006317 L 32.556888,39.006317 M 31.424619,41.497309 C 29.069501,41.497309 27.167287,43.399523 27.167287,45.754641 C 27.167287,48.064467 29.069501,50.011973 31.379328,50.011973 C 33.779736,50.011973 35.681951,48.109758 35.681951,45.754641 C 35.681951,43.399523 33.779736,41.497309 31.424619,41.497309"
+         style="font-size:45.290764px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125.00000%;writing-mode:lr-tb;text-anchor:start;fill:url(#linearGradient1363);fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Century Schoolbook L" />
+    </g>
+  </g>
+</svg>
index f262217..9a30b7f 100644 (file)
@@ -3,5 +3,7 @@
   <file alias="wpa_gui.png">icons/hicolor/16x16/apps/wpa_gui.png</file>
   <file alias="ap.png">icons/hicolor/32x32/apps/ap.png</file>
   <file alias="laptop.png">icons/hicolor/32x32/apps/laptop.png</file>
+  <file alias="group.png">icons/hicolor/32x32/apps/group.png</file>
+  <file alias="invitation.png">icons/hicolor/32x32/apps/invitation.png</file>
  </qresource>
 </RCC>
diff --git a/wpa_supplicant/wpa_gui-qt4/lang/.gitignore b/wpa_supplicant/wpa_gui-qt4/lang/.gitignore
deleted file mode 100644 (file)
index 8df47d5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-*.qm
index 7a99299..65bb17d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * wpa_gui - Peers class
- * Copyright (c) 2009, Atheros Communications
+ * 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
@@ -27,11 +27,22 @@ enum {
        peer_role_type,
        peer_role_uuid,
        peer_role_details,
+       peer_role_ifname,
        peer_role_pri_dev_type,
        peer_role_ssid,
        peer_role_config_methods,
        peer_role_dev_passwd_id,
-       peer_role_bss_id
+       peer_role_bss_id,
+       peer_role_selected_method,
+       peer_role_selected_pin,
+       peer_role_requested_method,
+       peer_role_network_id
+};
+
+enum selected_method {
+       SEL_METHOD_NONE,
+       SEL_METHOD_PIN_PEER_DISPLAY,
+       SEL_METHOD_PIN_LOCAL_DISPLAY
 };
 
 /*
@@ -44,6 +55,12 @@ enum peer_type {
        PEER_TYPE_AP,
        PEER_TYPE_AP_WPS,
        PEER_TYPE_WPS_PIN_NEEDED,
+       PEER_TYPE_P2P,
+       PEER_TYPE_P2P_CLIENT,
+       PEER_TYPE_P2P_GROUP,
+       PEER_TYPE_P2P_PERSISTENT_GROUP_GO,
+       PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT,
+       PEER_TYPE_P2P_INVITATION,
        PEER_TYPE_WPS_ER_AP,
        PEER_TYPE_WPS_ER_AP_UNCONFIGURED,
        PEER_TYPE_WPS_ER_ENROLLEE,
@@ -61,20 +78,27 @@ Peers::Peers(QWidget *parent, const char *, bool, Qt::WFlags)
                default_icon = new QIcon(":/icons/wpa_gui.svg");
                ap_icon = new QIcon(":/icons/ap.svg");
                laptop_icon = new QIcon(":/icons/laptop.svg");
+               group_icon = new QIcon(":/icons/group.svg");
+               invitation_icon = new QIcon(":/icons/invitation.svg");
        } else {
                default_icon = new QIcon(":/icons/wpa_gui.png");
                ap_icon = new QIcon(":/icons/ap.png");
                laptop_icon = new QIcon(":/icons/laptop.png");
+               group_icon = new QIcon(":/icons/group.png");
+               invitation_icon = new QIcon(":/icons/invitation.png");
        }
 
        peers->setModel(&model);
        peers->setResizeMode(QListView::Adjust);
+       peers->setDragEnabled(false);
+       peers->setSelectionMode(QAbstractItemView::NoSelection);
 
        peers->setContextMenuPolicy(Qt::CustomContextMenu);
        connect(peers, SIGNAL(customContextMenuRequested(const QPoint &)),
                this, SLOT(context_menu(const QPoint &)));
 
        wpagui = NULL;
+       hide_ap = false;
 }
 
 
@@ -90,6 +114,8 @@ Peers::~Peers()
        delete default_icon;
        delete ap_icon;
        delete laptop_icon;
+       delete group_icon;
+       delete invitation_icon;
 }
 
 
@@ -115,6 +141,24 @@ QString Peers::ItemType(int type)
        case PEER_TYPE_WPS_PIN_NEEDED:
                title = tr("WPS PIN needed");
                break;
+       case PEER_TYPE_P2P:
+               title = tr("P2P Device");
+               break;
+       case PEER_TYPE_P2P_CLIENT:
+               title = tr("P2P Device (group client)");
+               break;
+       case PEER_TYPE_P2P_GROUP:
+               title = tr("P2P Group");
+               break;
+       case PEER_TYPE_P2P_PERSISTENT_GROUP_GO:
+               title = tr("P2P Persistent Group (GO)");
+               break;
+       case PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT:
+               title = tr("P2P Persistent Group (client)");
+               break;
+       case PEER_TYPE_P2P_INVITATION:
+               title = tr("P2P Invitation");
+               break;
        case PEER_TYPE_WPS_ER_AP:
                title = tr("ER: WPS AP");
                break;
@@ -150,6 +194,11 @@ void Peers::context_menu(const QPoint &pos)
                if (var.isValid())
                        config_methods = var.toInt();
 
+               enum selected_method method = SEL_METHOD_NONE;
+               var = ctx_item->data(peer_role_selected_method);
+               if (var.isValid())
+                       method = (enum selected_method) var.toInt();
+
                if ((type == PEER_TYPE_ASSOCIATED_STATION ||
                     type == PEER_TYPE_AP_WPS ||
                     type == PEER_TYPE_WPS_PIN_NEEDED ||
@@ -160,6 +209,60 @@ void Peers::context_menu(const QPoint &pos)
                                        SLOT(enter_pin()));
                }
 
+               if (type == PEER_TYPE_P2P || type == PEER_TYPE_P2P_CLIENT) {
+                       menu->addAction(tr("P2P Connect"), this,
+                                       SLOT(ctx_p2p_connect()));
+                       if (method == SEL_METHOD_NONE &&
+                           config_methods > -1 &&
+                           config_methods & 0x0080 /* PBC */ &&
+                           config_methods != 0x0080)
+                               menu->addAction(tr("P2P Connect (PBC)"), this,
+                                               SLOT(connect_pbc()));
+                       if (method == SEL_METHOD_NONE) {
+                               menu->addAction(tr("P2P Request PIN"), this,
+                                               SLOT(ctx_p2p_req_pin()));
+                               menu->addAction(tr("P2P Show PIN"), this,
+                                               SLOT(ctx_p2p_show_pin()));
+                       }
+
+                       if (config_methods > -1 && (config_methods & 0x0100)) {
+                               /* Peer has Keypad */
+                               menu->addAction(tr("P2P Display PIN"), this,
+                                               SLOT(ctx_p2p_display_pin()));
+                       }
+
+                       if (config_methods > -1 && (config_methods & 0x000c)) {
+                               /* Peer has Label or Display */
+                               menu->addAction(tr("P2P Enter PIN"), this,
+                                               SLOT(ctx_p2p_enter_pin()));
+                       }
+               }
+
+               if (type == PEER_TYPE_P2P_GROUP) {
+                       menu->addAction(tr("Show passphrase"), this,
+                                       SLOT(ctx_p2p_show_passphrase()));
+                       menu->addAction(tr("Remove P2P Group"), this,
+                                       SLOT(ctx_p2p_remove_group()));
+               }
+
+               if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO ||
+                   type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT ||
+                   type == PEER_TYPE_P2P_INVITATION) {
+                       menu->addAction(tr("Start group"), this,
+                                       SLOT(ctx_p2p_start_persistent()));
+               }
+
+               if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO ||
+                   type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT) {
+                       menu->addAction(tr("Invite"), this,
+                                       SLOT(ctx_p2p_invite()));
+               }
+
+               if (type == PEER_TYPE_P2P_INVITATION) {
+                       menu->addAction(tr("Ignore"), this,
+                                       SLOT(ctx_p2p_delete()));
+               }
+
                if (type == PEER_TYPE_AP_WPS) {
                        menu->addAction(tr("Connect (PBC)"), this,
                                        SLOT(connect_pbc()));
@@ -183,6 +286,20 @@ void Peers::context_menu(const QPoint &pos)
                ctx_item = NULL;
                menu->addAction(QString(tr("Refresh")), this,
                                SLOT(ctx_refresh()));
+               menu->addAction(tr("Start P2P discovery"), this,
+                               SLOT(ctx_p2p_start()));
+               menu->addAction(tr("Stop P2P discovery"), this,
+                               SLOT(ctx_p2p_stop()));
+               menu->addAction(tr("P2P listen only"), this,
+                               SLOT(ctx_p2p_listen()));
+               menu->addAction(tr("Start P2P group"), this,
+                               SLOT(ctx_p2p_start_group()));
+               if (hide_ap)
+                       menu->addAction(tr("Show AP entries"), this,
+                                       SLOT(ctx_show_ap()));
+               else
+                       menu->addAction(tr("Hide AP entries"), this,
+                                       SLOT(ctx_hide_ap()));
        }
 
        menu->exec(peers->mapToGlobal(pos));
@@ -197,10 +314,9 @@ void Peers::enter_pin()
        int peer_type = ctx_item->data(peer_role_type).toInt();
        QString uuid;
        QString addr;
+       addr = ctx_item->data(peer_role_address).toString();
        if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE)
                uuid = ctx_item->data(peer_role_uuid).toString();
-       else
-               addr = ctx_item->data(peer_role_address).toString();
 
        StringQuery input(tr("PIN:"));
        input.setWindowTitle(tr("PIN for ") + ctx_item->text());
@@ -212,9 +328,10 @@ void Peers::enter_pin()
        size_t reply_len;
 
        if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) {
-               snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s",
+               snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s %s",
                         uuid.toAscii().constData(),
-                        input.get_string().toAscii().constData());
+                        input.get_string().toAscii().constData(),
+                        addr.toAscii().constData());
        } else {
                snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s",
                         addr.toAscii().constData(),
@@ -236,6 +353,60 @@ void Peers::ctx_refresh()
 }
 
 
+void Peers::ctx_p2p_start()
+{
+       char reply[20];
+       size_t reply_len;
+       reply_len = sizeof(reply) - 1;
+       if (wpagui->ctrlRequest("P2P_FIND", reply, &reply_len) < 0 ||
+           memcmp(reply, "FAIL", 4) == 0) {
+               QMessageBox msg;
+               msg.setIcon(QMessageBox::Warning);
+               msg.setText("Failed to start P2P discovery.");
+               msg.exec();
+       }
+}
+
+
+void Peers::ctx_p2p_stop()
+{
+       char reply[20];
+       size_t reply_len;
+       reply_len = sizeof(reply) - 1;
+       wpagui->ctrlRequest("P2P_STOP_FIND", reply, &reply_len);
+}
+
+
+void Peers::ctx_p2p_listen()
+{
+       char reply[20];
+       size_t reply_len;
+       reply_len = sizeof(reply) - 1;
+       if (wpagui->ctrlRequest("P2P_LISTEN 3600", reply, &reply_len) < 0 ||
+           memcmp(reply, "FAIL", 4) == 0) {
+               QMessageBox msg;
+               msg.setIcon(QMessageBox::Warning);
+               msg.setText("Failed to start P2P listen.");
+               msg.exec();
+       }
+}
+
+
+void Peers::ctx_p2p_start_group()
+{
+       char reply[20];
+       size_t reply_len;
+       reply_len = sizeof(reply) - 1;
+       if (wpagui->ctrlRequest("P2P_GROUP_ADD", reply, &reply_len) < 0 ||
+           memcmp(reply, "FAIL", 4) == 0) {
+               QMessageBox msg;
+               msg.setIcon(QMessageBox::Warning);
+               msg.setText("Failed to start P2P group.");
+               msg.exec();
+       }
+}
+
+
 void Peers::add_station(QString info)
 {
        QStringList lines = info.split(QRegExp("\\n"));
@@ -249,6 +420,8 @@ void Peers::add_station(QString info)
 
                if ((*it).startsWith("wpsDeviceName="))
                        name = (*it).mid(pos);
+               else if ((*it).startsWith("p2p_device_name="))
+                       name = (*it).mid(pos);
        }
 
        if (name.isEmpty())
@@ -256,6 +429,24 @@ void Peers::add_station(QString info)
 
        QStandardItem *item = new QStandardItem(*laptop_icon, name);
        if (item) {
+               /* Remove WPS enrollee entry if one is still pending */
+               if (model.rowCount() > 0) {
+                       QModelIndexList lst = model.match(model.index(0, 0),
+                                                         peer_role_address,
+                                                         lines[0]);
+                       for (int i = 0; i < lst.size(); i++) {
+                               QStandardItem *item;
+                               item = model.itemFromIndex(lst[i]);
+                               if (item == NULL)
+                                       continue;
+                               int type = item->data(peer_role_type).toInt();
+                               if (type == PEER_TYPE_WPS_ENROLLEE) {
+                                       model.removeRow(lst[i].row());
+                                       break;
+                               }
+                       }
+               }
+
                item->setData(lines[0], peer_role_address);
                item->setData(PEER_TYPE_ASSOCIATED_STATION,
                              peer_role_type);
@@ -322,6 +513,55 @@ void Peers::add_single_station(const char *addr)
 }
 
 
+void Peers::add_p2p_group_client(QStandardItem * /*parent*/, QString params)
+{
+       /*
+        * dev=02:b5:64:63:30:63 iface=02:b5:64:63:30:63 dev_capab=0x0
+        * dev_type=1-0050f204-1 dev_name='Wireless Client'
+        * config_methods=0x8c
+        */
+
+       QStringList items =
+               params.split(QRegExp(" (?=[^']*('[^']*'[^']*)*$)"));
+       QString addr = "";
+       QString name = "";
+       int config_methods = 0;
+       QString dev_type;
+
+       for (int i = 0; i < items.size(); i++) {
+               QString str = items.at(i);
+               int pos = str.indexOf('=') + 1;
+               if (str.startsWith("dev_name='"))
+                       name = str.section('\'', 1, -2);
+               else if (str.startsWith("config_methods="))
+                       config_methods =
+                               str.section('=', 1).toInt(0, 0);
+               else if (str.startsWith("dev="))
+                       addr = str.mid(pos);
+               else if (str.startsWith("dev_type=") && dev_type.isEmpty())
+                       dev_type = str.mid(pos);
+       }
+
+       QStandardItem *item = find_addr(addr);
+       if (item)
+               return;
+
+       item = new QStandardItem(*default_icon, name);
+       if (item) {
+               /* TODO: indicate somehow the relationship to the group owner
+                * (parent) */
+               item->setData(addr, peer_role_address);
+               item->setData(config_methods, peer_role_config_methods);
+               item->setData(PEER_TYPE_P2P_CLIENT, peer_role_type);
+               if (!dev_type.isEmpty())
+                       item->setData(dev_type, peer_role_pri_dev_type);
+               item->setData(items.join(QString("\n")), peer_role_details);
+               item->setToolTip(ItemType(PEER_TYPE_P2P_CLIENT));
+               model.appendRow(item);
+       }
+}
+
+
 void Peers::remove_bss(int id)
 {
        if (model.rowCount() == 0)
@@ -340,6 +580,9 @@ bool Peers::add_bss(const char *cmd)
        char reply[2048];
        size_t reply_len;
 
+       if (hide_ap)
+               return false;
+
        reply_len = sizeof(reply) - 1;
        if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
                return false;
@@ -403,6 +646,14 @@ bool Peers::add_bss(const char *cmd)
                if (!ssid.isEmpty())
                        item->setData(ssid, peer_role_ssid);
                model.appendRow(item);
+
+               lines = bss.split(QRegExp("\\n"));
+               for (QStringList::Iterator it = lines.begin();
+                    it != lines.end(); it++) {
+                       if ((*it).startsWith("p2p_group_client:"))
+                               add_p2p_group_client(item,
+                                                    (*it).mid(18));
+               }
        }
 
        return true;
@@ -426,6 +677,95 @@ void Peers::add_scan_results()
 }
 
 
+void Peers::add_persistent(int id, const char *ssid, const char *bssid)
+{
+       char cmd[100];
+       char reply[100];
+       size_t reply_len;
+       int mode;
+
+       snprintf(cmd, sizeof(cmd), "GET_NETWORK %d mode", id);
+       if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
+               return;
+       reply[reply_len] = '\0';
+       mode = atoi(reply);
+
+       QString name = ssid;
+       name = '[' + name + ']';
+
+       QStandardItem *item = new QStandardItem(*group_icon, name);
+       if (!item)
+               return;
+
+       int type;
+       if (mode == 3)
+               type = PEER_TYPE_P2P_PERSISTENT_GROUP_GO;
+       else
+               type = PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT;
+       item->setData(type, peer_role_type);
+       item->setToolTip(ItemType(type));
+       item->setData(ssid, peer_role_ssid);
+       if (bssid && strcmp(bssid, "any") == 0)
+               bssid = NULL;
+       if (bssid)
+               item->setData(bssid, peer_role_address);
+       item->setData(id, peer_role_network_id);
+       item->setBackground(Qt::BDiagPattern);
+
+       model.appendRow(item);
+}
+
+
+void Peers::add_persistent_groups()
+{
+       char buf[2048], *start, *end, *id, *ssid, *bssid, *flags;
+       size_t len;
+
+       len = sizeof(buf) - 1;
+       if (wpagui->ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
+               return;
+
+       buf[len] = '\0';
+       start = strchr(buf, '\n');
+       if (start == NULL)
+               return;
+       start++;
+
+       while (*start) {
+               bool last = false;
+               end = strchr(start, '\n');
+               if (end == NULL) {
+                       last = true;
+                       end = start;
+                       while (end[0] && end[1])
+                               end++;
+               }
+               *end = '\0';
+
+               id = start;
+               ssid = strchr(id, '\t');
+               if (ssid == NULL)
+                       break;
+               *ssid++ = '\0';
+               bssid = strchr(ssid, '\t');
+               if (bssid == NULL)
+                       break;
+               *bssid++ = '\0';
+               flags = strchr(bssid, '\t');
+               if (flags == NULL)
+                       break;
+               *flags++ = '\0';
+
+               if (strstr(flags, "[DISABLED][P2P-PERSISTENT]"))
+                       add_persistent(atoi(id), ssid, bssid);
+
+               if (last)
+                       break;
+               start = end + 1;
+       }
+}
+
+
 void Peers::update_peers()
 {
        model.clear();
@@ -438,6 +778,7 @@ void Peers::update_peers()
 
        add_stations();
        add_scan_results();
+       add_persistent_groups();
 }
 
 
@@ -454,6 +795,22 @@ QStandardItem * Peers::find_addr(QString addr)
 }
 
 
+QStandardItem * Peers::find_addr_type(QString addr, int type)
+{
+       if (model.rowCount() == 0)
+               return NULL;
+
+       QModelIndexList lst = model.match(model.index(0, 0), peer_role_address,
+                                         addr);
+       for (int i = 0; i < lst.size(); i++) {
+               QStandardItem *item = model.itemFromIndex(lst[i]);
+               if (item->data(peer_role_type).toInt() == type)
+                       return item;
+       }
+       return NULL;
+}
+
+
 QStandardItem * Peers::find_uuid(QString uuid)
 {
        if (model.rowCount() == 0)
@@ -530,16 +887,225 @@ void Peers::event_notify(WpaMsg msg)
                        return;
 
                QModelIndexList lst = model.match(model.index(0, 0),
-                                                 peer_role_address, addr);
+                                                 peer_role_address, addr, -1);
                for (int i = 0; i < lst.size(); i++) {
                        QStandardItem *item = model.itemFromIndex(lst[i]);
                        if (item && item->data(peer_role_type).toInt() ==
-                           PEER_TYPE_ASSOCIATED_STATION)
+                           PEER_TYPE_ASSOCIATED_STATION) {
                                model.removeRow(lst[i].row());
+                               break;
+                       }
+               }
+               return;
+       }
+
+       if (text.startsWith(P2P_EVENT_DEVICE_FOUND)) {
+               /*
+                * P2P-DEVICE-FOUND 02:b5:64:63:30:63
+                * p2p_dev_addr=02:b5:64:63:30:63 pri_dev_type=1-0050f204-1
+                * name='Wireless Client' config_methods=0x84 dev_capab=0x21
+                * group_capab=0x0
+                */
+               QStringList items =
+                       text.split(QRegExp(" (?=[^']*('[^']*'[^']*)*$)"));
+               QString addr = items[1];
+               QString name = "";
+               QString pri_dev_type;
+               int config_methods = 0;
+               for (int i = 0; i < items.size(); i++) {
+                       QString str = items.at(i);
+                       if (str.startsWith("name='"))
+                               name = str.section('\'', 1, -2);
+                       else if (str.startsWith("config_methods="))
+                               config_methods =
+                                       str.section('=', 1).toInt(0, 0);
+                       else if (str.startsWith("pri_dev_type="))
+                               pri_dev_type = str.section('=', 1);
+               }
+
+               QStandardItem *item = find_addr(addr);
+               if (item) {
+                       int type = item->data(peer_role_type).toInt();
+                       if (type == PEER_TYPE_P2P)
+                               return;
+               }
+
+               item = new QStandardItem(*default_icon, name);
+               if (item) {
+                       item->setData(addr, peer_role_address);
+                       item->setData(config_methods,
+                                     peer_role_config_methods);
+                       item->setData(PEER_TYPE_P2P, peer_role_type);
+                       if (!pri_dev_type.isEmpty())
+                               item->setData(pri_dev_type,
+                                             peer_role_pri_dev_type);
+                       item->setData(items.join(QString("\n")),
+                                     peer_role_details);
+                       item->setToolTip(ItemType(PEER_TYPE_P2P));
+                       model.appendRow(item);
+               }
+
+               item = find_addr_type(addr,
+                                     PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT);
+               if (item)
+                       item->setBackground(Qt::NoBrush);
+       }
+
+       if (text.startsWith(P2P_EVENT_GROUP_STARTED)) {
+               /* P2P-GROUP-STARTED wlan0-p2p-0 GO ssid="DIRECT-3F"
+                * passphrase="YOyTkxID" go_dev_addr=02:40:61:c2:f3:b7
+                * [PERSISTENT] */
+               QStringList items = text.split(' ');
+               if (items.size() < 4)
+                       return;
+
+               int pos = text.indexOf(" ssid=\"");
+               if (pos < 0)
+                       return;
+               QString ssid = text.mid(pos + 7);
+               pos = ssid.indexOf(" passphrase=\"");
+               if (pos < 0)
+                       pos = ssid.indexOf(" psk=");
+               if (pos >= 0)
+                       ssid.truncate(pos);
+               pos = ssid.lastIndexOf('"');
+               if (pos >= 0)
+                       ssid.truncate(pos);
+
+               QStandardItem *item = new QStandardItem(*group_icon, ssid);
+               if (item) {
+                       item->setData(PEER_TYPE_P2P_GROUP, peer_role_type);
+                       item->setData(items[1], peer_role_ifname);
+                       QString details;
+                       if (items[2] == "GO") {
+                               details = tr("P2P GO for interface ") +
+                                       items[1];
+                       } else {
+                               details = tr("P2P client for interface ") +
+                                       items[1];
+                       }
+                       if (text.contains(" [PERSISTENT]"))
+                               details += "\nPersistent group";
+                       item->setData(details, peer_role_details);
+                       item->setToolTip(ItemType(PEER_TYPE_P2P_GROUP));
+                       model.appendRow(item);
+               }
+       }
+
+       if (text.startsWith(P2P_EVENT_GROUP_REMOVED)) {
+               /* P2P-GROUP-REMOVED wlan0-p2p-0 GO */
+               QStringList items = text.split(' ');
+               if (items.size() < 2)
+                       return;
+
+               if (model.rowCount() == 0)
+                       return;
+
+               QModelIndexList lst = model.match(model.index(0, 0),
+                                                 peer_role_ifname, items[1]);
+               for (int i = 0; i < lst.size(); i++)
+                       model.removeRow(lst[i].row());
+               return;
+       }
+
+       if (text.startsWith(P2P_EVENT_PROV_DISC_SHOW_PIN)) {
+               /* P2P-PROV-DISC-SHOW-PIN 02:40:61:c2:f3:b7 12345670 */
+               QStringList items = text.split(' ');
+               if (items.size() < 3)
+                       return;
+               QString addr = items[1];
+               QString pin = items[2];
+
+               QStandardItem *item = find_addr_type(addr, PEER_TYPE_P2P);
+               if (item == NULL)
+                       return;
+               item->setData(SEL_METHOD_PIN_LOCAL_DISPLAY,
+                             peer_role_selected_method);
+               item->setData(pin, peer_role_selected_pin);
+               QVariant var = item->data(peer_role_requested_method);
+               if (var.isValid() &&
+                   var.toInt() == SEL_METHOD_PIN_LOCAL_DISPLAY) {
+                       ctx_item = item;
+                       ctx_p2p_display_pin_pd();
+               }
+               return;
+       }
+
+       if (text.startsWith(P2P_EVENT_PROV_DISC_ENTER_PIN)) {
+               /* P2P-PROV-DISC-ENTER-PIN 02:40:61:c2:f3:b7 */
+               QStringList items = text.split(' ');
+               if (items.size() < 2)
+                       return;
+               QString addr = items[1];
+
+               QStandardItem *item = find_addr_type(addr, PEER_TYPE_P2P);
+               if (item == NULL)
+                       return;
+               item->setData(SEL_METHOD_PIN_PEER_DISPLAY,
+                             peer_role_selected_method);
+               QVariant var = item->data(peer_role_requested_method);
+               if (var.isValid() &&
+                   var.toInt() == SEL_METHOD_PIN_PEER_DISPLAY) {
+                       ctx_item = item;
+                       ctx_p2p_connect();
                }
                return;
        }
 
+       if (text.startsWith(P2P_EVENT_INVITATION_RECEIVED)) {
+               /* P2P-INVITATION-RECEIVED sa=02:f0:bc:44:87:62 persistent=4 */
+               QStringList items = text.split(' ');
+               if (items.size() < 3)
+                       return;
+               if (!items[1].startsWith("sa=") ||
+                   !items[2].startsWith("persistent="))
+                       return;
+               QString addr = items[1].mid(3);
+               int id = items[2].mid(11).toInt();
+
+               char cmd[100];
+               char reply[100];
+               size_t reply_len;
+
+               snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", id);
+               reply_len = sizeof(reply) - 1;
+               if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
+                       return;
+               reply[reply_len] = '\0';
+               QString name;
+               char *pos = strrchr(reply, '"');
+               if (pos && reply[0] == '"') {
+                       *pos = '\0';
+                       name = reply + 1;
+               } else
+                       name = reply;
+
+               QStandardItem *item;
+               item = find_addr_type(addr, PEER_TYPE_P2P_INVITATION);
+               if (item)
+                       model.removeRow(item->row());
+
+               item = new QStandardItem(*invitation_icon, name);
+               if (!item)
+                       return;
+               item->setData(PEER_TYPE_P2P_INVITATION, peer_role_type);
+               item->setToolTip(ItemType(PEER_TYPE_P2P_INVITATION));
+               item->setData(addr, peer_role_address);
+               item->setData(id, peer_role_network_id);
+
+               model.appendRow(item);
+
+               enable_persistent(id);
+
+               return;
+       }
+
+       if (text.startsWith(P2P_EVENT_INVITATION_RESULT)) {
+               /* P2P-INVITATION-RESULT status=1 */
+               /* TODO */
+               return;
+       }
+
        if (text.startsWith(WPS_EVENT_ER_AP_ADD)) {
                /*
                 * WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002
@@ -700,6 +1266,13 @@ void Peers::event_notify(WpaMsg msg)
                int dev_passwd_id = items[5].toInt();
                QString name;
 
+               QStandardItem *item = find_addr(addr);
+               if (item) {
+                       int type = item->data(peer_role_type).toInt();
+                       if (type == PEER_TYPE_ASSOCIATED_STATION)
+                               return; /* already associated */
+               }
+
                int pos = text.indexOf('[');
                if (pos >= 0) {
                        int pos2 = text.lastIndexOf(']');
@@ -713,8 +1286,6 @@ void Peers::event_notify(WpaMsg msg)
                if (name.isEmpty())
                        name = addr;
 
-               QStandardItem *item;
-
                item = find_uuid(uuid);
                if (item) {
                        QVariant var = item->data(peer_role_config_methods);
@@ -767,6 +1338,221 @@ void Peers::event_notify(WpaMsg msg)
 }
 
 
+void Peers::ctx_p2p_connect()
+{
+       if (ctx_item == NULL)
+               return;
+       QString addr = ctx_item->data(peer_role_address).toString();
+       QString arg;
+       int config_methods =
+               ctx_item->data(peer_role_config_methods).toInt();
+       enum selected_method method = SEL_METHOD_NONE;
+       QVariant var = ctx_item->data(peer_role_selected_method);
+       if (var.isValid())
+               method = (enum selected_method) var.toInt();
+       if (method == SEL_METHOD_PIN_LOCAL_DISPLAY) {
+               arg = ctx_item->data(peer_role_selected_pin).toString();
+               char cmd[100];
+               char reply[100];
+               size_t reply_len;
+               snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s display",
+                        addr.toAscii().constData(),
+                        arg.toAscii().constData());
+               reply_len = sizeof(reply) - 1;
+               if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
+                       QMessageBox msg;
+                       msg.setIcon(QMessageBox::Warning);
+                       msg.setText("Failed to initiate P2P connect.");
+                       msg.exec();
+                       return;
+               }
+               QMessageBox::information(this,
+                                        tr("PIN for ") + ctx_item->text(),
+                                        tr("Enter the following PIN on the\n"
+                                           "peer device: ") + arg);
+       } else if (method == SEL_METHOD_PIN_PEER_DISPLAY) {
+               StringQuery input(tr("PIN from peer display:"));
+               input.setWindowTitle(tr("PIN for ") + ctx_item->text());
+               if (input.exec() != QDialog::Accepted)
+                       return;
+               arg = input.get_string();
+       } else if (config_methods == 0x0080 /* PBC */) {
+               arg = "pbc";
+       } else {
+               StringQuery input(tr("PIN:"));
+               input.setWindowTitle(tr("PIN for ") + ctx_item->text());
+               if (input.exec() != QDialog::Accepted)
+                       return;
+               arg = input.get_string();
+       }
+
+       char cmd[100];
+       char reply[100];
+       size_t reply_len;
+       snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s",
+                addr.toAscii().constData(),
+                arg.toAscii().constData());
+       reply_len = sizeof(reply) - 1;
+       if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
+               QMessageBox msg;
+               msg.setIcon(QMessageBox::Warning);
+               msg.setText("Failed to initiate P2P connect.");
+               msg.exec();
+       }
+}
+
+
+void Peers::ctx_p2p_req_pin()
+{
+       if (ctx_item == NULL)
+               return;
+       QString addr = ctx_item->data(peer_role_address).toString();
+       ctx_item->setData(SEL_METHOD_PIN_PEER_DISPLAY,
+                         peer_role_requested_method);
+
+       char cmd[100];
+       char reply[100];
+       size_t reply_len;
+       snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s display",
+                addr.toAscii().constData());
+       reply_len = sizeof(reply) - 1;
+       if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
+               QMessageBox msg;
+               msg.setIcon(QMessageBox::Warning);
+               msg.setText(tr("Failed to request PIN from peer."));
+               msg.exec();
+       }
+}
+
+
+void Peers::ctx_p2p_show_pin()
+{
+       if (ctx_item == NULL)
+               return;
+       QString addr = ctx_item->data(peer_role_address).toString();
+       ctx_item->setData(SEL_METHOD_PIN_LOCAL_DISPLAY,
+                         peer_role_requested_method);
+
+       char cmd[100];
+       char reply[100];
+       size_t reply_len;
+       snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s keypad",
+                addr.toAscii().constData());
+       reply_len = sizeof(reply) - 1;
+       if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
+               QMessageBox msg;
+               msg.setIcon(QMessageBox::Warning);
+               msg.setText(tr("Failed to request peer to enter PIN."));
+               msg.exec();
+       }
+}
+
+
+void Peers::ctx_p2p_display_pin()
+{
+       if (ctx_item == NULL)
+               return;
+       QString addr = ctx_item->data(peer_role_address).toString();
+
+       char cmd[100];
+       char reply[100];
+       size_t reply_len;
+       snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s pin",
+                addr.toAscii().constData());
+       reply_len = sizeof(reply) - 1;
+       if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
+               QMessageBox msg;
+               msg.setIcon(QMessageBox::Warning);
+               msg.setText("Failed to initiate P2P connect.");
+               msg.exec();
+               return;
+       }
+       reply[reply_len] = '\0';
+       QMessageBox::information(this,
+                                tr("PIN for ") + ctx_item->text(),
+                                tr("Enter the following PIN on the\n"
+                                   "peer device: ") + reply);
+}
+
+
+void Peers::ctx_p2p_display_pin_pd()
+{
+       if (ctx_item == NULL)
+               return;
+       QString addr = ctx_item->data(peer_role_address).toString();
+       QString arg = ctx_item->data(peer_role_selected_pin).toString();
+
+       char cmd[100];
+       char reply[100];
+       size_t reply_len;
+       snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s display",
+                addr.toAscii().constData(),
+                arg.toAscii().constData());
+       reply_len = sizeof(reply) - 1;
+       if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
+               QMessageBox msg;
+               msg.setIcon(QMessageBox::Warning);
+               msg.setText("Failed to initiate P2P connect.");
+               msg.exec();
+               return;
+       }
+       reply[reply_len] = '\0';
+       QMessageBox::information(this,
+                                tr("PIN for ") + ctx_item->text(),
+                                tr("Enter the following PIN on the\n"
+                                   "peer device: ") + arg);
+}
+
+
+void Peers::ctx_p2p_enter_pin()
+{
+       if (ctx_item == NULL)
+               return;
+       QString addr = ctx_item->data(peer_role_address).toString();
+       QString arg;
+
+       StringQuery input(tr("PIN from peer:"));
+       input.setWindowTitle(tr("PIN for ") + ctx_item->text());
+       if (input.exec() != QDialog::Accepted)
+               return;
+       arg = input.get_string();
+
+       char cmd[100];
+       char reply[100];
+       size_t reply_len;
+       snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s keypad",
+                addr.toAscii().constData(),
+                arg.toAscii().constData());
+       reply_len = sizeof(reply) - 1;
+       if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
+               QMessageBox msg;
+               msg.setIcon(QMessageBox::Warning);
+               msg.setText("Failed to initiate P2P connect.");
+               msg.exec();
+       }
+}
+
+
+void Peers::ctx_p2p_remove_group()
+{
+       if (ctx_item == NULL)
+               return;
+       char cmd[100];
+       char reply[100];
+       size_t reply_len;
+       snprintf(cmd, sizeof(cmd), "P2P_GROUP_REMOVE %s",
+                ctx_item->data(peer_role_ifname).toString().toAscii().
+                constData());
+       reply_len = sizeof(reply) - 1;
+       if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
+               QMessageBox msg;
+               msg.setIcon(QMessageBox::Warning);
+               msg.setText("Failed to remove P2P Group.");
+               msg.exec();
+       }
+}
+
+
 void Peers::closeEvent(QCloseEvent *)
 {
        if (wpagui) {
@@ -864,6 +1650,27 @@ void Peers::properties()
                info += "\n";
        }
 
+       var = ctx_item->data(peer_role_selected_method);
+       if (var.isValid()) {
+               enum selected_method method =
+                       (enum selected_method) var.toInt();
+               switch (method) {
+               case SEL_METHOD_NONE:
+                       break;
+               case SEL_METHOD_PIN_PEER_DISPLAY:
+                       info += tr("Selected Method: PIN on peer display\n");
+                       break;
+               case SEL_METHOD_PIN_LOCAL_DISPLAY:
+                       info += tr("Selected Method: PIN on local display\n");
+                       break;
+               }
+       }
+
+       var = ctx_item->data(peer_role_selected_pin);
+       if (var.isValid()) {
+               info += tr("PIN to enter on peer: ") + var.toString() + "\n";
+       }
+
        var = ctx_item->data(peer_role_dev_passwd_id);
        if (var.isValid()) {
                info += tr("Device Password ID: ") + var.toString();
@@ -914,6 +1721,11 @@ void Peers::connect_pbc()
                snprintf(cmd, sizeof(cmd), "WPS_ER_PBC %s",
                         ctx_item->data(peer_role_uuid).toString().toAscii().
                         constData());
+       } else if (peer_type == PEER_TYPE_P2P ||
+                  peer_type == PEER_TYPE_P2P_CLIENT) {
+               snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s pbc",
+                        ctx_item->data(peer_role_address).toString().
+                        toAscii().constData());
        } else {
                snprintf(cmd, sizeof(cmd), "WPS_PBC");
        }
@@ -954,3 +1766,124 @@ void Peers::learn_ap_config()
                msg.exec();
        }
 }
+
+
+void Peers::ctx_hide_ap()
+{
+       hide_ap = true;
+
+       if (model.rowCount() == 0)
+               return;
+
+       do {
+               QModelIndexList lst;
+               lst = model.match(model.index(0, 0),
+                                 peer_role_type, PEER_TYPE_AP);
+               if (lst.size() == 0) {
+                       lst = model.match(model.index(0, 0),
+                                         peer_role_type, PEER_TYPE_AP_WPS);
+                       if (lst.size() == 0)
+                               break;
+               }
+
+               model.removeRow(lst[0].row());
+       } while (1);
+}
+
+
+void Peers::ctx_show_ap()
+{
+       hide_ap = false;
+       add_scan_results();
+}
+
+
+void Peers::ctx_p2p_show_passphrase()
+{
+       char reply[64];
+       size_t reply_len;
+
+       reply_len = sizeof(reply) - 1;
+       if (wpagui->ctrlRequest("P2P_GET_PASSPHRASE", reply, &reply_len) < 0 ||
+           memcmp(reply, "FAIL", 4) == 0) {
+               QMessageBox msg;
+               msg.setIcon(QMessageBox::Warning);
+               msg.setText("Failed to get P2P group passphrase.");
+               msg.exec();
+       } else {
+               reply[reply_len] = '\0';
+               QMessageBox::information(this, tr("Passphrase"),
+                                        tr("P2P group passphrase:\n") +
+                                        reply);
+       }
+}
+
+
+void Peers::ctx_p2p_start_persistent()
+{
+       if (ctx_item == NULL)
+               return;
+
+       char cmd[100];
+       char reply[100];
+       size_t reply_len;
+
+       snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD persistent=%d",
+                ctx_item->data(peer_role_network_id).toInt());
+       if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0 ||
+           memcmp(reply, "FAIL", 4) == 0) {
+               QMessageBox msg;
+               msg.setIcon(QMessageBox::Warning);
+               msg.setText(tr("Failed to start persistent P2P Group."));
+               msg.exec();
+       } else if (ctx_item->data(peer_role_type).toInt() ==
+                  PEER_TYPE_P2P_INVITATION)
+               model.removeRow(ctx_item->row());
+}
+
+
+void Peers::ctx_p2p_invite()
+{
+       if (ctx_item == NULL)
+               return;
+
+       char cmd[100];
+       char reply[100];
+       size_t reply_len;
+
+       snprintf(cmd, sizeof(cmd), "P2P_INVITE persistent=%d",
+                ctx_item->data(peer_role_network_id).toInt());
+       if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0 ||
+           memcmp(reply, "FAIL", 4) == 0) {
+               QMessageBox msg;
+               msg.setIcon(QMessageBox::Warning);
+               msg.setText(tr("Failed to invite peer to start persistent "
+                              "P2P Group."));
+               msg.exec();
+       }
+}
+
+
+void Peers::ctx_p2p_delete()
+{
+       if (ctx_item == NULL)
+               return;
+       model.removeRow(ctx_item->row());
+}
+
+
+void Peers::enable_persistent(int id)
+{
+       if (model.rowCount() == 0)
+               return;
+
+       QModelIndexList lst = model.match(model.index(0, 0),
+                                         peer_role_network_id, id);
+       for (int i = 0; i < lst.size(); i++) {
+               QStandardItem *item = model.itemFromIndex(lst[i]);
+               int type = item->data(peer_role_type).toInt();
+               if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO ||
+                   type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT)
+                       item->setBackground(Qt::NoBrush);
+       }
+}
index 89b7b5b..a715395 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * wpa_gui - Peers class
- * Copyright (c) 2009, Atheros Communications
+ * 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
@@ -39,7 +39,24 @@ public slots:
        virtual void connect_pbc();
        virtual void learn_ap_config();
        virtual void ctx_refresh();
+       virtual void ctx_p2p_start();
+       virtual void ctx_p2p_stop();
+       virtual void ctx_p2p_listen();
+       virtual void ctx_p2p_start_group();
+       virtual void ctx_p2p_remove_group();
+       virtual void ctx_p2p_connect();
+       virtual void ctx_p2p_req_pin();
+       virtual void ctx_p2p_show_pin();
+       virtual void ctx_p2p_display_pin();
+       virtual void ctx_p2p_display_pin_pd();
+       virtual void ctx_p2p_enter_pin();
        virtual void properties();
+       virtual void ctx_hide_ap();
+       virtual void ctx_show_ap();
+       virtual void ctx_p2p_show_passphrase();
+       virtual void ctx_p2p_start_persistent();
+       virtual void ctx_p2p_invite();
+       virtual void ctx_p2p_delete();
 
 protected slots:
        virtual void languageChange();
@@ -52,19 +69,28 @@ private:
        bool add_bss(const char *cmd);
        void remove_bss(int id);
        void add_scan_results();
+       void add_persistent(int id, const char *ssid, const char *bssid);
+       void add_persistent_groups();
        void update_peers();
        QStandardItem * find_addr(QString addr);
+       QStandardItem * find_addr_type(QString addr, int type);
+       void add_p2p_group_client(QStandardItem *parent, QString params);
        QStandardItem * find_uuid(QString uuid);
        void done(int r);
        void remove_enrollee_uuid(QString uuid);
        QString ItemType(int type);
+       void enable_persistent(int id);
 
        WpaGui *wpagui;
        QStandardItemModel model;
        QIcon *default_icon;
        QIcon *ap_icon;
        QIcon *laptop_icon;
+       QIcon *group_icon;
+       QIcon *invitation_icon;
        QStandardItem *ctx_item;
+
+       bool hide_ap;
 };
 
 #endif /* PEERS_H */
index 459aa8c..f75f02a 100644 (file)
@@ -15,6 +15,7 @@
 #include <cstdio>
 
 #include "scanresults.h"
+#include "signalbar.h"
 #include "wpagui.h"
 #include "networkconfig.h"
 
@@ -33,6 +34,7 @@ ScanResults::ScanResults(QWidget *parent, const char *, bool, Qt::WFlags)
        wpagui = NULL;
        scanResultsWidget->setItemsExpandable(FALSE);
        scanResultsWidget->setRootIsDecorated(FALSE);
+       scanResultsWidget->setItemDelegate(new SignalBar(scanResultsWidget));
 }
 
 
@@ -91,7 +93,7 @@ void ScanResults::updateResults()
                                bssid = (*it).mid(pos);
                        else if ((*it).startsWith("freq="))
                                freq = (*it).mid(pos);
-                       else if ((*it).startsWith("qual="))
+                       else if ((*it).startsWith("level="))
                                signal = (*it).mid(pos);
                        else if ((*it).startsWith("flags="))
                                flags = (*it).mid(pos);
diff --git a/wpa_supplicant/wpa_gui-qt4/signalbar.cpp b/wpa_supplicant/wpa_gui-qt4/signalbar.cpp
new file mode 100644 (file)
index 0000000..f2688d5
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#include <cstdio>
+#include <qapplication.h>
+
+#include "signalbar.h"
+
+
+SignalBar::SignalBar(QObject *parent)
+       : QStyledItemDelegate(parent)
+{
+}
+
+
+SignalBar::~SignalBar()
+{
+}
+
+
+void SignalBar::paint(QPainter *painter,
+                     const QStyleOptionViewItem &option,
+                     const QModelIndex &index) const
+{
+       QStyleOptionProgressBar opts;
+       int signal;
+
+       if (index.column() != 3) {
+               QStyledItemDelegate::paint(painter, option, index);
+               return;
+       }
+
+       if (index.data().toInt() > 0)
+               signal = 0 - (256 - index.data().toInt());
+       else
+               signal = index.data().toInt();
+
+       opts.minimum = -95;
+       opts.maximum = -35;
+       if (signal < opts.minimum)
+               opts.progress = opts.minimum;
+       else if (signal > opts.maximum)
+               opts.progress = opts.maximum;
+       else
+               opts.progress = signal;
+
+       opts.text = QString::number(signal) + " dBm";
+       opts.textVisible = true;
+       opts.rect = option.rect;
+
+       QApplication::style()->drawControl(QStyle::CE_ProgressBar,
+                                          &opts, painter);
+}
diff --git a/wpa_supplicant/wpa_gui-qt4/signalbar.h b/wpa_supplicant/wpa_gui-qt4/signalbar.h
new file mode 100644 (file)
index 0000000..3d5dec1
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef SIGNALBAR_H
+#define SIGNALBAR_H
+
+#include <QObject>
+#include <QStyledItemDelegate>
+
+class SignalBar : public QStyledItemDelegate
+{
+       Q_OBJECT
+
+public:
+       SignalBar(QObject *parent = 0);
+       ~SignalBar();
+
+       virtual void paint(QPainter *painter,
+                          const QStyleOptionViewItem &option,
+                          const QModelIndex &index) const ;
+};
+
+#endif /* SIGNALBAR_H */
index 85848d7..3c81929 100644 (file)
@@ -34,6 +34,7 @@ HEADERS       += wpamsg.h \
        wpagui.h \
        eventhistory.h \
        scanresults.h \
+       signalbar.h \
        userdatarequest.h \
        networkconfig.h \
        addinterface.h \
@@ -44,6 +45,7 @@ SOURCES       += main.cpp \
        wpagui.cpp \
        eventhistory.cpp \
        scanresults.cpp \
+       signalbar.cpp \
        userdatarequest.cpp \
        networkconfig.cpp \
        addinterface.cpp \
index 2057d67..97bf5ac 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * wpa_gui - WpaGui class
- * Copyright (c) 2005-2010, Jouni Malinen <j@w1.fi>
+ * 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
@@ -659,6 +659,13 @@ void WpaGui::updateNetworks()
                        break;
                *flags++ = '\0';
 
+               if (strstr(flags, "[DISABLED][P2P-PERSISTENT]")) {
+                       if (last)
+                               break;
+                       start = end + 1;
+                       continue;
+               }
+
                QString network(id);
                network.append(": ");
                network.append(ssid);
@@ -712,7 +719,7 @@ void WpaGui::helpContents()
 void WpaGui::helpAbout()
 {
        QMessageBox::about(this, "wpa_gui for wpa_supplicant",
-                          "Copyright (c) 2003-2010,\n"
+                          "Copyright (c) 2003-2011,\n"
                           "Jouni Malinen <j@w1.fi>\n"
                           "and contributors.\n"
                           "\n"
@@ -899,6 +906,15 @@ void WpaGui::processMsg(char *msg)
                if (textStatus->text() == "INACTIVE" ||
                    textStatus->text() == "DISCONNECTED")
                        wpaguiTab->setCurrentWidget(wpsTab);
+       } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_AUTH)) {
+               showTrayMessage(QSystemTrayIcon::Information, 3,
+                               "Wi-Fi Protected Setup (WPS) AP\n"
+                               "indicating this client is authorized.");
+               wpsStatusText->setText("WPS AP indicating this client is "
+                                      "authorized");
+               if (textStatus->text() == "INACTIVE" ||
+                   textStatus->text() == "DISCONNECTED")
+                       wpaguiTab->setCurrentWidget(wpsTab);
        } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE)) {
                wpsStatusText->setText(tr("WPS AP detected"));
        } else if (str_match(pos, WPS_EVENT_OVERLAP)) {
diff --git a/wpa_supplicant/wpa_gui/.gitignore b/wpa_supplicant/wpa_gui/.gitignore
deleted file mode 100644 (file)
index 11963c8..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-.moc
-.obj
-.ui
-Makefile
-wpa_gui
diff --git a/wpa_supplicant/wpa_gui/eventhistory.ui b/wpa_supplicant/wpa_gui/eventhistory.ui
deleted file mode 100644 (file)
index 3735fb7..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>EventHistory</class>
-<widget class="QDialog">
-    <property name="name">
-        <cstring>EventHistory</cstring>
-    </property>
-    <property name="geometry">
-        <rect>
-            <x>0</x>
-            <y>0</y>
-            <width>533</width>
-            <height>285</height>
-        </rect>
-    </property>
-    <property name="caption">
-        <string>Event history</string>
-    </property>
-    <vbox>
-        <property name="name">
-            <cstring>unnamed</cstring>
-        </property>
-        <widget class="QListView">
-            <column>
-                <property name="text">
-                    <string>Timestamp</string>
-                </property>
-                <property name="clickable">
-                    <bool>true</bool>
-                </property>
-                <property name="resizable">
-                    <bool>true</bool>
-                </property>
-            </column>
-            <column>
-                <property name="text">
-                    <string>Message</string>
-                </property>
-                <property name="clickable">
-                    <bool>true</bool>
-                </property>
-                <property name="resizable">
-                    <bool>true</bool>
-                </property>
-            </column>
-            <property name="name">
-                <cstring>eventListView</cstring>
-            </property>
-            <property name="sizePolicy">
-                <sizepolicy>
-                    <hsizetype>7</hsizetype>
-                    <vsizetype>7</vsizetype>
-                    <horstretch>0</horstretch>
-                    <verstretch>0</verstretch>
-                </sizepolicy>
-            </property>
-            <property name="resizePolicy">
-                <enum>Manual</enum>
-            </property>
-            <property name="selectionMode">
-                <enum>NoSelection</enum>
-            </property>
-            <property name="resizeMode">
-                <enum>LastColumn</enum>
-            </property>
-        </widget>
-        <widget class="QLayoutWidget">
-            <property name="name">
-                <cstring>layout30</cstring>
-            </property>
-            <hbox>
-                <property name="name">
-                    <cstring>unnamed</cstring>
-                </property>
-                <spacer>
-                    <property name="name">
-                        <cstring>spacer3</cstring>
-                    </property>
-                    <property name="orientation">
-                        <enum>Horizontal</enum>
-                    </property>
-                    <property name="sizeType">
-                        <enum>Expanding</enum>
-                    </property>
-                    <property name="sizeHint">
-                        <size>
-                            <width>20</width>
-                            <height>20</height>
-                        </size>
-                    </property>
-                </spacer>
-                <widget class="QPushButton">
-                    <property name="name">
-                        <cstring>closeButton</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Close</string>
-                    </property>
-                </widget>
-            </hbox>
-        </widget>
-    </vbox>
-</widget>
-<connections>
-    <connection>
-        <sender>closeButton</sender>
-        <signal>clicked()</signal>
-        <receiver>EventHistory</receiver>
-        <slot>close()</slot>
-    </connection>
-</connections>
-<includes>
-    <include location="local" impldecl="in declaration">wpamsg.h</include>
-    <include location="local" impldecl="in implementation">eventhistory.ui.h</include>
-</includes>
-<slots>
-    <slot>addEvents( WpaMsgList msgs )</slot>
-    <slot>addEvent( WpaMsg msg )</slot>
-</slots>
-<functions>
-    <function access="private" specifier="non virtual">init()</function>
-    <function access="private" specifier="non virtual">destroy()</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
diff --git a/wpa_supplicant/wpa_gui/eventhistory.ui.h b/wpa_supplicant/wpa_gui/eventhistory.ui.h
deleted file mode 100644 (file)
index cb2caab..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/****************************************************************************
-** ui.h extension file, included from the uic-generated form implementation.
-**
-** If you want to add, delete, or rename functions or slots, use
-** Qt Designer to update this file, preserving your code.
-**
-** You should not define a constructor or destructor in this file.
-** Instead, write your code in functions called init() and destroy().
-** These will automatically be called by the form's constructor and
-** destructor.
-*****************************************************************************/
-
-void EventHistory::init()
-{
-}
-
-
-void EventHistory::destroy()
-{
-}
-
-
-void EventHistory::addEvents(WpaMsgList msgs)
-{
-    WpaMsgList::iterator it;
-    for (it = msgs.begin(); it != msgs.end(); it++) {
-       addEvent(*it);
-    }
-}
-
-
-void EventHistory::addEvent(WpaMsg msg)
-{
-    Q3ListViewItem *item;
-    item = new Q3ListViewItem(eventListView,
-                            msg.getTimestamp().toString("yyyy-MM-dd hh:mm:ss.zzz"),
-                            msg.getMsg());
-    if (item == NULL)
-       return;
-    eventListView->setSelected(item, false);
-}
diff --git a/wpa_supplicant/wpa_gui/main.cpp b/wpa_supplicant/wpa_gui/main.cpp
deleted file mode 100644 (file)
index a78473a..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifdef CONFIG_NATIVE_WINDOWS
-#include <winsock.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
-#include <qapplication.h>
-#include "wpagui.h"
-
-int main( int argc, char ** argv )
-{
-    QApplication a( argc, argv );
-    WpaGui w;
-    int ret;
-
-#ifdef CONFIG_NATIVE_WINDOWS
-    WSADATA wsaData;
-    if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
-       printf("Could not find a usable WinSock.dll\n");
-       return -1;
-    }
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-    w.show();
-    a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) );
-    ret = a.exec();
-
-#ifdef CONFIG_NATIVE_WINDOWS
-    WSACleanup();
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-    return ret;
-}
diff --git a/wpa_supplicant/wpa_gui/networkconfig.ui b/wpa_supplicant/wpa_gui/networkconfig.ui
deleted file mode 100644 (file)
index 019ecf7..0000000
+++ /dev/null
@@ -1,475 +0,0 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>NetworkConfig</class>
-<widget class="QDialog">
-    <property name="name">
-        <cstring>NetworkConfig</cstring>
-    </property>
-    <property name="geometry">
-        <rect>
-            <x>0</x>
-            <y>0</y>
-            <width>380</width>
-            <height>430</height>
-        </rect>
-    </property>
-    <property name="caption">
-        <string>NetworkConfig</string>
-    </property>
-    <grid>
-        <property name="name">
-            <cstring>unnamed</cstring>
-        </property>
-        <widget class="QPushButton" row="1" column="3">
-            <property name="name">
-                <cstring>cancelButton</cstring>
-            </property>
-            <property name="text">
-                <string>Cancel</string>
-            </property>
-        </widget>
-        <widget class="QFrame" row="0" column="0" rowspan="1" colspan="4">
-            <property name="name">
-                <cstring>frame9</cstring>
-            </property>
-            <property name="frameShape">
-                <enum>StyledPanel</enum>
-            </property>
-            <property name="frameShadow">
-                <enum>Raised</enum>
-            </property>
-            <grid>
-                <property name="name">
-                    <cstring>unnamed</cstring>
-                </property>
-                <widget class="QLabel" row="0" column="0">
-                    <property name="name">
-                        <cstring>textLabel0</cstring>
-                    </property>
-                    <property name="text">
-                        <string>SSID</string>
-                    </property>
-                </widget>
-                <widget class="QLineEdit" row="0" column="1">
-                    <property name="name">
-                        <cstring>ssidEdit</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                    <property name="toolTip" stdset="0">
-                        <string>Network name (Service Set IDentifier)</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="1" column="0">
-                    <property name="name">
-                        <cstring>textLabel1</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Network ID</string>
-                    </property>
-                </widget>
-                <widget class="QLineEdit" row="1" column="1">
-                    <property name="name">
-                        <cstring>idstrEdit</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                    <property name="toolTip" stdset="0">
-                        <string>Network Identification String</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="2" column="0">
-                    <property name="name">
-                        <cstring>textLabel2</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Authentication</string>
-                    </property>
-                </widget>
-                <widget class="QComboBox" row="2" column="1">
-                    <item>
-                        <property name="text">
-                            <string>Plaintext or static WEP</string>
-                        </property>
-                    </item>
-                    <item>
-                        <property name="text">
-                            <string>IEEE 802.1X</string>
-                        </property>
-                    </item>
-                    <item>
-                        <property name="text">
-                            <string>WPA-Personal (PSK)</string>
-                        </property>
-                    </item>
-                    <item>
-                        <property name="text">
-                            <string>WPA-Enterprise (EAP)</string>
-                        </property>
-                    </item>
-                    <item>
-                        <property name="text">
-                            <string>WPA2-Personal (PSK)</string>
-                        </property>
-                    </item>
-                    <item>
-                        <property name="text">
-                            <string>WPA2-Enterprise (EAP)</string>
-                        </property>
-                    </item>
-                    <property name="name">
-                        <cstring>authSelect</cstring>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="3" column="0">
-                    <property name="name">
-                        <cstring>textLabel3</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Encryption</string>
-                    </property>
-                </widget>
-                <widget class="QComboBox" row="3" column="1">
-                    <item>
-                        <property name="text">
-                            <string>None</string>
-                        </property>
-                    </item>
-                    <item>
-                        <property name="text">
-                            <string>WEP</string>
-                        </property>
-                    </item>
-                    <item>
-                        <property name="text">
-                            <string>TKIP</string>
-                        </property>
-                    </item>
-                    <item>
-                        <property name="text">
-                            <string>CCMP</string>
-                        </property>
-                    </item>
-                    <property name="name">
-                        <cstring>encrSelect</cstring>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="4" column="0">
-                    <property name="name">
-                        <cstring>textLabel4</cstring>
-                    </property>
-                    <property name="text">
-                        <string>PSK</string>
-                    </property>
-                </widget>
-                <widget class="QLineEdit" row="4" column="1">
-                    <property name="name">
-                        <cstring>pskEdit</cstring>
-                    </property>
-                    <property name="enabled">
-                        <bool>false</bool>
-                    </property>
-                    <property name="echoMode">
-                        <enum>Password</enum>
-                    </property>
-                    <property name="toolTip" stdset="0">
-                        <string>WPA/WPA2 pre-shared key or passphrase</string>
-                    </property>
-                    <property name="whatsThis" stdset="0">
-                        <string></string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="5" column="0">
-                    <property name="name">
-                        <cstring>textLabel5</cstring>
-                    </property>
-                    <property name="text">
-                        <string>EAP method</string>
-                    </property>
-                </widget>
-                <widget class="QComboBox" row="5" column="1">
-                    <property name="name">
-                        <cstring>eapSelect</cstring>
-                    </property>
-                    <property name="enabled">
-                        <bool>false</bool>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="6" column="0">
-                    <property name="name">
-                        <cstring>textLabel6</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Identity</string>
-                    </property>
-                </widget>
-                <widget class="QLineEdit" row="6" column="1">
-                    <property name="name">
-                        <cstring>identityEdit</cstring>
-                    </property>
-                    <property name="enabled">
-                        <bool>false</bool>
-                    </property>
-                    <property name="toolTip" stdset="0">
-                        <string>Username/Identity for EAP methods</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="7" column="0">
-                    <property name="name">
-                        <cstring>textLabel7</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Password</string>
-                    </property>
-                </widget>
-                <widget class="QLineEdit" row="7" column="1">
-                    <property name="name">
-                        <cstring>passwordEdit</cstring>
-                    </property>
-                    <property name="enabled">
-                        <bool>false</bool>
-                    </property>
-                    <property name="echoMode">
-                        <enum>Password</enum>
-                    </property>
-                    <property name="toolTip" stdset="0">
-                        <string>Password for EAP methods</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="8" column="0">
-                    <property name="name">
-                        <cstring>textLabel1_2</cstring>
-                    </property>
-                    <property name="text">
-                        <string>CA certificate</string>
-                    </property>
-                </widget>
-                <widget class="QLineEdit" row="8" column="1">
-                    <property name="name">
-                        <cstring>cacertEdit</cstring>
-                    </property>
-                    <property name="enabled">
-                        <bool>false</bool>
-                    </property>
-                </widget>
-                <widget class="QButtonGroup" row="9" column="0" rowspan="1" colspan="2">
-                    <property name="name">
-                        <cstring>buttonGroup1</cstring>
-                    </property>
-                    <property name="enabled">
-                        <bool>true</bool>
-                    </property>
-                    <property name="title">
-                        <string>WEP keys</string>
-                    </property>
-                    <grid>
-                        <property name="name">
-                            <cstring>unnamed</cstring>
-                        </property>
-                        <widget class="QRadioButton" row="0" column="0">
-                            <property name="name">
-                                <cstring>wep0Radio</cstring>
-                            </property>
-                            <property name="enabled">
-                                <bool>false</bool>
-                            </property>
-                            <property name="text">
-                                <string>key 0</string>
-                            </property>
-                        </widget>
-                        <widget class="QRadioButton" row="1" column="0">
-                            <property name="name">
-                                <cstring>wep1Radio</cstring>
-                            </property>
-                            <property name="enabled">
-                                <bool>false</bool>
-                            </property>
-                            <property name="text">
-                                <string>key 1</string>
-                            </property>
-                        </widget>
-                        <widget class="QRadioButton" row="3" column="0">
-                            <property name="name">
-                                <cstring>wep3Radio</cstring>
-                            </property>
-                            <property name="enabled">
-                                <bool>false</bool>
-                            </property>
-                            <property name="text">
-                                <string>key 3</string>
-                            </property>
-                        </widget>
-                        <widget class="QRadioButton" row="2" column="0">
-                            <property name="name">
-                                <cstring>wep2Radio</cstring>
-                            </property>
-                            <property name="enabled">
-                                <bool>false</bool>
-                            </property>
-                            <property name="text">
-                                <string>key 2</string>
-                            </property>
-                        </widget>
-                        <widget class="QLineEdit" row="0" column="1">
-                            <property name="name">
-                                <cstring>wep0Edit</cstring>
-                            </property>
-                            <property name="enabled">
-                                <bool>false</bool>
-                            </property>
-                        </widget>
-                        <widget class="QLineEdit" row="1" column="1">
-                            <property name="name">
-                                <cstring>wep1Edit</cstring>
-                            </property>
-                            <property name="enabled">
-                                <bool>false</bool>
-                            </property>
-                        </widget>
-                        <widget class="QLineEdit" row="2" column="1">
-                            <property name="name">
-                                <cstring>wep2Edit</cstring>
-                            </property>
-                            <property name="enabled">
-                                <bool>false</bool>
-                            </property>
-                        </widget>
-                        <widget class="QLineEdit" row="3" column="1">
-                            <property name="name">
-                                <cstring>wep3Edit</cstring>
-                            </property>
-                            <property name="enabled">
-                                <bool>false</bool>
-                            </property>
-                        </widget>
-                    </grid>
-                </widget>
-            </grid>
-        </widget>
-        <spacer row="1" column="0">
-            <property name="name">
-                <cstring>spacer5</cstring>
-            </property>
-            <property name="orientation">
-                <enum>Horizontal</enum>
-            </property>
-            <property name="sizeType">
-                <enum>Expanding</enum>
-            </property>
-            <property name="sizeHint">
-                <size>
-                    <width>130</width>
-                    <height>20</height>
-                </size>
-            </property>
-        </spacer>
-        <widget class="QPushButton" row="1" column="1">
-            <property name="name">
-                <cstring>addButton</cstring>
-            </property>
-            <property name="text">
-                <string>Add</string>
-            </property>
-        </widget>
-        <widget class="QPushButton" row="1" column="2">
-            <property name="name">
-                <cstring>removeButton</cstring>
-            </property>
-            <property name="enabled">
-                <bool>false</bool>
-            </property>
-            <property name="text">
-                <string>Remove</string>
-            </property>
-        </widget>
-    </grid>
-</widget>
-<connections>
-    <connection>
-        <sender>authSelect</sender>
-        <signal>activated(int)</signal>
-        <receiver>NetworkConfig</receiver>
-        <slot>authChanged(int)</slot>
-    </connection>
-    <connection>
-        <sender>cancelButton</sender>
-        <signal>clicked()</signal>
-        <receiver>NetworkConfig</receiver>
-        <slot>close()</slot>
-    </connection>
-    <connection>
-        <sender>addButton</sender>
-        <signal>clicked()</signal>
-        <receiver>NetworkConfig</receiver>
-        <slot>addNetwork()</slot>
-    </connection>
-    <connection>
-        <sender>encrSelect</sender>
-        <signal>activated(const QString&amp;)</signal>
-        <receiver>NetworkConfig</receiver>
-        <slot>encrChanged(const QString&amp;)</slot>
-    </connection>
-    <connection>
-        <sender>removeButton</sender>
-        <signal>clicked()</signal>
-        <receiver>NetworkConfig</receiver>
-        <slot>removeNetwork()</slot>
-    </connection>
-</connections>
-<tabstops>
-    <tabstop>ssidEdit</tabstop>
-    <tabstop>idstrEdit</tabstop>
-    <tabstop>authSelect</tabstop>
-    <tabstop>encrSelect</tabstop>
-    <tabstop>pskEdit</tabstop>
-    <tabstop>eapSelect</tabstop>
-    <tabstop>identityEdit</tabstop>
-    <tabstop>passwordEdit</tabstop>
-    <tabstop>cacertEdit</tabstop>
-    <tabstop>wep0Radio</tabstop>
-    <tabstop>wep1Radio</tabstop>
-    <tabstop>wep2Radio</tabstop>
-    <tabstop>wep3Radio</tabstop>
-    <tabstop>wep0Edit</tabstop>
-    <tabstop>wep1Edit</tabstop>
-    <tabstop>wep2Edit</tabstop>
-    <tabstop>wep3Edit</tabstop>
-    <tabstop>addButton</tabstop>
-    <tabstop>removeButton</tabstop>
-    <tabstop>cancelButton</tabstop>
-</tabstops>
-<includes>
-    <include location="global" impldecl="in declaration">qlistview.h</include>
-    <include location="global" impldecl="in implementation">qmessagebox.h</include>
-    <include location="local" impldecl="in implementation">wpagui.h</include>
-    <include location="local" impldecl="in implementation">networkconfig.ui.h</include>
-</includes>
-<forwards>
-    <forward>class WpaGui;</forward>
-</forwards>
-<variables>
-    <variable access="private">WpaGui *wpagui;</variable>
-    <variable access="private">int edit_network_id;</variable>
-    <variable access="private">bool new_network;</variable>
-</variables>
-<slots>
-    <slot>authChanged( int sel )</slot>
-    <slot>addNetwork()</slot>
-    <slot>encrChanged( const QString &amp; sel )</slot>
-    <slot>writeWepKey( int network_id, QLineEdit * edit, int id )</slot>
-    <slot>removeNetwork()</slot>
-</slots>
-<functions>
-    <function access="private" specifier="non virtual">init()</function>
-    <function>paramsFromScanResults( QListViewItem * sel )</function>
-    <function>setWpaGui( WpaGui * _wpagui )</function>
-    <function returnType="int">setNetworkParam( int id, const char * field, const char * value, bool quote )</function>
-    <function access="private">wepEnabled( bool enabled )</function>
-    <function>paramsFromConfig( int network_id )</function>
-    <function>newNetwork()</function>
-    <function access="private">getEapCapa()</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
diff --git a/wpa_supplicant/wpa_gui/networkconfig.ui.h b/wpa_supplicant/wpa_gui/networkconfig.ui.h
deleted file mode 100644 (file)
index 501d5d2..0000000
+++ /dev/null
@@ -1,552 +0,0 @@
-/****************************************************************************
-** ui.h extension file, included from the uic-generated form implementation.
-**
-** If you want to add, delete, or rename functions or slots, use
-** Qt Designer to update this file, preserving your code.
-**
-** You should not define a constructor or destructor in this file.
-** Instead, write your code in functions called init() and destroy().
-** These will automatically be called by the form's constructor and
-** destructor.
-*****************************************************************************/
-
-#include <stdlib.h>
-
-enum {
-    AUTH_NONE = 0,
-    AUTH_IEEE8021X = 1,
-    AUTH_WPA_PSK = 2,
-    AUTH_WPA_EAP = 3,
-    AUTH_WPA2_PSK = 4,
-    AUTH_WPA2_EAP = 5
-};
-
-#define WPA_GUI_KEY_DATA "[key is configured]"
-
-void NetworkConfig::init()
-{
-    wpagui = NULL;
-    new_network = false;
-}
-
-void NetworkConfig::paramsFromScanResults(Q3ListViewItem *sel)
-{
-    new_network = true;
-
-    /* SSID BSSID frequency signal flags */
-    setCaption(sel->text(0));
-    ssidEdit->setText(sel->text(0));
-    
-    QString flags = sel->text(4);
-    int auth, encr = 0;
-    if (flags.find("[WPA2-EAP") >= 0)
-       auth = AUTH_WPA2_EAP;
-    else if (flags.find("[WPA-EAP") >= 0)
-       auth = AUTH_WPA_EAP;
-    else if (flags.find("[WPA2-PSK") >= 0)
-       auth = AUTH_WPA2_PSK;
-    else if (flags.find("[WPA-PSK") >= 0)
-       auth = AUTH_WPA_PSK;
-    else
-       auth = AUTH_NONE;
-    
-    if (flags.find("-CCMP") >= 0)
-       encr = 1;
-    else if (flags.find("-TKIP") >= 0)
-       encr = 0;
-    else if (flags.find("WEP") >= 0)
-       encr = 1;
-    else
-       encr = 0;
-    authSelect->setCurrentItem(auth);
-    authChanged(auth);
-    encrSelect->setCurrentItem(encr);
-
-    getEapCapa();
-}
-
-
-void NetworkConfig::authChanged(int sel)
-{
-    pskEdit->setEnabled(sel == AUTH_WPA_PSK || sel == AUTH_WPA2_PSK);
-    bool eap = sel == AUTH_IEEE8021X || sel == AUTH_WPA_EAP ||
-              sel == AUTH_WPA2_EAP;
-    eapSelect->setEnabled(eap);
-    identityEdit->setEnabled(eap);
-    passwordEdit->setEnabled(eap);
-    cacertEdit->setEnabled(eap);
-   
-    while (encrSelect->count())
-       encrSelect->removeItem(0);
-    
-    if (sel == AUTH_NONE || sel == AUTH_IEEE8021X) {
-       encrSelect->insertItem("None");
-       encrSelect->insertItem("WEP");
-       encrSelect->setCurrentItem(sel == AUTH_NONE ? 0 : 1);
-    } else {
-       encrSelect->insertItem("TKIP");
-       encrSelect->insertItem("CCMP");
-       encrSelect->setCurrentItem((sel == AUTH_WPA2_PSK ||
-                                   sel == AUTH_WPA2_EAP) ? 1 : 0);
-    }
-    
-    wepEnabled(sel == AUTH_IEEE8021X);
-}
-
-
-void NetworkConfig::addNetwork()
-{
-    char reply[10], cmd[256];
-    size_t reply_len;
-    int id;
-    int psklen = pskEdit->text().length();
-    int auth = authSelect->currentItem();
-
-    if (auth == AUTH_WPA_PSK || auth == AUTH_WPA2_PSK) {
-       if (psklen < 8 || psklen > 64) {
-           QMessageBox::warning(this, "wpa_gui", "WPA-PSK requires a passphrase "
-                                "of 8 to 63 characters\n"
-                                "or 64 hex digit PSK");
-           return;
-       }
-    }
-        
-    if (wpagui == NULL)
-       return;
-    
-    memset(reply, 0, sizeof(reply));
-    reply_len = sizeof(reply) - 1;
-    
-    if (new_network) {
-       wpagui->ctrlRequest("ADD_NETWORK", reply, &reply_len);
-       if (reply[0] == 'F') {
-           QMessageBox::warning(this, "wpa_gui", "Failed to add network to wpa_supplicant\n"
-                                "configuration.");
-           return;
-       }
-       id = atoi(reply);
-    } else {
-       id = edit_network_id;
-    }
-
-    setNetworkParam(id, "ssid", ssidEdit->text().ascii(), true);
-    
-    if (idstrEdit->isEnabled())
-       setNetworkParam(id, "id_str", idstrEdit->text().ascii(), true);
-
-    const char *key_mgmt = NULL, *proto = NULL, *pairwise = NULL;
-    switch (auth) {
-    case AUTH_NONE:
-       key_mgmt = "NONE";
-       break;
-    case AUTH_IEEE8021X:
-       key_mgmt = "IEEE8021X";
-       break;
-    case AUTH_WPA_PSK:
-       key_mgmt = "WPA-PSK";
-       proto = "WPA";
-       break;
-    case AUTH_WPA_EAP:
-       key_mgmt = "WPA-EAP";
-       proto = "WPA";
-       break;
-    case AUTH_WPA2_PSK:
-       key_mgmt = "WPA-PSK";
-       proto = "WPA2";
-       break;
-    case AUTH_WPA2_EAP:
-       key_mgmt = "WPA-EAP";
-       proto = "WPA2";
-       break;
-    }
-    
-    if (auth == AUTH_WPA_PSK || auth == AUTH_WPA_EAP ||
-       auth == AUTH_WPA2_PSK || auth == AUTH_WPA2_EAP) {
-       int encr = encrSelect->currentItem();
-       if (encr == 0)
-           pairwise = "TKIP";
-       else
-           pairwise = "CCMP";
-    }
-    
-    if (proto)
-       setNetworkParam(id, "proto", proto, false);
-    if (key_mgmt)
-       setNetworkParam(id, "key_mgmt", key_mgmt, false);
-    if (pairwise) {
-       setNetworkParam(id, "pairwise", pairwise, false);
-       setNetworkParam(id, "group", "TKIP CCMP WEP104 WEP40", false);
-    }
-    if (pskEdit->isEnabled() &&
-       strcmp(pskEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0)
-       setNetworkParam(id, "psk", pskEdit->text().ascii(), psklen != 64);
-    if (eapSelect->isEnabled())
-       setNetworkParam(id, "eap", eapSelect->currentText().ascii(), false);
-    if (identityEdit->isEnabled())
-       setNetworkParam(id, "identity", identityEdit->text().ascii(), true);
-    if (passwordEdit->isEnabled() &&
-       strcmp(passwordEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0)
-       setNetworkParam(id, "password", passwordEdit->text().ascii(), true);
-    if (cacertEdit->isEnabled())
-       setNetworkParam(id, "ca_cert", cacertEdit->text().ascii(), true);
-    writeWepKey(id, wep0Edit, 0);
-    writeWepKey(id, wep1Edit, 1);
-    writeWepKey(id, wep2Edit, 2);
-    writeWepKey(id, wep3Edit, 3);
-  
-    if (wep0Radio->isEnabled() && wep0Radio->isChecked())
-       setNetworkParam(id, "wep_tx_keyidx", "0", false);
-    else if (wep1Radio->isEnabled() && wep1Radio->isChecked())
-       setNetworkParam(id, "wep_tx_keyidx", "1", false);
-    else if (wep2Radio->isEnabled() && wep2Radio->isChecked())
-       setNetworkParam(id, "wep_tx_keyidx", "2", false);
-    else if (wep3Radio->isEnabled() && wep3Radio->isChecked())
-       setNetworkParam(id, "wep_tx_keyidx", "3", false);
-
-    snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %d", id);
-    reply_len = sizeof(reply);
-    wpagui->ctrlRequest(cmd, reply, &reply_len);
-    if (strncmp(reply, "OK", 2) != 0) {
-       QMessageBox::warning(this, "wpa_gui", "Failed to enable network in wpa_supplicant\n"
-                            "configuration.");
-       /* Network was added, so continue anyway */
-    }
-    wpagui->triggerUpdate();
-    wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len);
-
-    close();
-}
-
-
-void NetworkConfig::setWpaGui( WpaGui *_wpagui )
-{
-    wpagui = _wpagui;
-}
-
-
-int NetworkConfig::setNetworkParam(int id, const char *field, const char *value, bool quote)
-{
-    char reply[10], cmd[256];
-    size_t reply_len;
-    snprintf(cmd, sizeof(cmd), "SET_NETWORK %d %s %s%s%s",
-            id, field, quote ? "\"" : "", value, quote ? "\"" : "");
-    reply_len = sizeof(reply);
-    wpagui->ctrlRequest(cmd, reply, &reply_len);
-    return strncmp(reply, "OK", 2) == 0 ? 0 : -1;
-}
-
-
-void NetworkConfig::encrChanged( const QString &sel )
-{
-    wepEnabled(sel.find("WEP") == 0);
-}
-
-
-void NetworkConfig::wepEnabled( bool enabled )
-{
-    wep0Edit->setEnabled(enabled);
-    wep1Edit->setEnabled(enabled);
-    wep2Edit->setEnabled(enabled);
-    wep3Edit->setEnabled(enabled);
-    wep0Radio->setEnabled(enabled);
-    wep1Radio->setEnabled(enabled);
-    wep2Radio->setEnabled(enabled);
-    wep3Radio->setEnabled(enabled);
-}
-
-
-void NetworkConfig::writeWepKey( int network_id, QLineEdit *edit, int id )
-{
-    char buf[10];
-    bool hex;
-    const char *txt, *pos;
-    size_t len;
-  
-    if (!edit->isEnabled() || edit->text().isEmpty())
-       return;
-    
-    /*
-        * Assume hex key if only hex characters are present and length matches
-       * with 40, 104, or 128-bit key
-       */
-    txt = edit->text().ascii();
-    if (strcmp(txt, WPA_GUI_KEY_DATA) == 0)
-       return;
-    len = strlen(txt);
-    if (len == 0)
-       return;
-    pos = txt;
-    hex = true;
-    while (*pos) {
-       if (!((*pos >= '0' && *pos <= '9') || (*pos >= 'a' && *pos <= 'f') ||
-             (*pos >= 'A' && *pos <= 'F'))) {
-           hex = false;
-           break;
-       }
-       pos++;
-    }
-    if (hex && len != 10 && len != 26 && len != 32)
-       hex = false;
-    snprintf(buf, sizeof(buf), "wep_key%d", id);
-    setNetworkParam(network_id, buf, txt, !hex);
-}
-
-
-static int key_value_isset(const char *reply, size_t reply_len)
-{
-    return reply_len > 0 && (reply_len < 4 || memcmp(reply, "FAIL", 4) != 0);
-}
-
-
-void NetworkConfig::paramsFromConfig( int network_id )
-{
-    int i, res;
-
-    edit_network_id = network_id;
-    getEapCapa();
-    
-    char reply[1024], cmd[256], *pos;
-    size_t reply_len;
-    
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", network_id);
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
-       reply[0] == '"') {
-       reply[reply_len] = '\0';
-       pos = strchr(reply + 1, '"');
-       if (pos)
-           *pos = '\0';
-       ssidEdit->setText(reply + 1);
-    }
-
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d id_str", network_id);
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
-       reply[0] == '"') {
-       reply[reply_len] = '\0';
-       pos = strchr(reply + 1, '"');
-       if (pos)
-           *pos = '\0';
-       idstrEdit->setText(reply + 1);
-    }
-    
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d proto", network_id);
-    reply_len = sizeof(reply) - 1;
-    int wpa = 0;
-    if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
-       reply[reply_len] = '\0';
-       if (strstr(reply, "RSN") || strstr(reply, "WPA2"))
-           wpa = 2;
-       else if (strstr(reply, "WPA"))
-           wpa = 1;
-    }
-
-    int auth = AUTH_NONE, encr = 0;
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d key_mgmt", network_id);
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
-       reply[reply_len] = '\0';
-       if (strstr(reply, "WPA-EAP"))
-           auth = wpa & 2 ? AUTH_WPA2_EAP : AUTH_WPA_EAP;
-       else if (strstr(reply, "WPA-PSK"))
-           auth = wpa & 2 ? AUTH_WPA2_PSK : AUTH_WPA_PSK;
-       else if (strstr(reply, "IEEE8021X")) {
-           auth = AUTH_IEEE8021X;
-           encr = 1;
-       }
-    }
-
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d pairwise", network_id);
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
-       reply[reply_len] = '\0';
-       if (strstr(reply, "CCMP") && auth != AUTH_NONE)
-           encr = 1;
-       else if (strstr(reply, "TKIP"))
-           encr = 0;
-       else if (strstr(reply, "WEP"))
-           encr = 1;
-       else
-           encr = 0;
-    }
-
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d psk", network_id);
-    reply_len = sizeof(reply) - 1;
-    res = wpagui->ctrlRequest(cmd, reply, &reply_len);
-    if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
-       reply[reply_len] = '\0';
-       pos = strchr(reply + 1, '"');
-       if (pos)
-           *pos = '\0';
-       pskEdit->setText(reply + 1);
-    } else if (res >= 0 && key_value_isset(reply, reply_len)) {
-       pskEdit->setText(WPA_GUI_KEY_DATA);
-    }
-
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d identity", network_id);
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
-       reply[0] == '"') {
-       reply[reply_len] = '\0';
-       pos = strchr(reply + 1, '"');
-       if (pos)
-           *pos = '\0';
-       identityEdit->setText(reply + 1);
-    }
-
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d password", network_id);
-    reply_len = sizeof(reply) - 1;
-    res = wpagui->ctrlRequest(cmd, reply, &reply_len);
-    if (res >= 0 && reply_len >= 2 &&
-       reply[0] == '"') {
-       reply[reply_len] = '\0';
-       pos = strchr(reply + 1, '"');
-       if (pos)
-           *pos = '\0';
-       passwordEdit->setText(reply + 1);
-    } else if (res >= 0 && key_value_isset(reply, reply_len)) {
-       passwordEdit->setText(WPA_GUI_KEY_DATA);
-    }
-
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ca_cert", network_id);
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
-       reply[0] == '"') {
-       reply[reply_len] = '\0';
-       pos = strchr(reply + 1, '"');
-       if (pos)
-           *pos = '\0';
-       cacertEdit->setText(reply + 1);
-    }
-
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d eap", network_id);
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) {
-       reply[reply_len] = '\0';
-       for (i = 0; i < eapSelect->count(); i++) {
-           if (eapSelect->text(i).compare(reply) == 0) {
-               eapSelect->setCurrentItem(i);
-               break;
-           }
-       }
-    }
-
-    for (i = 0; i < 4; i++) {
-       QLineEdit *wepEdit;
-       switch (i) {
-       default:
-       case 0:
-           wepEdit = wep0Edit;
-           break;
-       case 1:
-           wepEdit = wep1Edit;
-           break;
-       case 2:
-           wepEdit = wep2Edit;
-           break;
-       case 3:
-           wepEdit = wep3Edit;
-           break;
-       }
-       snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_key%d", network_id, i);
-       reply_len = sizeof(reply) - 1;
-       res = wpagui->ctrlRequest(cmd, reply, &reply_len);
-       if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
-           reply[reply_len] = '\0';
-           pos = strchr(reply + 1, '"');
-           if (pos)
-               *pos = '\0';
-           if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
-               encr = 1;
-
-           wepEdit->setText(reply + 1);
-       } else if (res >= 0 && key_value_isset(reply, reply_len)) {
-           if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
-               encr = 1;
-           wepEdit->setText(WPA_GUI_KEY_DATA);
-       }
-    }
-
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_tx_keyidx", network_id);
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) {
-       reply[reply_len] = '\0';
-       switch (atoi(reply)) {
-       case 0:
-           wep0Radio->setChecked(true);
-           break;
-       case 1:
-           wep1Radio->setChecked(true);
-           break;
-       case 2:
-           wep2Radio->setChecked(true);
-           break;
-       case 3:
-           wep3Radio->setChecked(true);
-           break;
-       }
-    }
-
-    authSelect->setCurrentItem(auth);
-    authChanged(auth);
-    encrSelect->setCurrentItem(encr);
-    if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
-       wepEnabled(encr == 1);
-
-    removeButton->setEnabled(true);
-    addButton->setText("Save");
-}
-
-
-void NetworkConfig::removeNetwork()
-{
-    char reply[10], cmd[256];
-    size_t reply_len;
-    
-    if (QMessageBox::information(this, "wpa_gui",
-                                "This will permanently remove the network\n"
-                                "from the configuration. Do you really want\n"
-                                "to remove this network?", "Yes", "No") != 0)
-       return;
-    
-    snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %d", edit_network_id);
-    reply_len = sizeof(reply);
-    wpagui->ctrlRequest(cmd, reply, &reply_len);
-    if (strncmp(reply, "OK", 2) != 0) {
-       QMessageBox::warning(this, "wpa_gui",
-                            "Failed to remove network from wpa_supplicant\n"
-                            "configuration.");
-    } else {
-       wpagui->triggerUpdate();
-       wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len);
-    }
-
-    close();
-}
-
-
-void NetworkConfig::newNetwork()
-{
-    new_network = true;
-    getEapCapa();
-}
-
-
-void NetworkConfig::getEapCapa()
-{
-    char reply[256];
-    size_t reply_len;
-    
-    if (wpagui == NULL)
-       return;
-
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest("GET_CAPABILITY eap", reply, &reply_len) < 0)
-       return;
-    reply[reply_len] = '\0';
-    
-    QString res(reply);
-    QStringList types = QStringList::split(QChar(' '), res);
-    eapSelect->insertStringList(types);
-}
diff --git a/wpa_supplicant/wpa_gui/scanresults.ui b/wpa_supplicant/wpa_gui/scanresults.ui
deleted file mode 100644 (file)
index dea305b..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>ScanResults</class>
-<widget class="QDialog">
-    <property name="name">
-        <cstring>ScanResults</cstring>
-    </property>
-    <property name="geometry">
-        <rect>
-            <x>0</x>
-            <y>0</y>
-            <width>452</width>
-            <height>225</height>
-        </rect>
-    </property>
-    <property name="caption">
-        <string>Scan results</string>
-    </property>
-    <vbox>
-        <property name="name">
-            <cstring>unnamed</cstring>
-        </property>
-        <widget class="QListView">
-            <column>
-                <property name="text">
-                    <string>SSID</string>
-                </property>
-                <property name="clickable">
-                    <bool>true</bool>
-                </property>
-                <property name="resizable">
-                    <bool>true</bool>
-                </property>
-            </column>
-            <column>
-                <property name="text">
-                    <string>BSSID</string>
-                </property>
-                <property name="clickable">
-                    <bool>true</bool>
-                </property>
-                <property name="resizable">
-                    <bool>true</bool>
-                </property>
-            </column>
-            <column>
-                <property name="text">
-                    <string>frequency</string>
-                </property>
-                <property name="clickable">
-                    <bool>true</bool>
-                </property>
-                <property name="resizable">
-                    <bool>true</bool>
-                </property>
-            </column>
-            <column>
-                <property name="text">
-                    <string>signal</string>
-                </property>
-                <property name="clickable">
-                    <bool>true</bool>
-                </property>
-                <property name="resizable">
-                    <bool>true</bool>
-                </property>
-            </column>
-            <column>
-                <property name="text">
-                    <string>flags</string>
-                </property>
-                <property name="clickable">
-                    <bool>true</bool>
-                </property>
-                <property name="resizable">
-                    <bool>true</bool>
-                </property>
-            </column>
-            <property name="name">
-                <cstring>scanResultsView</cstring>
-            </property>
-            <property name="frameShape">
-                <enum>StyledPanel</enum>
-            </property>
-            <property name="frameShadow">
-                <enum>Sunken</enum>
-            </property>
-        </widget>
-        <widget class="QLayoutWidget">
-            <property name="name">
-                <cstring>layout24</cstring>
-            </property>
-            <hbox>
-                <property name="name">
-                    <cstring>unnamed</cstring>
-                </property>
-                <spacer>
-                    <property name="name">
-                        <cstring>spacer6</cstring>
-                    </property>
-                    <property name="orientation">
-                        <enum>Horizontal</enum>
-                    </property>
-                    <property name="sizeType">
-                        <enum>Expanding</enum>
-                    </property>
-                    <property name="sizeHint">
-                        <size>
-                            <width>50</width>
-                            <height>20</height>
-                        </size>
-                    </property>
-                </spacer>
-                <widget class="QPushButton">
-                    <property name="name">
-                        <cstring>scanButton</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Scan</string>
-                    </property>
-                </widget>
-                <widget class="QPushButton">
-                    <property name="name">
-                        <cstring>closeButton</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Close</string>
-                    </property>
-                </widget>
-            </hbox>
-        </widget>
-    </vbox>
-</widget>
-<connections>
-    <connection>
-        <sender>closeButton</sender>
-        <signal>clicked()</signal>
-        <receiver>ScanResults</receiver>
-        <slot>close()</slot>
-    </connection>
-    <connection>
-        <sender>scanButton</sender>
-        <signal>clicked()</signal>
-        <receiver>ScanResults</receiver>
-        <slot>scanRequest()</slot>
-    </connection>
-    <connection>
-        <sender>scanResultsView</sender>
-        <signal>doubleClicked(QListViewItem*)</signal>
-        <receiver>ScanResults</receiver>
-        <slot>bssSelected(QListViewItem*)</slot>
-    </connection>
-</connections>
-<includes>
-    <include location="local" impldecl="in implementation">common/wpa_ctrl.h</include>
-    <include location="local" impldecl="in implementation">wpagui.h</include>
-    <include location="local" impldecl="in implementation">networkconfig.h</include>
-    <include location="local" impldecl="in implementation">scanresults.ui.h</include>
-</includes>
-<forwards>
-    <forward>class WpaGui;</forward>
-</forwards>
-<variables>
-    <variable access="private">WpaGui *wpagui;</variable>
-    <variable access="private">QTimer *timer;</variable>
-</variables>
-<slots>
-    <slot>setWpaGui( WpaGui * _wpagui )</slot>
-    <slot>updateResults()</slot>
-    <slot>scanRequest()</slot>
-    <slot>getResults()</slot>
-    <slot>bssSelected( QListViewItem * sel )</slot>
-</slots>
-<functions>
-    <function access="private" specifier="non virtual">init()</function>
-    <function access="private" specifier="non virtual">destroy()</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
diff --git a/wpa_supplicant/wpa_gui/scanresults.ui.h b/wpa_supplicant/wpa_gui/scanresults.ui.h
deleted file mode 100644 (file)
index 530d2e6..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/****************************************************************************
-** ui.h extension file, included from the uic-generated form implementation.
-**
-** If you want to add, delete, or rename functions or slots, use
-** Qt Designer to update this file, preserving your code.
-**
-** You should not define a constructor or destructor in this file.
-** Instead, write your code in functions called init() and destroy().
-** These will automatically be called by the form's constructor and
-** destructor.
-*****************************************************************************/
-
-void ScanResults::init()
-{
-    wpagui = NULL;
-}
-
-
-void ScanResults::destroy()
-{
-    delete timer;
-}
-
-
-void ScanResults::setWpaGui(WpaGui *_wpagui)
-{
-    wpagui = _wpagui;
-    updateResults();
-    
-    timer = new QTimer(this);
-    connect(timer, SIGNAL(timeout()), SLOT(getResults()));
-    timer->start(10000, FALSE);
-}
-
-
-void ScanResults::updateResults()
-{
-    char reply[8192];
-    size_t reply_len;
-    
-    if (wpagui == NULL)
-       return;
-
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest("SCAN_RESULTS", reply, &reply_len) < 0)
-       return;
-    reply[reply_len] = '\0';
-
-    scanResultsView->clear();
-    
-    QString res(reply);
-    QStringList lines = QStringList::split(QChar('\n'), res);
-    bool first = true;
-    for (QStringList::Iterator it = lines.begin(); it != lines.end(); it++) {
-       if (first) {
-           first = false;
-           continue;
-       }
-       
-       QStringList cols = QStringList::split(QChar('\t'), *it, true);
-       QString ssid, bssid, freq, signal, flags;
-       bssid = cols.count() > 0 ? cols[0] : "";
-       freq = cols.count() > 1 ? cols[1] : "";
-       signal = cols.count() > 2 ? cols[2] : "";
-       flags = cols.count() > 3 ? cols[3] : "";
-       ssid = cols.count() > 4 ? cols[4] : "";
-       new Q3ListViewItem(scanResultsView, ssid, bssid, freq, signal, flags);
-    }
-}
-
-
-void ScanResults::scanRequest()
-{
-    char reply[10];
-    size_t reply_len = sizeof(reply);
-    
-    if (wpagui == NULL)
-       return;
-    
-    wpagui->ctrlRequest("SCAN", reply, &reply_len);
-}
-
-
-void ScanResults::getResults()
-{
-    updateResults();
-}
-
-
-
-
-void ScanResults::bssSelected( Q3ListViewItem * sel )
-{
-    NetworkConfig *nc = new NetworkConfig();
-    if (nc == NULL)
-       return;
-    nc->setWpaGui(wpagui);
-    nc->paramsFromScanResults(sel);
-    nc->show();
-    nc->exec();
-}
diff --git a/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling b/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling
deleted file mode 100755 (executable)
index e173b00..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-# qmake seems to be forcing include and lib paths from the original build
-# and I have no idea how to change these. For now, just override the
-# directories in the Makefile.Release file after qmake run.
-
-qmake -spec /q/jm/qt4-win/4.0.0/mkspecs/win32-g++ wpa_gui.pro -o Makefile
-cat Makefile.Release |
-    sed s%qt4/lib%qt4-win/4.0.0/lib%g |
-    sed s%qt4/include%qt4-win/4.0.0/include%g > tmp.Makefile.Release &&
-mv -f tmp.Makefile.Release Makefile.Release
diff --git a/wpa_supplicant/wpa_gui/userdatarequest.ui b/wpa_supplicant/wpa_gui/userdatarequest.ui
deleted file mode 100644 (file)
index 6106b1e..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>UserDataRequest</class>
-<widget class="QDialog">
-    <property name="name">
-        <cstring>UserDataRequest</cstring>
-    </property>
-    <property name="geometry">
-        <rect>
-            <x>0</x>
-            <y>0</y>
-            <width>216</width>
-            <height>103</height>
-        </rect>
-    </property>
-    <property name="caption">
-        <string>Authentication credentials required</string>
-    </property>
-    <property name="sizeGripEnabled">
-        <bool>true</bool>
-    </property>
-    <vbox>
-        <property name="name">
-            <cstring>unnamed</cstring>
-        </property>
-        <widget class="QLabel">
-            <property name="name">
-                <cstring>queryInfo</cstring>
-            </property>
-            <property name="text">
-                <string></string>
-            </property>
-        </widget>
-        <widget class="QLayoutWidget">
-            <property name="name">
-                <cstring>layout28</cstring>
-            </property>
-            <hbox>
-                <property name="name">
-                    <cstring>unnamed</cstring>
-                </property>
-                <widget class="QLabel">
-                    <property name="name">
-                        <cstring>queryField</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                </widget>
-                <widget class="QLineEdit">
-                    <property name="name">
-                        <cstring>queryEdit</cstring>
-                    </property>
-                    <property name="enabled">
-                        <bool>true</bool>
-                    </property>
-                    <property name="echoMode">
-                        <enum>Password</enum>
-                    </property>
-                </widget>
-            </hbox>
-        </widget>
-        <widget class="QLayoutWidget">
-            <property name="name">
-                <cstring>layout27</cstring>
-            </property>
-            <hbox>
-                <property name="name">
-                    <cstring>unnamed</cstring>
-                </property>
-                <spacer>
-                    <property name="name">
-                        <cstring>spacer4</cstring>
-                    </property>
-                    <property name="orientation">
-                        <enum>Horizontal</enum>
-                    </property>
-                    <property name="sizeType">
-                        <enum>Expanding</enum>
-                    </property>
-                    <property name="sizeHint">
-                        <size>
-                            <width>20</width>
-                            <height>20</height>
-                        </size>
-                    </property>
-                </spacer>
-                <widget class="QPushButton">
-                    <property name="name">
-                        <cstring>buttonOk</cstring>
-                    </property>
-                    <property name="text">
-                        <string>&amp;OK</string>
-                    </property>
-                    <property name="accel">
-                        <string></string>
-                    </property>
-                    <property name="autoDefault">
-                        <bool>true</bool>
-                    </property>
-                    <property name="default">
-                        <bool>true</bool>
-                    </property>
-                </widget>
-                <widget class="QPushButton">
-                    <property name="name">
-                        <cstring>buttonCancel</cstring>
-                    </property>
-                    <property name="text">
-                        <string>&amp;Cancel</string>
-                    </property>
-                    <property name="accel">
-                        <string></string>
-                    </property>
-                    <property name="autoDefault">
-                        <bool>true</bool>
-                    </property>
-                </widget>
-            </hbox>
-        </widget>
-    </vbox>
-</widget>
-<connections>
-    <connection>
-        <sender>buttonOk</sender>
-        <signal>clicked()</signal>
-        <receiver>UserDataRequest</receiver>
-        <slot>sendReply()</slot>
-    </connection>
-    <connection>
-        <sender>buttonCancel</sender>
-        <signal>clicked()</signal>
-        <receiver>UserDataRequest</receiver>
-        <slot>reject()</slot>
-    </connection>
-    <connection>
-        <sender>queryEdit</sender>
-        <signal>returnPressed()</signal>
-        <receiver>UserDataRequest</receiver>
-        <slot>sendReply()</slot>
-    </connection>
-</connections>
-<includes>
-    <include location="local" impldecl="in implementation">common/wpa_ctrl.h</include>
-    <include location="local" impldecl="in implementation">wpagui.h</include>
-    <include location="local" impldecl="in implementation">userdatarequest.ui.h</include>
-</includes>
-<forwards>
-    <forward>class WpaGui;</forward>
-</forwards>
-<variables>
-    <variable access="private">WpaGui *wpagui;</variable>
-    <variable access="private">int networkid;</variable>
-    <variable access="private">QString field;</variable>
-</variables>
-<slots>
-    <slot>sendReply()</slot>
-</slots>
-<functions>
-    <function specifier="non virtual" returnType="int">setParams( WpaGui * _wpagui, const char * reqMsg )</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
diff --git a/wpa_supplicant/wpa_gui/userdatarequest.ui.h b/wpa_supplicant/wpa_gui/userdatarequest.ui.h
deleted file mode 100644 (file)
index 66d4478..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/****************************************************************************
-** ui.h extension file, included from the uic-generated form implementation.
-**
-** If you want to add, delete, or rename functions or slots, use
-** Qt Designer to update this file, preserving your code.
-**
-** You should not define a constructor or destructor in this file.
-** Instead, write your code in functions called init() and destroy().
-** These will automatically be called by the form's constructor and
-** destructor.
-*****************************************************************************/
-
-#include <stdlib.h>
-
-int UserDataRequest::setParams(WpaGui *_wpagui, const char *reqMsg)
-{
-    char *tmp, *pos, *pos2;
-    wpagui = _wpagui;
-    tmp = strdup(reqMsg);
-    if (tmp == NULL)
-       return -1;
-    pos = strchr(tmp, '-');
-    if (pos == NULL) {
-       free(tmp);
-       return -1;
-    }
-    *pos++ = '\0';
-    field = tmp;
-    pos2 = strchr(pos, ':');
-    if (pos2 == NULL) {
-       free(tmp);
-       return -1;
-    }
-    *pos2++ = '\0';
-    
-    networkid = atoi(pos);
-    queryInfo->setText(pos2);
-    if (strcmp(tmp, "PASSWORD") == 0) {
-       queryField->setText("Password: ");
-       queryEdit->setEchoMode(QLineEdit::Password);
-    } else if (strcmp(tmp, "NEW_PASSWORD") == 0) {
-       queryField->setText("New password: ");
-       queryEdit->setEchoMode(QLineEdit::Password);
-    } else if (strcmp(tmp, "IDENTITY") == 0)
-       queryField->setText("Identity: ");
-    else if (strcmp(tmp, "PASSPHRASE") == 0) {
-       queryField->setText("Private key passphrase: ");
-       queryEdit->setEchoMode(QLineEdit::Password);
-    } else
-       queryField->setText(field + ":");
-    free(tmp);
-    
-    return 0;
-}
-
-
-void UserDataRequest::sendReply()
-{
-    char reply[10];
-    size_t reply_len = sizeof(reply);
-    
-    if (wpagui == NULL) {
-       reject();
-       return;
-    }
-    
-    QString cmd = QString(WPA_CTRL_RSP) + field + '-' +
-                 QString::number(networkid) + ':' +
-                 queryEdit->text();
-    wpagui->ctrlRequest(cmd.ascii(), reply, &reply_len);
-    accept();
-}
diff --git a/wpa_supplicant/wpa_gui/wpa_gui.pro b/wpa_supplicant/wpa_gui/wpa_gui.pro
deleted file mode 100644 (file)
index a42a4ac..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-TEMPLATE       = app
-LANGUAGE       = C++
-
-CONFIG += qt warn_on release
-
-DEFINES += CONFIG_CTRL_IFACE
-
-win32 {
-  LIBS += -lws2_32 -static
-  DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE
-  SOURCES += ../../src/utils/os_win32.c
-} else:win32-g++ {
-  # cross compilation to win32
-  LIBS += -lws2_32 -static
-  DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE
-  SOURCES += ../../src/utils/os_win32.c
-} else {
-  DEFINES += CONFIG_CTRL_IFACE_UNIX
-  SOURCES += ../../src/utils/os_unix.c
-}
-
-INCLUDEPATH    += . .. ../../src ../../src/utils
-
-HEADERS        += wpamsg.h
-
-SOURCES        += main.cpp \
-       ../../src/common/wpa_ctrl.c
-
-FORMS  = wpagui.ui \
-       eventhistory.ui \
-       scanresults.ui \
-       userdatarequest.ui \
-       networkconfig.ui
-
-
-unix {
-  UI_DIR = .ui
-  MOC_DIR = .moc
-  OBJECTS_DIR = .obj
-}
-
-qtver = $$[QT_VERSION]
-isEmpty( qtver ) {
-       message(Compiling for Qt 3.x)
-       DEFINES += Q3ListViewItem=QListViewItem
-} else {
-       message(Compiling for Qt $$qtver)
-       QT += qt3support
-       CONFIG += uic3
-}
diff --git a/wpa_supplicant/wpa_gui/wpagui.ui b/wpa_supplicant/wpa_gui/wpagui.ui
deleted file mode 100644 (file)
index b49d96b..0000000
+++ /dev/null
@@ -1,471 +0,0 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>WpaGui</class>
-<widget class="QMainWindow">
-    <property name="name">
-        <cstring>WpaGui</cstring>
-    </property>
-    <property name="geometry">
-        <rect>
-            <x>0</x>
-            <y>0</y>
-            <width>279</width>
-            <height>308</height>
-        </rect>
-    </property>
-    <property name="caption">
-        <string>wpa_gui</string>
-    </property>
-    <grid>
-        <property name="name">
-            <cstring>unnamed</cstring>
-        </property>
-        <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
-            <property name="name">
-                <cstring>textLabel16</cstring>
-            </property>
-            <property name="text">
-                <string>Adapter:</string>
-            </property>
-        </widget>
-        <widget class="QComboBox" row="0" column="2" rowspan="1" colspan="2">
-            <property name="name">
-                <cstring>adapterSelect</cstring>
-            </property>
-        </widget>
-        <widget class="QLabel" row="1" column="0" rowspan="1" colspan="2">
-            <property name="name">
-                <cstring>textLabel8</cstring>
-            </property>
-            <property name="text">
-                <string>Network:</string>
-            </property>
-        </widget>
-        <widget class="QComboBox" row="1" column="2" rowspan="1" colspan="2">
-            <property name="name">
-                <cstring>networkSelect</cstring>
-            </property>
-        </widget>
-        <widget class="QFrame" row="2" column="0" rowspan="1" colspan="4">
-            <property name="name">
-                <cstring>frame3</cstring>
-            </property>
-            <property name="frameShape">
-                <enum>StyledPanel</enum>
-            </property>
-            <property name="frameShadow">
-                <enum>Raised</enum>
-            </property>
-            <grid>
-                <property name="name">
-                    <cstring>unnamed</cstring>
-                </property>
-                <widget class="QLabel" row="0" column="0">
-                    <property name="name">
-                        <cstring>textLabel1</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Status:</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="1" column="0">
-                    <property name="name">
-                        <cstring>textLabel2</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Last message:</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="2" column="0">
-                    <property name="name">
-                        <cstring>textLabel3</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Authentication:</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="3" column="0">
-                    <property name="name">
-                        <cstring>textLabel4</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Encryption:</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="4" column="0">
-                    <property name="name">
-                        <cstring>textLabel5</cstring>
-                    </property>
-                    <property name="text">
-                        <string>SSID:</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="5" column="0">
-                    <property name="name">
-                        <cstring>textLabel6</cstring>
-                    </property>
-                    <property name="text">
-                        <string>BSSID:</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="6" column="0">
-                    <property name="name">
-                        <cstring>textLabel7</cstring>
-                    </property>
-                    <property name="text">
-                        <string>IP address:</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="0" column="1">
-                    <property name="name">
-                        <cstring>textStatus</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="1" column="1" rowspan="1" colspan="3">
-                    <property name="name">
-                        <cstring>textLastMessage</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="2" column="1">
-                    <property name="name">
-                        <cstring>textAuthentication</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="3" column="1">
-                    <property name="name">
-                        <cstring>textEncryption</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="4" column="1">
-                    <property name="name">
-                        <cstring>textSsid</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="5" column="1">
-                    <property name="name">
-                        <cstring>textBssid</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="6" column="1">
-                    <property name="name">
-                        <cstring>textIpAddress</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                </widget>
-            </grid>
-        </widget>
-        <spacer row="3" column="0">
-            <property name="name">
-                <cstring>spacer7</cstring>
-            </property>
-            <property name="orientation">
-                <enum>Horizontal</enum>
-            </property>
-            <property name="sizeType">
-                <enum>Expanding</enum>
-            </property>
-            <property name="sizeHint">
-                <size>
-                    <width>16</width>
-                    <height>16</height>
-                </size>
-            </property>
-        </spacer>
-        <widget class="QPushButton" row="3" column="1">
-            <property name="name">
-                <cstring>connectButton</cstring>
-            </property>
-            <property name="text">
-                <string>Connect</string>
-            </property>
-        </widget>
-        <widget class="QPushButton" row="3" column="2">
-            <property name="name">
-                <cstring>disconnectButton</cstring>
-            </property>
-            <property name="text">
-                <string>Disconnect</string>
-            </property>
-        </widget>
-        <widget class="QPushButton" row="3" column="3">
-            <property name="name">
-                <cstring>scanButton</cstring>
-            </property>
-            <property name="text">
-                <string>Scan</string>
-            </property>
-        </widget>
-    </grid>
-</widget>
-<menubar>
-    <property name="name">
-        <cstring>MenuBar</cstring>
-    </property>
-    <item text="&amp;File" name="fileMenu">
-        <separator/>
-        <action name="fileEventHistoryAction"/>
-        <action name="fileAdd_NetworkAction"/>
-        <action name="fileEdit_networkAction"/>
-        <separator/>
-        <action name="fileExitAction"/>
-    </item>
-    <item text="&amp;Help" name="helpMenu">
-        <action name="helpContentsAction"/>
-        <action name="helpIndexAction"/>
-        <separator/>
-        <action name="helpAboutAction"/>
-    </item>
-</menubar>
-<toolbars>
-</toolbars>
-<actions>
-    <action>
-        <property name="name">
-            <cstring>fileExitAction</cstring>
-        </property>
-        <property name="text">
-            <string>Exit</string>
-        </property>
-        <property name="menuText">
-            <string>E&amp;xit</string>
-        </property>
-        <property name="accel">
-            <string>Ctrl+Q</string>
-        </property>
-    </action>
-    <action>
-        <property name="name">
-            <cstring>helpContentsAction</cstring>
-        </property>
-        <property name="enabled">
-            <bool>false</bool>
-        </property>
-        <property name="text">
-            <string>Contents</string>
-        </property>
-        <property name="menuText">
-            <string>&amp;Contents...</string>
-        </property>
-        <property name="accel">
-            <string></string>
-        </property>
-    </action>
-    <action>
-        <property name="name">
-            <cstring>helpIndexAction</cstring>
-        </property>
-        <property name="enabled">
-            <bool>false</bool>
-        </property>
-        <property name="text">
-            <string>Index</string>
-        </property>
-        <property name="menuText">
-            <string>&amp;Index...</string>
-        </property>
-        <property name="accel">
-            <string></string>
-        </property>
-    </action>
-    <action>
-        <property name="name">
-            <cstring>helpAboutAction</cstring>
-        </property>
-        <property name="text">
-            <string>About</string>
-        </property>
-        <property name="menuText">
-            <string>&amp;About</string>
-        </property>
-        <property name="accel">
-            <string></string>
-        </property>
-    </action>
-    <action>
-        <property name="name">
-            <cstring>fileEventHistoryAction</cstring>
-        </property>
-        <property name="text">
-            <string>Event History</string>
-        </property>
-        <property name="menuText">
-            <string>Event &amp;History</string>
-        </property>
-    </action>
-    <action>
-        <property name="name">
-            <cstring>fileAdd_NetworkAction</cstring>
-        </property>
-        <property name="text">
-            <string>Add Network</string>
-        </property>
-        <property name="menuText">
-            <string>&amp;Add Network</string>
-        </property>
-    </action>
-    <action>
-        <property name="name">
-            <cstring>fileEdit_networkAction</cstring>
-        </property>
-        <property name="text">
-            <string>Edit Network</string>
-        </property>
-        <property name="menuText">
-            <string>&amp;Edit Network</string>
-        </property>
-    </action>
-</actions>
-<connections>
-    <connection>
-        <sender>helpIndexAction</sender>
-        <signal>activated()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>helpIndex()</slot>
-    </connection>
-    <connection>
-        <sender>helpContentsAction</sender>
-        <signal>activated()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>helpContents()</slot>
-    </connection>
-    <connection>
-        <sender>helpAboutAction</sender>
-        <signal>activated()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>helpAbout()</slot>
-    </connection>
-    <connection>
-        <sender>fileExitAction</sender>
-        <signal>activated()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>close()</slot>
-    </connection>
-    <connection>
-        <sender>disconnectButton</sender>
-        <signal>clicked()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>disconnect()</slot>
-    </connection>
-    <connection>
-        <sender>scanButton</sender>
-        <signal>clicked()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>scan()</slot>
-    </connection>
-    <connection>
-        <sender>connectButton</sender>
-        <signal>clicked()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>connectB()</slot>
-    </connection>
-    <connection>
-        <sender>fileEventHistoryAction</sender>
-        <signal>activated()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>eventHistory()</slot>
-    </connection>
-    <connection>
-        <sender>networkSelect</sender>
-        <signal>activated(const QString&amp;)</signal>
-        <receiver>WpaGui</receiver>
-        <slot>selectNetwork(const QString&amp;)</slot>
-    </connection>
-    <connection>
-        <sender>fileEdit_networkAction</sender>
-        <signal>activated()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>editNetwork()</slot>
-    </connection>
-    <connection>
-        <sender>fileAdd_NetworkAction</sender>
-        <signal>activated()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>addNetwork()</slot>
-    </connection>
-    <connection>
-        <sender>adapterSelect</sender>
-        <signal>activated(const QString&amp;)</signal>
-        <receiver>WpaGui</receiver>
-        <slot>selectAdapter(const QString&amp;)</slot>
-    </connection>
-</connections>
-<includes>
-    <include location="global" impldecl="in declaration">qtimer.h</include>
-    <include location="global" impldecl="in declaration">qsocketnotifier.h</include>
-    <include location="local" impldecl="in declaration">wpamsg.h</include>
-    <include location="local" impldecl="in declaration">eventhistory.h</include>
-    <include location="local" impldecl="in declaration">scanresults.h</include>
-    <include location="local" impldecl="in implementation">common/wpa_ctrl.h</include>
-    <include location="global" impldecl="in implementation">dirent.h</include>
-    <include location="global" impldecl="in implementation">qmessagebox.h</include>
-    <include location="global" impldecl="in implementation">qapplication.h</include>
-    <include location="local" impldecl="in implementation">userdatarequest.h</include>
-    <include location="local" impldecl="in implementation">networkconfig.h</include>
-    <include location="local" impldecl="in implementation">wpagui.ui.h</include>
-</includes>
-<forwards>
-    <forward>class UserDataRequest;</forward>
-</forwards>
-<variables>
-    <variable access="private">ScanResults *scanres;</variable>
-    <variable access="private">bool networkMayHaveChanged;</variable>
-    <variable access="private">char *ctrl_iface;</variable>
-    <variable access="private">EventHistory *eh;</variable>
-    <variable access="private">struct wpa_ctrl *ctrl_conn;</variable>
-    <variable access="private">QSocketNotifier *msgNotifier;</variable>
-    <variable access="private">QTimer *timer;</variable>
-    <variable access="private">int pingsToStatusUpdate;</variable>
-    <variable access="private">WpaMsgList msgs;</variable>
-    <variable access="private">char *ctrl_iface_dir;</variable>
-    <variable access="private">struct wpa_ctrl *monitor_conn;</variable>
-    <variable access="private">UserDataRequest *udr;</variable>
-</variables>
-<slots>
-    <slot>parse_argv()</slot>
-    <slot>updateStatus()</slot>
-    <slot>updateNetworks()</slot>
-    <slot>helpIndex()</slot>
-    <slot>helpContents()</slot>
-    <slot>helpAbout()</slot>
-    <slot>disconnect()</slot>
-    <slot>scan()</slot>
-    <slot>eventHistory()</slot>
-    <slot>ping()</slot>
-    <slot>processMsg( char * msg )</slot>
-    <slot>processCtrlReq( const char * req )</slot>
-    <slot>receiveMsgs()</slot>
-    <slot>connectB()</slot>
-    <slot>selectNetwork( const QString &amp; sel )</slot>
-    <slot>editNetwork()</slot>
-    <slot>addNetwork()</slot>
-    <slot>selectAdapter( const QString &amp; sel )</slot>
-</slots>
-<functions>
-    <function access="private" specifier="non virtual">init()</function>
-    <function access="private" specifier="non virtual">destroy()</function>
-    <function access="private" specifier="non virtual" returnType="int">openCtrlConnection( const char * ifname )</function>
-    <function returnType="int">ctrlRequest( const char * cmd, char * buf, size_t * buflen )</function>
-    <function>triggerUpdate()</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
diff --git a/wpa_supplicant/wpa_gui/wpagui.ui.h b/wpa_supplicant/wpa_gui/wpagui.ui.h
deleted file mode 100644 (file)
index 678ff1b..0000000
+++ /dev/null
@@ -1,730 +0,0 @@
-/****************************************************************************
-** ui.h extension file, included from the uic-generated form implementation.
-**
-** If you want to add, delete, or rename functions or slots, use
-** Qt Designer to update this file, preserving your code.
-**
-** You should not define a constructor or destructor in this file.
-** Instead, write your code in functions called init() and destroy().
-** These will automatically be called by the form's constructor and
-** destructor.
-*****************************************************************************/
-
-
-#ifdef __MINGW32__
-/* Need to get getopt() */
-#include <unistd.h>
-#endif
-
-#include <stdlib.h>
-
-void WpaGui::init()
-{
-    eh = NULL;
-    scanres = NULL;
-    udr = NULL;
-    ctrl_iface = NULL;
-    ctrl_conn = NULL;
-    monitor_conn = NULL;
-    msgNotifier = NULL;
-    ctrl_iface_dir = strdup("/var/run/wpa_supplicant");
-    
-    parse_argv();
-
-    textStatus->setText("connecting to wpa_supplicant");
-    timer = new QTimer(this);
-    connect(timer, SIGNAL(timeout()), SLOT(ping()));
-    timer->start(1000, FALSE);
-    
-    if (openCtrlConnection(ctrl_iface) < 0) {
-       printf("Failed to open control connection to wpa_supplicant.\n");
-    }
-    
-    updateStatus();
-    networkMayHaveChanged = true;
-    updateNetworks();
-}
-
-
-void WpaGui::destroy()
-{
-    delete msgNotifier;
-
-    if (monitor_conn) {
-       wpa_ctrl_detach(monitor_conn);
-       wpa_ctrl_close(monitor_conn);
-       monitor_conn = NULL;
-    }
-    if (ctrl_conn) {
-       wpa_ctrl_close(ctrl_conn);
-       ctrl_conn = NULL;
-    }
-    
-    if (eh) {
-       eh->close();
-       delete eh;
-       eh = NULL;
-    }
-    
-    if (scanres) {
-       scanres->close();
-       delete scanres;
-       scanres = NULL;
-    }
-    
-    if (udr) {
-       udr->close();
-       delete udr;
-       udr = NULL;
-    }
-    
-    free(ctrl_iface);
-    ctrl_iface = NULL;
-    
-    free(ctrl_iface_dir);
-    ctrl_iface_dir = NULL;
-}
-
-
-void WpaGui::parse_argv()
-{
-    int c;
-    for (;;) {
-       c = getopt(qApp->argc(), qApp->argv(), "i:p:");
-       if (c < 0)
-           break;
-       switch (c) {
-       case 'i':
-           free(ctrl_iface);
-           ctrl_iface = strdup(optarg);
-           break;
-       case 'p':
-           free(ctrl_iface_dir);
-           ctrl_iface_dir = strdup(optarg);
-           break;
-       }
-    }
-}
-
-
-int WpaGui::openCtrlConnection(const char *ifname)
-{
-    char *cfile;
-    int flen;
-    char buf[2048], *pos, *pos2;
-    size_t len;
-
-    if (ifname) {
-       if (ifname != ctrl_iface) {
-           free(ctrl_iface);
-           ctrl_iface = strdup(ifname);
-       }
-    } else {
-#ifdef CONFIG_CTRL_IFACE_UDP
-       free(ctrl_iface);
-       ctrl_iface = strdup("udp");
-#endif /* CONFIG_CTRL_IFACE_UDP */
-#ifdef CONFIG_CTRL_IFACE_UNIX
-       struct dirent *dent;
-       DIR *dir = opendir(ctrl_iface_dir);
-       free(ctrl_iface);
-       ctrl_iface = NULL;
-       if (dir) {
-           while ((dent = readdir(dir))) {
-#ifdef _DIRENT_HAVE_D_TYPE
-               /* Skip the file if it is not a socket.
-                * Also accept DT_UNKNOWN (0) in case
-                * the C library or underlying file
-                * system does not support d_type. */
-               if (dent->d_type != DT_SOCK &&
-                   dent->d_type != DT_UNKNOWN)
-                   continue;
-#endif /* _DIRENT_HAVE_D_TYPE */
-
-               if (strcmp(dent->d_name, ".") == 0 ||
-                   strcmp(dent->d_name, "..") == 0)
-                   continue;
-               printf("Selected interface '%s'\n", dent->d_name);
-               ctrl_iface = strdup(dent->d_name);
-               break;
-           }
-           closedir(dir);
-       }
-#endif /* CONFIG_CTRL_IFACE_UNIX */
-#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
-       struct wpa_ctrl *ctrl;
-       int ret;
-
-       free(ctrl_iface);
-       ctrl_iface = NULL;
-
-       ctrl = wpa_ctrl_open(NULL);
-       if (ctrl) {
-           len = sizeof(buf) - 1;
-           ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL);
-           if (ret >= 0) {
-               buf[len] = '\0';
-               pos = strchr(buf, '\n');
-               if (pos)
-                   *pos = '\0';
-               ctrl_iface = strdup(buf);
-           }
-           wpa_ctrl_close(ctrl);
-       }
-#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
-    }
-    
-    if (ctrl_iface == NULL)
-       return -1;
-
-#ifdef CONFIG_CTRL_IFACE_UNIX
-    flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2;
-    cfile = (char *) malloc(flen);
-    if (cfile == NULL)
-       return -1;
-    snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface);
-#else /* CONFIG_CTRL_IFACE_UNIX */
-    flen = strlen(ctrl_iface) + 1;
-    cfile = (char *) malloc(flen);
-    if (cfile == NULL)
-       return -1;
-    snprintf(cfile, flen, "%s", ctrl_iface);
-#endif /* CONFIG_CTRL_IFACE_UNIX */
-
-    if (ctrl_conn) {
-       wpa_ctrl_close(ctrl_conn);
-       ctrl_conn = NULL;
-    }
-
-    if (monitor_conn) {
-       delete msgNotifier;
-       msgNotifier = NULL;
-       wpa_ctrl_detach(monitor_conn);
-       wpa_ctrl_close(monitor_conn);
-       monitor_conn = NULL;
-    }
-
-    printf("Trying to connect to '%s'\n", cfile);
-    ctrl_conn = wpa_ctrl_open(cfile);
-    if (ctrl_conn == NULL) {
-       free(cfile);
-       return -1;
-    }
-    monitor_conn = wpa_ctrl_open(cfile);
-    free(cfile);
-    if (monitor_conn == NULL) {
-       wpa_ctrl_close(ctrl_conn);
-       return -1;
-    }
-    if (wpa_ctrl_attach(monitor_conn)) {
-       printf("Failed to attach to wpa_supplicant\n");
-       wpa_ctrl_close(monitor_conn);
-       monitor_conn = NULL;
-       wpa_ctrl_close(ctrl_conn);
-       ctrl_conn = NULL;
-       return -1;
-    }
-
-#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
-    msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn),
-                                     QSocketNotifier::Read, this);
-    connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs()));
-#endif
-
-    adapterSelect->clear();
-    adapterSelect->insertItem(ctrl_iface);
-    adapterSelect->setCurrentItem(0);
-
-    len = sizeof(buf) - 1;
-    if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >= 0) {
-       buf[len] = '\0';
-       pos = buf;
-       while (*pos) {
-               pos2 = strchr(pos, '\n');
-               if (pos2)
-                       *pos2 = '\0';
-               if (strcmp(pos, ctrl_iface) != 0)
-                       adapterSelect->insertItem(pos);
-               if (pos2)
-                       pos = pos2 + 1;
-               else
-                       break;
-       }
-    }
-
-    return 0;
-}
-
-
-static void wpa_gui_msg_cb(char *msg, size_t)
-{
-    /* This should not happen anymore since two control connections are used. */
-    printf("missed message: %s\n", msg);
-}
-
-
-int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen)
-{
-    int ret;
-    
-    if (ctrl_conn == NULL)
-       return -3;
-    ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen,
-                          wpa_gui_msg_cb);
-    if (ret == -2) {
-       printf("'%s' command timed out.\n", cmd);
-    } else if (ret < 0) {
-       printf("'%s' command failed.\n", cmd);
-    }
-    
-    return ret;
-}
-
-
-void WpaGui::updateStatus()
-{
-    char buf[2048], *start, *end, *pos;
-    size_t len;
-
-    pingsToStatusUpdate = 10;
-
-    len = sizeof(buf) - 1;
-    if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) {
-       textStatus->setText("Could not get status from wpa_supplicant");
-       textAuthentication->clear();
-       textEncryption->clear();
-       textSsid->clear();
-       textBssid->clear();
-       textIpAddress->clear();
-       return;
-    }
-    
-    buf[len] = '\0';
-    
-    bool auth_updated = false, ssid_updated = false;
-    bool bssid_updated = false, ipaddr_updated = false;
-    bool status_updated = false;
-    char *pairwise_cipher = NULL, *group_cipher = NULL;
-    
-    start = buf;
-    while (*start) {
-       bool last = false;
-       end = strchr(start, '\n');
-       if (end == NULL) {
-           last = true;
-           end = start;
-           while (end[0] && end[1])
-               end++;
-       }
-       *end = '\0';
-       
-       pos = strchr(start, '=');
-       if (pos) {
-           *pos++ = '\0';
-           if (strcmp(start, "bssid") == 0) {
-               bssid_updated = true;
-               textBssid->setText(pos);
-           } else if (strcmp(start, "ssid") == 0) {
-               ssid_updated = true;
-               textSsid->setText(pos);
-           } else if (strcmp(start, "ip_address") == 0) {
-               ipaddr_updated = true;
-               textIpAddress->setText(pos);
-           } else if (strcmp(start, "wpa_state") == 0) {
-               status_updated = true;
-               textStatus->setText(pos);
-           } else if (strcmp(start, "key_mgmt") == 0) {
-               auth_updated = true;
-               textAuthentication->setText(pos);
-               /* TODO: could add EAP status to this */
-           } else if (strcmp(start, "pairwise_cipher") == 0) {
-               pairwise_cipher = pos;
-           } else if (strcmp(start, "group_cipher") == 0) {
-               group_cipher = pos;
-           }
-       }
-       
-       if (last)
-           break;
-       start = end + 1;
-    }
-    
-    if (pairwise_cipher || group_cipher) {
-       QString encr;
-       if (pairwise_cipher && group_cipher &&
-           strcmp(pairwise_cipher, group_cipher) != 0) {
-           encr.append(pairwise_cipher);
-           encr.append(" + ");
-           encr.append(group_cipher);
-       } else if (pairwise_cipher) {
-           encr.append(pairwise_cipher);
-       } else {
-           encr.append(group_cipher);
-           encr.append(" [group key only]");
-       }
-       textEncryption->setText(encr);
-    } else
-       textEncryption->clear();
-
-    if (!status_updated)
-       textStatus->clear();
-    if (!auth_updated)
-       textAuthentication->clear();
-    if (!ssid_updated)
-       textSsid->clear();
-    if (!bssid_updated)
-       textBssid->clear();
-    if (!ipaddr_updated)
-       textIpAddress->clear();
-}
-
-
-void WpaGui::updateNetworks()
-{
-    char buf[2048], *start, *end, *id, *ssid, *bssid, *flags;
-    size_t len;
-    int first_active = -1;
-    bool selected = false;
-
-    if (!networkMayHaveChanged)
-       return;
-
-    networkSelect->clear();
-
-    if (ctrl_conn == NULL)
-       return;
-    
-    len = sizeof(buf) - 1;
-    if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
-       return;
-    
-    buf[len] = '\0';
-    start = strchr(buf, '\n');
-    if (start == NULL)
-       return;
-    start++;
-
-    while (*start) {
-       bool last = false;
-       end = strchr(start, '\n');
-       if (end == NULL) {
-           last = true;
-           end = start;
-           while (end[0] && end[1])
-               end++;
-       }
-       *end = '\0';
-       
-       id = start;
-       ssid = strchr(id, '\t');
-       if (ssid == NULL)
-           break;
-       *ssid++ = '\0';
-       bssid = strchr(ssid, '\t');
-       if (bssid == NULL)
-           break;
-       *bssid++ = '\0';
-       flags = strchr(bssid, '\t');
-       if (flags == NULL)
-           break;
-       *flags++ = '\0';
-       
-       QString network(id);
-       network.append(": ");
-       network.append(ssid);
-       networkSelect->insertItem(network);
-       
-       if (strstr(flags, "[CURRENT]")) {
-           networkSelect->setCurrentItem(networkSelect->count() - 1);
-           selected = true;
-       } else if (first_active < 0 && strstr(flags, "[DISABLED]") == NULL)
-           first_active = networkSelect->count() - 1;
-       
-       if (last)
-           break;
-       start = end + 1;
-    }
-
-    if (!selected && first_active >= 0)
-       networkSelect->setCurrentItem(first_active);
-
-    networkMayHaveChanged = false;
-}
-
-
-void WpaGui::helpIndex()
-{
-    printf("helpIndex\n");
-}
-
-
-void WpaGui::helpContents()
-{
-    printf("helpContents\n");
-}
-
-
-void WpaGui::helpAbout()
-{
-    QMessageBox::about(this, "wpa_gui for wpa_supplicant",
-                      "Copyright (c) 2003-2008,\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"
-                      "\n"
-                      "This product includes software developed\n"
-                      "by the OpenSSL Project for use in the\n"
-                      "OpenSSL Toolkit (http://www.openssl.org/)\n");
-}
-
-
-void WpaGui::disconnect()
-{
-    char reply[10];
-    size_t reply_len = sizeof(reply);
-    ctrlRequest("DISCONNECT", reply, &reply_len);
-}
-
-
-void WpaGui::scan()
-{
-    if (scanres) {
-       scanres->close();
-       delete scanres;
-    }
-
-    scanres = new ScanResults();
-    if (scanres == NULL)
-       return;
-    scanres->setWpaGui(this);
-    scanres->show();
-    scanres->exec();
-}
-
-
-void WpaGui::eventHistory()
-{
-    if (eh) {
-       eh->close();
-       delete eh;
-    }
-
-    eh = new EventHistory();
-    if (eh == NULL)
-       return;
-    eh->addEvents(msgs);
-    eh->show();
-    eh->exec();
-}
-
-
-void WpaGui::ping()
-{
-    char buf[10];
-    size_t len;
-    
-#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
-    /*
-     * QSocketNotifier cannot be used with Windows named pipes, so use a timer
-     * to check for received messages for now. This could be optimized be doing
-     * something specific to named pipes or Windows events, but it is not clear
-     * what would be the best way of doing that in Qt.
-     */
-    receiveMsgs();
-#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
-
-    if (scanres && !scanres->isVisible()) {
-       delete scanres;
-       scanres = NULL;
-    }
-    
-    if (eh && !eh->isVisible()) {
-       delete eh;
-       eh = NULL;
-    }
-    
-    if (udr && !udr->isVisible()) {
-       delete udr;
-       udr = NULL;
-    }
-    
-    len = sizeof(buf) - 1;
-    if (ctrlRequest("PING", buf, &len) < 0) {
-       printf("PING failed - trying to reconnect\n");
-       if (openCtrlConnection(ctrl_iface) >= 0) {
-           printf("Reconnected successfully\n");
-           pingsToStatusUpdate = 0;
-       }
-    }
-
-    pingsToStatusUpdate--;
-    if (pingsToStatusUpdate <= 0) {
-       updateStatus();
-       updateNetworks();
-    }
-}
-
-
-static int str_match(const char *a, const char *b)
-{
-    return strncmp(a, b, strlen(b)) == 0;
-}
-
-
-void WpaGui::processMsg(char *msg)
-{
-    char *pos = msg, *pos2;
-    int priority = 2;
-    
-    if (*pos == '<') {
-       /* skip priority */
-       pos++;
-       priority = atoi(pos);
-       pos = strchr(pos, '>');
-       if (pos)
-           pos++;
-       else
-           pos = msg;
-    }
-
-    WpaMsg wm(pos, priority);
-    if (eh)
-       eh->addEvent(wm);
-    msgs.append(wm);
-    while (msgs.count() > 100)
-       msgs.pop_front();
-    
-    /* Update last message with truncated version of the event */
-    if (strncmp(pos, "CTRL-", 5) == 0) {
-       pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' ');
-       if (pos2)
-           pos2++;
-       else
-           pos2 = pos;
-    } else
-       pos2 = pos;
-    QString lastmsg = pos2;
-    lastmsg.truncate(40);
-    textLastMessage->setText(lastmsg);
-    
-    pingsToStatusUpdate = 0;
-    networkMayHaveChanged = true;
-    
-    if (str_match(pos, WPA_CTRL_REQ))
-       processCtrlReq(pos + strlen(WPA_CTRL_REQ));
-}
-
-
-void WpaGui::processCtrlReq(const char *req)
-{
-    if (udr) {
-       udr->close();
-       delete udr;
-    }
-    udr = new UserDataRequest();
-    if (udr == NULL)
-       return;
-    if (udr->setParams(this, req) < 0) {
-       delete udr;
-       udr = NULL;
-       return;
-    }
-    udr->show();
-    udr->exec();
-}
-
-
-void WpaGui::receiveMsgs()
-{
-    char buf[256];
-    size_t len;
-    
-    while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) {
-       len = sizeof(buf) - 1;
-       if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) {
-           buf[len] = '\0';
-           processMsg(buf);
-       }
-    }
-}
-
-
-void WpaGui::connectB()
-{
-    char reply[10];
-    size_t reply_len = sizeof(reply);
-    ctrlRequest("REASSOCIATE", reply, &reply_len);
-}
-
-
-void WpaGui::selectNetwork( const QString &sel )
-{
-    QString cmd(sel);
-    char reply[10];
-    size_t reply_len = sizeof(reply);
-    
-    int pos = cmd.find(':');
-    if (pos < 0) {
-       printf("Invalid selectNetwork '%s'\n", cmd.ascii());
-       return;
-    }
-    cmd.truncate(pos);
-    cmd.prepend("SELECT_NETWORK ");
-    ctrlRequest(cmd.ascii(), reply, &reply_len);
-}
-
-
-void WpaGui::editNetwork()
-{
-    QString sel(networkSelect->currentText());
-    int pos = sel.find(':');
-    if (pos < 0) {
-       printf("Invalid selectNetwork '%s'\n", sel.ascii());
-       return;
-    }
-    sel.truncate(pos);
-    
-    NetworkConfig *nc = new NetworkConfig();
-    if (nc == NULL)
-       return;
-    nc->setWpaGui(this);
-    
-    nc->paramsFromConfig(sel.toInt());
-    nc->show();
-    nc->exec();
-}
-
-
-void WpaGui::triggerUpdate()
-{
-    updateStatus();
-    networkMayHaveChanged = true;
-    updateNetworks();
-}
-
-
-void WpaGui::addNetwork()
-{
-    NetworkConfig *nc = new NetworkConfig();
-    if (nc == NULL)
-       return;
-    nc->setWpaGui(this);
-    nc->newNetwork();
-    nc->show();
-    nc->exec();
-}
-
-
-void WpaGui::selectAdapter( const QString & sel )
-{
-    if (openCtrlConnection(sel.ascii()) < 0)
-       printf("Failed to open control connection to wpa_supplicant.\n");
-    updateStatus();
-    updateNetworks();
-}
diff --git a/wpa_supplicant/wpa_gui/wpamsg.h b/wpa_supplicant/wpa_gui/wpamsg.h
deleted file mode 100644 (file)
index f3fce06..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef WPAMSG_H
-#define WPAMSG_H
-
-class WpaMsg;
-
-#if QT_VERSION >= 0x040000
-#include <QDateTime>
-#include <QLinkedList>
-typedef QLinkedList<WpaMsg> WpaMsgList;
-#else
-#include <qdatetime.h>
-typedef QValueList<WpaMsg> WpaMsgList;
-#endif
-
-class WpaMsg {
-public:
-    WpaMsg() {}
-    WpaMsg(const QString &_msg, int _priority = 2)
-       : msg(_msg), priority(_priority)
-    {
-       timestamp = QDateTime::currentDateTime();
-    }
-    
-    QString getMsg() const { return msg; }
-    int getPriority() const { return priority; }
-    QDateTime getTimestamp() const { return timestamp; }
-    
-private:
-    QString msg;
-    int priority;
-    QDateTime timestamp;
-};
-
-#endif /* WPAMSG_H */
index d2a991b..c8854da 100644 (file)
@@ -825,7 +825,7 @@ static void wpa_priv_send_ft_response(struct wpa_priv_interface *iface,
 }
 
 
-void wpa_supplicant_event(void *ctx, wpa_event_type event,
+void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                          union wpa_event_data *data)
 {
        struct wpa_priv_interface *iface = ctx;
@@ -915,7 +915,7 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
 }
 
 
-static void wpa_priv_terminate(int sig, void *eloop_ctx, void *signal_ctx)
+static void wpa_priv_terminate(int sig, void *signal_ctx)
 {
        wpa_printf(MSG_DEBUG, "wpa_priv termination requested");
        eloop_terminate();
index af3d773..d04d32b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * 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
@@ -19,6 +19,8 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/random.h"
+#include "crypto/sha1.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "eap_peer/eap.h"
 #include "eap_server/eap_methods.h"
 #include "rsn_supp/preauth.h"
 #include "rsn_supp/pmksa_cache.h"
 #include "common/wpa_ctrl.h"
-#include "mlme.h"
 #include "common/ieee802_11_defs.h"
+#include "p2p/p2p.h"
 #include "blacklist.h"
 #include "wpas_glue.h"
 #include "wps_supplicant.h"
 #include "ibss_rsn.h"
 #include "sme.h"
+#include "gas_query.h"
 #include "ap.h"
+#include "p2p_supplicant.h"
 #include "notify.h"
 #include "bgscan.h"
 #include "bss.h"
 #include "scan.h"
+#include "offchannel.h"
 
 const char *wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2011, 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"
@@ -130,9 +135,8 @@ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
                        continue;
 
                set = 1;
-               wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
-                               (u8 *) "\xff\xff\xff\xff\xff\xff",
-                               i, i == ssid->wep_tx_keyidx, (u8 *) "", 0,
+               wpa_drv_set_key(wpa_s, WPA_ALG_WEP, NULL,
+                               i, i == ssid->wep_tx_keyidx, NULL, 0,
                                ssid->wep_key[i], ssid->wep_key_len[i]);
        }
 
@@ -152,13 +156,14 @@ static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
         * sending unicast and multicast packets. */
 
        if (ssid->mode != WPAS_MODE_IBSS) {
-               wpa_printf(MSG_INFO, "WPA: Invalid mode %d (not IBSS/ad-hoc) "
-                          "for WPA-None", ssid->mode);
+               wpa_msg(wpa_s, MSG_INFO, "WPA: Invalid mode %d (not "
+                       "IBSS/ad-hoc) for WPA-None", ssid->mode);
                return -1;
        }
 
        if (!ssid->psk_set) {
-               wpa_printf(MSG_INFO, "WPA: No PSK configured for WPA-None");
+               wpa_msg(wpa_s, MSG_INFO, "WPA: No PSK configured for "
+                       "WPA-None");
                return -1;
        }
 
@@ -176,115 +181,124 @@ static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
                alg = WPA_ALG_TKIP;
                break;
        default:
-               wpa_printf(MSG_INFO, "WPA: Invalid group cipher %d for "
-                          "WPA-None", wpa_s->group_cipher);
+               wpa_msg(wpa_s, MSG_INFO, "WPA: Invalid group cipher %d for "
+                       "WPA-None", wpa_s->group_cipher);
                return -1;
        }
 
        /* TODO: should actually remember the previously used seq#, both for TX
         * and RX from each STA.. */
 
-       return wpa_drv_set_key(wpa_s, alg, (u8 *) "\xff\xff\xff\xff\xff\xff",
-                              0, 1, seq, 6, key, keylen);
+       return wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
 }
 
 /*
- * Oct, 26th. 2011. TIZEN
- * Add a function to check current networks is set for wps in this file
+ * 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.
  */
-#ifdef CONFIG_WPS
-static int wpas_wps_in_use_wpasupplicant(struct wpa_config *conf)
-{
-       struct wpa_ssid *ssid;
-       int wps = 0;
 
-       for (ssid = conf->ssid; ssid; ssid = ssid->next) {
-               if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
-                       continue;
+/*
+ * 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;
 
-               wps = 1;
+       if (wpa_s == NULL)
+               return -1;
+       if (wpa_s->conf == NULL)
+               return -1;
+       if (wpa_s->conf->ssid == NULL)
+               return -1;
 
-               if (!ssid->eap.phase1)
-                       continue;
+       start = wpa_s->conf->ssid;
 
-               if (os_strstr(ssid->eap.phase1, "pbc=1"))
-                       return 2;
+       while (start) {
+               if (start->scan_ssid != 0) {
+                       ret = 0;
+                       break;
+               }
+               start = start->next;
        }
 
-       return wps;
+       return ret;
+
 }
-#endif /* CONFIG_WPS */
+
+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)
 {
-       /*
-        * Oct, 26th. 2011. TIZEN
-        * A wps variable is added for check enabled networks is set for WPS
-        */
-       int wps = 0;
        struct wpa_supplicant *wpa_s = eloop_ctx;
-       /*
-        * Oct, 26th. 2011. TIZEN
-        * A wps variable is added for check enabled networks is set for WPS
-        */
-       struct wpa_ssid *start = wpa_s->conf->ssid;
        const u8 *bssid = wpa_s->bssid;
        if (is_zero_ether_addr(bssid))
                bssid = wpa_s->pending_bssid;
        wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
                MAC2STR(bssid));
        wpa_blacklist_add(wpa_s, bssid);
-       wpa_sm_notify_disassoc(wpa_s->wpa);
-       wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 
+#if defined TIZEN_EXT
        /*
-        * Oct, 26th. 2011. TIZEN
-        * WPS check routine is added due to our changes's side effect
+        * 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.
         */
-       wps = wpas_wps_in_use_wpasupplicant(wpa_s->conf);
 
-       if(wps == 0)
-       {       
-               /*
-                * September, 29th 2011. TIZEN
-                *
-                * Change reassociate to 0 and add disconnect 1
-                * thus
-                */
-                wpa_msg(wpa_s,MSG_INFO, "wpa_s->reassociate %d, wpa_s->associate_num %d",wpa_s->reassociate ,wpa_s->associate_num);
-               if(wpa_s->disconnected == 0)
-               {
-                       if(wpa_s->associate_num < 2)
-                       {
-                               if(wpa_s->associate_num == 1)
-                               {
-                                       while(start)
-                                       {
-                                               start->scan_ssid = 0;
-                                               start = start->next;
-                                       }
-                               }
-                               wpa_s->reassociate = 1;
-                               wpa_s->associate_num++;
-                               wpa_supplicant_req_scan(wpa_s, 0, 0);
-                               return;
-                       }
-               }
-               
-               wpa_s->reassociate = 0;
-               wpa_s->disconnected = 1;
-               
-               while(start)
-               {
-                       start->scan_ssid = 0;
-                       start = start->next;
+       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_printf(MSG_DEBUG,"===============================");
-       wpa_printf(MSG_DEBUG,"Scan request after timeout");
-       wpa_printf(MSG_DEBUG,"===============================");
-       wpa_supplicant_req_scan(wpa_s, 0, 0);
+       wpa_s->reassociate = 1;
+
+       /*
+        * If we timed out, the AP or the local radio may be busy.
+        * So, wait a second until scanning again.
+        */
+       wpa_supplicant_req_scan(wpa_s, 1, 0);
 }
 
 
@@ -304,7 +318,7 @@ void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
            (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
                return;
 
-       wpa_msg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
+       wpa_dbg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
                "%d usec", sec, usec);
        eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
        eloop_register_timeout(sec, usec, wpa_supplicant_timeout, wpa_s, NULL);
@@ -321,7 +335,7 @@ void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
  */
 void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
 {
-       wpa_msg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout");
+       wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout");
        eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
        wpa_blacklist_del(wpa_s, wpa_s->bssid);
 }
@@ -444,6 +458,22 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
 }
 
 
+static void free_hw_features(struct wpa_supplicant *wpa_s)
+{
+       int i;
+       if (wpa_s->hw.modes == NULL)
+               return;
+
+       for (i = 0; i < wpa_s->hw.num_modes; i++) {
+               os_free(wpa_s->hw.modes[i].channels);
+               os_free(wpa_s->hw.modes[i].rates);
+       }
+
+       os_free(wpa_s->hw.modes);
+       wpa_s->hw.modes = NULL;
+}
+
+
 static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 {
        bgscan_deinit(wpa_s);
@@ -479,6 +509,10 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 
        rsn_preauth_deinit(wpa_s->wpa);
 
+#ifdef CONFIG_TDLS
+       wpa_tdls_deinit(wpa_s->wpa);
+#endif /* CONFIG_TDLS */
+
        pmksa_candidate_free(wpa_s->wpa);
        wpa_sm_deinit(wpa_s->wpa);
        wpa_s->wpa = NULL;
@@ -488,8 +522,11 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 
        wpa_supplicant_cancel_scan(wpa_s);
        wpa_supplicant_cancel_auth_timeout(wpa_s);
-
-       ieee80211_sta_deinit(wpa_s);
+       eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
+#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
+       eloop_cancel_timeout(wpa_supplicant_delayed_mic_error_report,
+                            wpa_s, NULL);
+#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
 
        wpas_wps_deinit(wpa_s);
 
@@ -501,15 +538,29 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        wpa_s->ibss_rsn = NULL;
 #endif /* CONFIG_IBSS_RSN */
 
-#ifdef CONFIG_SME
-       os_free(wpa_s->sme.ft_ies);
-       wpa_s->sme.ft_ies = NULL;
-       wpa_s->sme.ft_ies_len = 0;
-#endif /* CONFIG_SME */
+       sme_deinit(wpa_s);
 
 #ifdef CONFIG_AP
        wpa_supplicant_ap_deinit(wpa_s);
 #endif /* CONFIG_AP */
+
+#ifdef CONFIG_P2P
+       wpas_p2p_deinit(wpa_s);
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_OFFCHANNEL
+       offchannel_deinit(wpa_s);
+#endif /* CONFIG_OFFCHANNEL */
+
+       wpa_supplicant_cancel_sched_scan(wpa_s);
+
+       os_free(wpa_s->next_scan_freqs);
+       wpa_s->next_scan_freqs = NULL;
+
+       gas_query_deinit(wpa_s->gas);
+       wpa_s->gas = NULL;
+
+       free_hw_features(wpa_s);
 }
 
 
@@ -523,8 +574,6 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
  */
 void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
 {
-       u8 *bcast = (u8 *) "\xff\xff\xff\xff\xff\xff";
-
        if (wpa_s->keys_cleared) {
                /* Some drivers (e.g., ndiswrapper & NDIS drivers) seem to have
                 * timing issues with keys being cleared just before new keys
@@ -533,19 +582,19 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
                 * client not receiving the first encrypted packets correctly.
                 * Skipping some of the extra key clearing steps seems to help
                 * in completing group key handshake more reliably. */
-               wpa_printf(MSG_DEBUG, "No keys have been configured - "
-                          "skip key clearing");
+               wpa_dbg(wpa_s, MSG_DEBUG, "No keys have been configured - "
+                       "skip key clearing");
                return;
        }
 
        /* MLME-DELETEKEYS.request */
-       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 0, 0, NULL, 0, NULL, 0);
-       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 1, 0, NULL, 0, NULL, 0);
-       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 2, 0, NULL, 0, NULL, 0);
-       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 3, 0, NULL, 0, NULL, 0);
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
 #ifdef CONFIG_IEEE80211W
-       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 4, 0, NULL, 0, NULL, 0);
-       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 5, 0, NULL, 0, NULL, 0);
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
 #endif /* CONFIG_IEEE80211W */
        if (addr) {
                wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
@@ -572,6 +621,8 @@ const char * wpa_supplicant_state_txt(enum wpa_states state)
                return "DISCONNECTED";
        case WPA_INACTIVE:
                return "INACTIVE";
+       case WPA_INTERFACE_DISABLED:
+               return "INTERFACE_DISABLED";
        case WPA_SCANNING:
                return "SCANNING";
        case WPA_AUTHENTICATING:
@@ -592,6 +643,43 @@ const char * wpa_supplicant_state_txt(enum wpa_states state)
 }
 
 
+#ifdef CONFIG_BGSCAN
+
+static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
+{
+       if (wpas_driver_bss_selection(wpa_s))
+               return;
+       if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
+               return;
+
+       bgscan_deinit(wpa_s);
+       if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan) {
+               if (bgscan_init(wpa_s, wpa_s->current_ssid)) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
+                               "bgscan");
+                       /*
+                        * Live without bgscan; it is only used as a roaming
+                        * optimization, so the initial connection is not
+                        * affected.
+                        */
+               } else
+                       wpa_s->bgscan_ssid = wpa_s->current_ssid;
+       } else
+               wpa_s->bgscan_ssid = NULL;
+}
+
+
+static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->bgscan_ssid != NULL) {
+               bgscan_deinit(wpa_s);
+               wpa_s->bgscan_ssid = NULL;
+       }
+}
+
+#endif /* CONFIG_BGSCAN */
+
+
 /**
  * wpa_supplicant_set_state - Set current connection state
  * @wpa_s: Pointer to wpa_supplicant data
@@ -605,9 +693,9 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
 {
        enum wpa_states old_state = wpa_s->wpa_state;
 
-       wpa_printf(MSG_DEBUG, "State: %s -> %s",
-                  wpa_supplicant_state_txt(wpa_s->wpa_state),
-                  wpa_supplicant_state_txt(state));
+       wpa_dbg(wpa_s, MSG_DEBUG, "State: %s -> %s",
+               wpa_supplicant_state_txt(wpa_s->wpa_state),
+               wpa_supplicant_state_txt(state));
 
        if (state != WPA_SCANNING)
                wpa_supplicant_notify_scanning(wpa_s, 0);
@@ -625,29 +713,52 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                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);
+#endif /* IEEE8021X_EAPOL */
                wpa_s->after_wps = 0;
+#ifdef CONFIG_P2P
+               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)
-               {
+               if (wpa_s->conf->ssid != NULL) {
                        struct wpa_ssid *start = wpa_s->conf->ssid;
-                       while(start)
-                       {
+                       while (start) {
                                start->scan_ssid = 0;
                                start = start->next;
                        }
                }
+#endif
+
        } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
                   state == WPA_ASSOCIATED) {
                wpa_s->new_connection = 1;
                wpa_drv_set_operstate(wpa_s, 0);
+#ifndef IEEE8021X_EAPOL
+               wpa_drv_set_supp_port(wpa_s, 0);
+#endif /* IEEE8021X_EAPOL */
        }
        wpa_s->wpa_state = state;
 
-       if (wpa_s->wpa_state != old_state)
+#ifdef CONFIG_BGSCAN
+       if (state == WPA_COMPLETED)
+               wpa_supplicant_start_bgscan(wpa_s);
+       else
+               wpa_supplicant_stop_bgscan(wpa_s);
+#endif /* CONFIG_BGSCAN */
+
+       if (wpa_s->wpa_state != old_state) {
                wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
+
+               if (wpa_s->wpa_state == WPA_COMPLETED ||
+                   old_state == WPA_COMPLETED)
+                       wpas_notify_auth_changed(wpa_s);
+       }
 }
 
 
@@ -680,7 +791,7 @@ static void wpa_supplicant_terminate(int sig, void *signal_ctx)
 }
 
 
-static void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
+void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
 {
        enum wpa_states old_state = wpa_s->wpa_state;
 
@@ -688,7 +799,8 @@ static void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
        wpa_s->group_cipher = 0;
        wpa_s->mgmt_group_cipher = 0;
        wpa_s->key_mgmt = 0;
-       wpa_s->wpa_state = WPA_DISCONNECTED;
+       if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
+               wpa_s->wpa_state = WPA_DISCONNECTED;
 
        if (wpa_s->wpa_state != old_state)
                wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
@@ -709,7 +821,6 @@ static void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
 int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
 {
        struct wpa_config *conf;
-       struct wpa_ssid *old_ssid;
        int reconf_ctrl;
        int old_ap_scan;
 
@@ -721,6 +832,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
                        "file '%s' - exiting", wpa_s->confname);
                return -1;
        }
+       conf->changed_parameters = (unsigned int) -1;
 
        reconf_ctrl = !!conf->ctrl_interface != !!wpa_s->conf->ctrl_interface
                || (conf->ctrl_interface && wpa_s->conf->ctrl_interface &&
@@ -733,10 +845,10 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
        }
 
        eapol_sm_invalidate_cached_session(wpa_s->eapol);
-       old_ssid = wpa_s->current_ssid;
-       wpa_s->current_ssid = NULL;
-       if (old_ssid != wpa_s->current_ssid)
-               wpas_notify_network_changed(wpa_s);
+       if (wpa_s->current_ssid) {
+               wpa_supplicant_deauthenticate(wpa_s,
+                                             WLAN_REASON_DEAUTH_LEAVING);
+       }
 
        /*
         * TODO: should notify EAPOL SM about changes in opensc_engine_path,
@@ -751,6 +863,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
        }
        eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
        wpa_sm_set_config(wpa_s->wpa, NULL);
+       wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
        wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
        rsn_preauth_deinit(wpa_s->wpa);
 
@@ -763,10 +876,14 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
        if (reconf_ctrl)
                wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
 
+       wpa_supplicant_update_config(wpa_s);
+
        wpa_supplicant_clear_status(wpa_s);
-       wpa_s->reassociate = 1;
-       wpa_supplicant_req_scan(wpa_s, 0, 0);
-       wpa_msg(wpa_s, MSG_DEBUG, "Reconfiguration completed");
+       if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
+               wpa_s->reassociate = 1;
+               wpa_supplicant_req_scan(wpa_s, 0, 0);
+       }
+       wpa_dbg(wpa_s, MSG_DEBUG, "Reconfiguration completed");
        return 0;
 }
 
@@ -775,8 +892,9 @@ static void wpa_supplicant_reconfig(int sig, void *signal_ctx)
 {
        struct wpa_global *global = signal_ctx;
        struct wpa_supplicant *wpa_s;
-       wpa_printf(MSG_DEBUG, "Signal %d received - reconfiguring", sig);
        for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "Signal %d received - reconfiguring",
+                       sig);
                if (wpa_supplicant_reload_configuration(wpa_s) < 0) {
                        wpa_supplicant_terminate_proc(global);
                }
@@ -843,8 +961,8 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
-       wpa_printf(MSG_DEBUG, "WPA: Using WPA IE from AssocReq to set cipher "
-                  "suites");
+       wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Using WPA IE from AssocReq to set "
+               "cipher suites");
        if (!(ie->group_cipher & ssid->group_cipher)) {
                wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled group "
                        "cipher 0x%x (mask 0x%x) - reject",
@@ -911,14 +1029,14 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
            (ie.group_cipher & ssid->group_cipher) &&
            (ie.pairwise_cipher & ssid->pairwise_cipher) &&
            (ie.key_mgmt & ssid->key_mgmt)) {
-               wpa_msg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
+               wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
                proto = WPA_PROTO_RSN;
        } else if (bss_wpa && (ssid->proto & WPA_PROTO_WPA) &&
                   wpa_parse_wpa_ie(bss_wpa, 2 +bss_wpa[1], &ie) == 0 &&
                   (ie.group_cipher & ssid->group_cipher) &&
                   (ie.pairwise_cipher & ssid->pairwise_cipher) &&
                   (ie.key_mgmt & ssid->key_mgmt)) {
-               wpa_msg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
                proto = WPA_PROTO_WPA;
        } else if (bss) {
                wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
@@ -938,22 +1056,23 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                                ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION ?
                                WPA_CIPHER_AES_128_CMAC : 0;
 #endif /* CONFIG_IEEE80211W */
-                       wpa_printf(MSG_DEBUG, "WPA: Set cipher suites based "
-                                  "on configuration");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Set cipher suites "
+                               "based on configuration");
                } else
                        proto = ie.proto;
        }
 
-       wpa_printf(MSG_DEBUG, "WPA: Selected cipher suites: group %d "
-                  "pairwise %d key_mgmt %d proto %d",
-                  ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
+       wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected cipher suites: group %d "
+               "pairwise %d key_mgmt %d proto %d",
+               ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
 #ifdef CONFIG_IEEE80211W
        if (ssid->ieee80211w) {
-               wpa_printf(MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
-                          ie.mgmt_group_cipher);
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
+                       ie.mgmt_group_cipher);
        }
 #endif /* CONFIG_IEEE80211W */
 
+       wpa_s->wpa_proto = proto;
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED,
                         !!(ssid->proto & WPA_PROTO_RSN));
@@ -969,34 +1088,35 @@ 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_msg(wpa_s, MSG_DEBUG, "WPA: using GTK 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_msg(wpa_s, MSG_DEBUG, "WPA: using GTK 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_msg(wpa_s, MSG_DEBUG, "WPA: using GTK 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_msg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP40");
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP40");
        } else {
-               wpa_printf(MSG_WARNING, "WPA: Failed to select group cipher.");
+               wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select group "
+                       "cipher");
                return -1;
        }
 
        sel = ie.pairwise_cipher & ssid->pairwise_cipher;
        if (sel & WPA_CIPHER_CCMP) {
                wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
-               wpa_msg(wpa_s, MSG_DEBUG, "WPA: using PTK 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_msg(wpa_s, MSG_DEBUG, "WPA: using PTK 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_msg(wpa_s, MSG_DEBUG, "WPA: using PTK NONE");
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK NONE");
        } else {
-               wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise "
-                          "cipher.");
+               wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select pairwise "
+                       "cipher");
                return -1;
        }
 
@@ -1005,33 +1125,33 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 #ifdef CONFIG_IEEE80211R
        } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
-               wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
        } else if (sel & WPA_KEY_MGMT_FT_PSK) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
-               wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
 #endif /* CONFIG_IEEE80211R */
 #ifdef CONFIG_IEEE80211W
        } else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
-               wpa_msg(wpa_s, MSG_DEBUG,
+               wpa_dbg(wpa_s, MSG_DEBUG,
                        "WPA: using KEY_MGMT 802.1X with SHA256");
        } else if (sel & WPA_KEY_MGMT_PSK_SHA256) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
-               wpa_msg(wpa_s, MSG_DEBUG,
+               wpa_dbg(wpa_s, MSG_DEBUG,
                        "WPA: using KEY_MGMT PSK with SHA256");
 #endif /* CONFIG_IEEE80211W */
        } else if (sel & WPA_KEY_MGMT_IEEE8021X) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
-               wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
        } else if (sel & WPA_KEY_MGMT_PSK) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
-               wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-PSK");
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-PSK");
        } else if (sel & WPA_KEY_MGMT_WPA_NONE) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_WPA_NONE;
-               wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-NONE");
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-NONE");
        } else {
-               wpa_printf(MSG_WARNING, "WPA: Failed to select authenticated "
-                          "key management type.");
+               wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select "
+                       "authenticated key management type");
                return -1;
        }
 
@@ -1047,11 +1167,11 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                sel = 0;
        if (sel & WPA_CIPHER_AES_128_CMAC) {
                wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
-               wpa_msg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
                        "AES-128-CMAC");
        } else {
                wpa_s->mgmt_group_cipher = 0;
-               wpa_msg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
        }
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
                         wpa_s->mgmt_group_cipher);
@@ -1059,14 +1179,24 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_IEEE80211W */
 
        if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
-               wpa_printf(MSG_WARNING, "WPA: Failed to generate WPA IE.");
+               wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
                return -1;
        }
 
-       if (ssid->key_mgmt &
-           (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_PSK_SHA256))
+       if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
                wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN);
-       else
+#ifndef CONFIG_NO_PBKDF2
+               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);
+                       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 */
+       } else
                wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
 
        return 0;
@@ -1084,7 +1214,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                              struct wpa_bss *bss, struct wpa_ssid *ssid)
 {
-       u8 wpa_ie[80];
+       u8 wpa_ie[200];
        size_t wpa_ie_len;
        int use_crypt, ret, i, bssid_changed;
        int algs = WPA_AUTH_ALG_OPEN;
@@ -1095,30 +1225,43 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        int assoc_failed = 0;
        struct wpa_ssid *old_ssid;
 
-       if (ssid->mode == WPAS_MODE_AP) {
+#ifdef CONFIG_IBSS_RSN
+       ibss_rsn_deinit(wpa_s->ibss_rsn);
+       wpa_s->ibss_rsn = NULL;
+#endif /* CONFIG_IBSS_RSN */
+
+       if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO ||
+           ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
 #ifdef CONFIG_AP
                if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP)) {
-                       wpa_printf(MSG_INFO, "Driver does not support AP "
-                                  "mode");
+                       wpa_msg(wpa_s, MSG_INFO, "Driver does not support AP "
+                               "mode");
                        return;
                }
                wpa_supplicant_create_ap(wpa_s, ssid);
                wpa_s->current_bss = bss;
 #else /* CONFIG_AP */
-               wpa_printf(MSG_ERROR, "AP mode support not included in the "
-                          "build");
+               wpa_msg(wpa_s, MSG_ERROR, "AP mode support not included in "
+                       "the build");
 #endif /* CONFIG_AP */
                return;
        }
 
+#ifdef CONFIG_TDLS
+       if (bss)
+               wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1),
+                               bss->ie_len);
+#endif /* CONFIG_TDLS */
+
        if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
            ssid->mode == IEEE80211_MODE_INFRA) {
                sme_authenticate(wpa_s, bss, ssid);
                return;
        }
 
+       os_memset(&params, 0, sizeof(params));
        wpa_s->reassociate = 0;
-       if (bss) {
+       if (bss && !wpas_driver_bss_selection(wpa_s)) {
 #ifdef CONFIG_IEEE80211R
                const u8 *ie, *md = NULL;
 #endif /* CONFIG_IEEE80211R */
@@ -1156,6 +1299,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                        wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
                os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
        }
+       wpa_supplicant_cancel_sched_scan(wpa_s);
        wpa_supplicant_cancel_scan(wpa_s);
 
        /* Starting new association, so clear the possibly used WPA IE from the
@@ -1172,20 +1316,16 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                }
        }
 #endif /* IEEE8021X_EAPOL */
-       wpa_printf(MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
+       wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
        if (ssid->auth_alg) {
                algs = ssid->auth_alg;
-               wpa_printf(MSG_DEBUG, "Overriding auth_alg selection: 0x%x",
-                          algs);
+               wpa_dbg(wpa_s, MSG_DEBUG, "Overriding auth_alg selection: "
+                       "0x%x", algs);
        }
 
        if (bss && (wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
                    wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
-           (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
-                              WPA_KEY_MGMT_FT_IEEE8021X |
-                              WPA_KEY_MGMT_FT_PSK |
-                              WPA_KEY_MGMT_IEEE8021X_SHA256 |
-                              WPA_KEY_MGMT_PSK_SHA256))) {
+           wpa_key_mgmt_wpa(ssid->key_mgmt)) {
                int try_opportunistic;
                try_opportunistic = ssid->proactive_key_caching &&
                        (ssid->proto & WPA_PROTO_RSN);
@@ -1196,21 +1336,17 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                wpa_ie_len = sizeof(wpa_ie);
                if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
                                              wpa_ie, &wpa_ie_len)) {
-                       wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key "
-                                  "management and encryption suites");
+                       wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
+                               "key management and encryption suites");
                        return;
                }
-       } else if (ssid->key_mgmt &
-                  (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
-                   WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK |
-                   WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 |
-                   WPA_KEY_MGMT_IEEE8021X_SHA256)) {
+       } else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
                wpa_ie_len = sizeof(wpa_ie);
                if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
                                              wpa_ie, &wpa_ie_len)) {
-                       wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key "
-                                  "management and encryption suites (no scan "
-                                  "results)");
+                       wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
+                               "key management and encryption suites (no "
+                               "scan results)");
                        return;
                }
 #ifdef CONFIG_WPS
@@ -1224,12 +1360,64 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                        wpa_ie_len = 0;
                wpabuf_free(wps_ie);
                wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+               if (!bss || (bss->caps & IEEE80211_CAP_PRIVACY))
+                       params.wps = WPS_MODE_PRIVACY;
+               else
+                       params.wps = WPS_MODE_OPEN;
+               wpa_s->wpa_proto = 0;
 #endif /* CONFIG_WPS */
        } else {
                wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
                wpa_ie_len = 0;
+               wpa_s->wpa_proto = 0;
+       }
+
+#ifdef CONFIG_P2P
+       if (wpa_s->global->p2p) {
+               u8 *pos;
+               size_t len;
+               int res;
+               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);
+               if (res >= 0)
+                       wpa_ie_len += res;
        }
 
+       wpa_s->cross_connect_disallowed = 0;
+       if (bss) {
+               struct wpabuf *p2p;
+               p2p = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+               if (p2p) {
+                       wpa_s->cross_connect_disallowed =
+                               p2p_get_cross_connect_disallowed(p2p);
+                       wpabuf_free(p2p);
+                       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: WLAN AP %s cross "
+                               "connection",
+                               wpa_s->cross_connect_disallowed ?
+                               "disallows" : "allows");
+               }
+       }
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_INTERWORKING
+       if (wpa_s->conf->interworking) {
+               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 */
+       }
+#endif /* CONFIG_INTERWORKING */
+
        wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
        use_crypt = 1;
        cipher_pairwise = cipher_suite2driver(wpa_s->pairwise_cipher);
@@ -1268,12 +1456,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        }
 
        wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
-       os_memset(&params, 0, sizeof(params));
        if (bss) {
-               params.bssid = bss->bssid;
                params.ssid = bss->ssid;
                params.ssid_len = bss->ssid_len;
-               params.freq = bss->freq;
+               if (!wpas_driver_bss_selection(wpa_s)) {
+                       params.bssid = bss->bssid;
+                       params.freq = bss->freq;
+               }
        } else {
                params.ssid = ssid->ssid;
                params.ssid_len = ssid->ssid_len;
@@ -1286,6 +1475,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        params.pairwise_suite = cipher_pairwise;
        params.group_suite = cipher_group;
        params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
+       params.wpa_proto = wpa_s->wpa_proto;
        params.auth_alg = algs;
        params.mode = ssid->mode;
        for (i = 0; i < NUM_WEP_KEYS; i++) {
@@ -1313,21 +1503,35 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 &&
                    ie.capabilities &
                    (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
-                       wpa_printf(MSG_DEBUG, "WPA: Selected AP supports MFP: "
-                                  "require MFP");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected AP supports "
+                               "MFP: require MFP");
                        params.mgmt_frame_protection =
                                MGMT_FRAME_PROTECTION_REQUIRED;
                }
        }
 #endif /* CONFIG_IEEE80211W */
 
-       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-               ret = ieee80211_sta_associate(wpa_s, &params);
+       params.p2p = ssid->p2p_group;
+
+       if (wpa_s->parent->set_sta_uapsd)
+               params.uapsd = wpa_s->parent->sta_uapsd;
        else
-               ret = wpa_drv_associate(wpa_s, &params);
+               params.uapsd = -1;
+
+       ret = wpa_drv_associate(wpa_s, &params);
        if (ret < 0) {
                wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
                        "failed");
+               if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SANE_ERROR_CODES) {
+                       /*
+                        * The driver is known to mean what is saying, so we
+                        * can stop right here; the association will not
+                        * succeed.
+                        */
+                       wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+                       os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+                       return;
+               }
                /* try to continue anyway; new association will be tried again
                 * after timeout */
                assoc_failed = 1;
@@ -1345,7 +1549,6 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        } else if (ssid->mode == WPAS_MODE_IBSS &&
                   wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
                   wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
-               ibss_rsn_set_psk(wpa_s->ibss_rsn, ssid->psk);
                /*
                 * RSN IBSS authentication is per-STA and we can disable the
                 * per-BSSID authentication.
@@ -1389,6 +1592,24 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 }
 
 
+static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
+                                           const u8 *addr)
+{
+       struct wpa_ssid *old_ssid;
+
+       wpa_clear_keys(wpa_s, addr);
+       wpa_supplicant_mark_disassoc(wpa_s);
+       old_ssid = wpa_s->current_ssid;
+       wpa_s->current_ssid = NULL;
+       wpa_s->current_bss = NULL;
+       wpa_sm_set_config(wpa_s->wpa, NULL);
+       eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+       if (old_ssid != wpa_s->current_ssid)
+               wpas_notify_network_changed(wpa_s);
+       eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+}
+
+
 /**
  * wpa_supplicant_disassociate - Disassociate the current connection
  * @wpa_s: Pointer to wpa_supplicant data
@@ -1400,26 +1621,14 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
                                 int reason_code)
 {
-       struct wpa_ssid *old_ssid;
        u8 *addr = NULL;
 
        if (!is_zero_ether_addr(wpa_s->bssid)) {
-               if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-                       ieee80211_sta_disassociate(wpa_s, reason_code);
-               else
-                       wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
+               wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
                addr = wpa_s->bssid;
        }
-       wpa_clear_keys(wpa_s, addr);
-       wpa_supplicant_mark_disassoc(wpa_s);
-       old_ssid = wpa_s->current_ssid;
-       wpa_s->current_ssid = NULL;
-       wpa_s->current_bss = NULL;
-       wpa_sm_set_config(wpa_s->wpa, NULL);
-       eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
-       if (old_ssid != wpa_s->current_ssid)
-               wpas_notify_network_changed(wpa_s);
-       eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+
+       wpa_supplicant_clear_connection(wpa_s, addr);
 }
 
 
@@ -1434,27 +1643,14 @@ void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
 void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
                                   int reason_code)
 {
-       struct wpa_ssid *old_ssid;
        u8 *addr = NULL;
 
        if (!is_zero_ether_addr(wpa_s->bssid)) {
-               if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-                       ieee80211_sta_deauthenticate(wpa_s, reason_code);
-               else
-                       wpa_drv_deauthenticate(wpa_s, wpa_s->bssid,
-                                              reason_code);
+               wpa_drv_deauthenticate(wpa_s, wpa_s->bssid, reason_code);
                addr = wpa_s->bssid;
        }
-       wpa_clear_keys(wpa_s, addr);
-       wpa_supplicant_mark_disassoc(wpa_s);
-       old_ssid = wpa_s->current_ssid;
-       wpa_s->current_ssid = NULL;
-       wpa_s->current_bss = NULL;
-       wpa_sm_set_config(wpa_s->wpa, NULL);
-       eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
-       if (old_ssid != wpa_s->current_ssid)
-               wpas_notify_network_changed(wpa_s);
-       eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+
+       wpa_supplicant_clear_connection(wpa_s, addr);
 }
 
 
@@ -1472,8 +1668,11 @@ void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
        int was_disabled;
 
        if (ssid == NULL) {
-               other_ssid = wpa_s->conf->ssid;
-               while (other_ssid) {
+               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;
@@ -1485,12 +1684,10 @@ void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
                        if (was_disabled != other_ssid->disabled)
                                wpas_notify_network_enabled_changed(
                                        wpa_s, other_ssid);
-
-                       other_ssid = other_ssid->next;
                }
                if (wpa_s->reassociate)
                        wpa_supplicant_req_scan(wpa_s, 0, 0);
-       } else if (ssid->disabled) {
+       } else if (ssid->disabled && ssid->disabled != 2) {
                if (wpa_s->current_ssid == NULL) {
                        /*
                         * Try to reassociate since there is no current
@@ -1524,22 +1721,23 @@ void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
        int was_disabled;
 
        if (ssid == NULL) {
-               other_ssid = wpa_s->conf->ssid;
-               while (other_ssid) {
+               for (other_ssid = wpa_s->conf->ssid; other_ssid;
+                    other_ssid = other_ssid->next) {
                        was_disabled = other_ssid->disabled;
+                       if (was_disabled == 2)
+                               continue; /* do not change persistent P2P group
+                                          * data */
 
                        other_ssid->disabled = 1;
 
                        if (was_disabled != other_ssid->disabled)
                                wpas_notify_network_enabled_changed(
                                        wpa_s, other_ssid);
-
-                       other_ssid = other_ssid->next;
                }
                if (wpa_s->current_ssid)
                        wpa_supplicant_disassociate(
                                wpa_s, WLAN_REASON_DEAUTH_LEAVING);
-       } else {
+       } else if (ssid->disabled != 2) {
                if (ssid == wpa_s->current_ssid)
                        wpa_supplicant_disassociate(
                                wpa_s, WLAN_REASON_DEAUTH_LEAVING);
@@ -1562,7 +1760,13 @@ 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;
 
        if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid)
@@ -1573,44 +1777,51 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
         * Mark all other networks disabled or mark all networks enabled if no
         * network specified.
         */
-       other_ssid = wpa_s->conf->ssid;
-       while (other_ssid) {
+       for (other_ssid = wpa_s->conf->ssid; other_ssid;
+            other_ssid = other_ssid->next) {
                int was_disabled = other_ssid->disabled;
+               if (was_disabled == 2)
+                       continue; /* do not change persistent P2P group data */
 
                other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
 
                if (was_disabled != other_ssid->disabled)
                        wpas_notify_network_enabled_changed(wpa_s, other_ssid);
+       }
 
-               other_ssid = other_ssid->next;
+       if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid) {
+               /* We are already associated with the selected network */
+               wpa_printf(MSG_DEBUG, "Already associated with the "
+                          "selected network - do nothing");
+               return;
        }
+
+       wpa_s->connect_without_scan = NULL;
        wpa_s->disconnected = 0;
        wpa_s->reassociate = 1;
 
-       wpa_printf(MSG_DEBUG, "==================================================");
-       wpa_printf(MSG_DEBUG, "Select network start ssid : '%s'", ssid->ssid);
-       wpa_printf(MSG_DEBUG, "==================================================");
-
+#if defined TIZEN_EXT
        /*
         * August 1st, 2011 TIZEN
         * This part is changed to reduce associating duration.
         */
-        wpa_s->associate_num = 0;
-       if( (selected_bss = wpa_bss_check_scan_res(wpa_s,ssid->ssid)) == NULL)
+       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
-       {
+       } 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 (ssid)
+               wpas_notify_network_selected(wpa_s, ssid);
+#endif
 }
 
 
@@ -1629,6 +1840,16 @@ int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan)
        if (ap_scan < 0 || ap_scan > 2)
                return -1;
 
+#ifdef ANDROID
+       if (ap_scan == 2 && ap_scan != wpa_s->conf->ap_scan &&
+           wpa_s->wpa_state >= WPA_ASSOCIATING &&
+           wpa_s->wpa_state < WPA_COMPLETED) {
+               wpa_printf(MSG_ERROR, "ap_scan = %d (%d) rejected while "
+                          "associating", wpa_s->conf->ap_scan, ap_scan);
+               return 0;
+       }
+#endif /* ANDROID */
+
        old_ap_scan = wpa_s->conf->ap_scan;
        wpa_s->conf->ap_scan = ap_scan;
 
@@ -1640,6 +1861,52 @@ int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan)
 
 
 /**
+ * wpa_supplicant_set_bss_expiration_age - Set BSS entry expiration age
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @expire_age: Expiration age in seconds
+ * Returns: 0 if succeed or -1 if expire_age has an invalid value
+ *
+ */
+int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s,
+                                         unsigned int bss_expire_age)
+{
+       if (bss_expire_age < 10) {
+               wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration age %u",
+                       bss_expire_age);
+               return -1;
+       }
+       wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration age: %d sec",
+               bss_expire_age);
+       wpa_s->conf->bss_expiration_age = bss_expire_age;
+
+       return 0;
+}
+
+
+/**
+ * wpa_supplicant_set_bss_expiration_count - Set BSS entry expiration scan count
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @expire_count: number of scans after which an unseen BSS is reclaimed
+ * Returns: 0 if succeed or -1 if expire_count has an invalid value
+ *
+ */
+int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s,
+                                           unsigned int bss_expire_count)
+{
+       if (bss_expire_count < 1) {
+               wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration count %u",
+                       bss_expire_count);
+               return -1;
+       }
+       wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration scan count: %u",
+               bss_expire_count);
+       wpa_s->conf->bss_expiration_scan_count = bss_expire_count;
+
+       return 0;
+}
+
+
+/**
  * wpa_supplicant_set_debug_params - Set global debug params
  * @global: wpa_global structure
  * @debug_level: debug level
@@ -1654,7 +1921,8 @@ int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level,
        int old_level, old_timestamp, old_show_keys;
 
        /* check for allowed debuglevels */
-       if (debug_level != MSG_MSGDUMP &&
+       if (debug_level != MSG_EXCESSIVE &&
+           debug_level != MSG_MSGDUMP &&
            debug_level != MSG_DEBUG &&
            debug_level != MSG_INFO &&
            debug_level != MSG_WARNING &&
@@ -1694,26 +1962,17 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
        u8 bssid[ETH_ALEN];
        int wired;
 
-       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
-               if (ieee80211_sta_get_ssid(wpa_s, ssid, &ssid_len)) {
-                       wpa_printf(MSG_WARNING, "Could not read SSID from "
-                                  "MLME.");
-                       return NULL;
-               }
-       } else {
-               res = wpa_drv_get_ssid(wpa_s, ssid);
-               if (res < 0) {
-                       wpa_printf(MSG_WARNING, "Could not read SSID from "
-                                  "driver.");
-                       return NULL;
-               }
-               ssid_len = res;
+       res = wpa_drv_get_ssid(wpa_s, ssid);
+       if (res < 0) {
+               wpa_msg(wpa_s, MSG_WARNING, "Could not read SSID from "
+                       "driver");
+               return NULL;
        }
+       ssid_len = res;
 
-       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-               os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
-       else if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
-               wpa_printf(MSG_WARNING, "Could not read BSSID from driver.");
+       if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
+               wpa_msg(wpa_s, MSG_WARNING, "Could not read BSSID from "
+                       "driver");
                return NULL;
        }
 
@@ -1736,6 +1995,12 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
                     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
                        return entry;
 #endif /* CONFIG_WPS */
+
+               if (!entry->disabled && entry->bssid_set &&
+                   entry->ssid_len == 0 &&
+                   os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)
+                       return entry;
+
                entry = entry->next;
        }
 
@@ -1743,45 +2008,65 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
 }
 
 
+static int select_driver(struct wpa_supplicant *wpa_s, int i)
+{
+       struct wpa_global *global = wpa_s->global;
+
+       if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) {
+               global->drv_priv[i] = wpa_drivers[i]->global_init();
+               if (global->drv_priv[i] == NULL) {
+                       wpa_printf(MSG_ERROR, "Failed to initialize driver "
+                                  "'%s'", wpa_drivers[i]->name);
+                       return -1;
+               }
+       }
+
+       wpa_s->driver = wpa_drivers[i];
+       wpa_s->global_drv_priv = global->drv_priv[i];
+
+       return 0;
+}
+
+
 static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
                                     const char *name)
 {
        int i;
        size_t len;
-       const char *pos;
+       const char *pos, *driver = name;
 
        if (wpa_s == NULL)
                return -1;
 
        if (wpa_drivers[0] == NULL) {
-               wpa_printf(MSG_ERROR, "No driver interfaces build into "
-                          "wpa_supplicant.");
+               wpa_msg(wpa_s, MSG_ERROR, "No driver interfaces build into "
+                       "wpa_supplicant");
                return -1;
        }
 
        if (name == NULL) {
                /* default to first driver in the list */
-               wpa_s->driver = wpa_drivers[0];
-               wpa_s->global_drv_priv = wpa_s->global->drv_priv[0];
-               return 0;
+               return select_driver(wpa_s, 0);
        }
 
-       pos = os_strchr(name, ',');
-       if (pos)
-               len = pos - name;
-       else
-               len = os_strlen(name);
-       for (i = 0; wpa_drivers[i]; i++) {
-               if (os_strlen(wpa_drivers[i]->name) == len &&
-                   os_strncmp(name, wpa_drivers[i]->name, len) ==
-                   0) {
-                       wpa_s->driver = wpa_drivers[i];
-                       wpa_s->global_drv_priv = wpa_s->global->drv_priv[i];
-                       return 0;
+       do {
+               pos = os_strchr(driver, ',');
+               if (pos)
+                       len = pos - driver;
+               else
+                       len = os_strlen(driver);
+
+               for (i = 0; wpa_drivers[i]; i++) {
+                       if (os_strlen(wpa_drivers[i]->name) == len &&
+                           os_strncmp(driver, wpa_drivers[i]->name, len) ==
+                           0)
+                               return select_driver(wpa_s, i);
                }
-       }
 
-       wpa_printf(MSG_ERROR, "Unsupported driver '%s'.", name);
+               driver = pos + 1;
+       } while (pos);
+
+       wpa_msg(wpa_s, MSG_ERROR, "Unsupported driver '%s'", name);
        return -1;
 }
 
@@ -1805,7 +2090,7 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
 {
        struct wpa_supplicant *wpa_s = ctx;
 
-       wpa_printf(MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(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) {
@@ -1817,8 +2102,8 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
                 * association information, lets queue it for processing until
                 * the association event is received.
                 */
-               wpa_printf(MSG_DEBUG, "Not associated - Delay processing of "
-                          "received EAPOL frame");
+               wpa_dbg(wpa_s, MSG_DEBUG, "Not associated - Delay processing "
+                       "of received EAPOL frame");
                wpabuf_free(wpa_s->pending_eapol_rx);
                wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
                if (wpa_s->pending_eapol_rx) {
@@ -1837,8 +2122,8 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
 #endif /* CONFIG_AP */
 
        if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
-               wpa_printf(MSG_DEBUG, "Ignored received EAPOL frame since "
-                          "no key management is configured");
+               wpa_dbg(wpa_s, MSG_DEBUG, "Ignored received EAPOL frame since "
+                       "no key management is configured");
                return;
        }
 
@@ -1859,8 +2144,8 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
        wpa_s->eapol_received++;
 
        if (wpa_s->countermeasures) {
-               wpa_printf(MSG_INFO, "WPA: Countermeasures - dropped EAPOL "
-                          "packet");
+               wpa_msg(wpa_s, MSG_INFO, "WPA: Countermeasures - dropped "
+                       "EAPOL packet");
                return;
        }
 
@@ -1897,52 +2182,68 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
 }
 
 
-/**
- * wpa_supplicant_driver_init - Initialize driver interface parameters
- * @wpa_s: Pointer to wpa_supplicant data
- * Returns: 0 on success, -1 on failure
- *
- * This function is called to initialize driver interface parameters.
- * wpa_drv_init() must have been called before this function to initialize the
- * driver interface.
- */
-int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
+int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
 {
-       static int interface_count = 0;
-
        if (wpa_s->driver->send_eapol) {
                const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
                if (addr)
                        os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
-       } else {
+       } else if (!(wpa_s->drv_flags &
+                    WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
+               l2_packet_deinit(wpa_s->l2);
                wpa_s->l2 = l2_packet_init(wpa_s->ifname,
                                           wpa_drv_get_mac_addr(wpa_s),
                                           ETH_P_EAPOL,
                                           wpa_supplicant_rx_eapol, wpa_s, 0);
                if (wpa_s->l2 == NULL)
                        return -1;
+       } else {
+               const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
+               if (addr)
+                       os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
        }
 
        if (wpa_s->l2 && l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
-               wpa_printf(MSG_ERROR, "Failed to get own L2 address");
+               wpa_msg(wpa_s, MSG_ERROR, "Failed to get own L2 address");
                return -1;
        }
 
-       wpa_printf(MSG_DEBUG, "Own MAC address: " MACSTR,
-                  MAC2STR(wpa_s->own_addr));
+       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;
+}
+
+
+/**
+ * wpa_supplicant_driver_init - Initialize driver interface parameters
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called to initialize driver interface parameters.
+ * wpa_drv_init() must have been called before this function to initialize the
+ * driver interface.
+ */
+int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
+{
+       static int interface_count = 0;
+
+       if (wpa_supplicant_update_mac_addr(wpa_s) < 0)
+               return -1;
 
        if (wpa_s->bridge_ifname[0]) {
-               wpa_printf(MSG_DEBUG, "Receiving packets from bridge interface"
-                          " '%s'", wpa_s->bridge_ifname);
+               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);
                if (wpa_s->l2_br == NULL) {
-                       wpa_printf(MSG_ERROR, "Failed to open l2_packet "
-                                  "connection for the bridge interface '%s'",
-                                  wpa_s->bridge_ifname);
+                       wpa_msg(wpa_s, MSG_ERROR, "Failed to open l2_packet "
+                               "connection for the bridge interface '%s'",
+                               wpa_s->bridge_ifname);
                        return -1;
                }
        }
@@ -1953,12 +2254,15 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
         * happen if wpa_supplicant is killed during countermeasures. */
        wpa_drv_set_countermeasures(wpa_s, 0);
 
-       wpa_printf(MSG_DEBUG, "RSN: flushing PMKID list in the driver");
+       wpa_dbg(wpa_s, MSG_DEBUG, "RSN: flushing PMKID list in the driver");
        wpa_drv_flush_pmkid(wpa_s);
 
        wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
        if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
-               wpa_supplicant_req_scan(wpa_s, interface_count, 100000);
+               if (wpa_supplicant_delayed_sched_scan(wpa_s, interface_count,
+                                                     100000))
+                       wpa_supplicant_req_scan(wpa_s, interface_count,
+                                               100000);
                interface_count++;
        } else
                wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
@@ -1982,7 +2286,17 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
        if (wpa_s == NULL)
                return NULL;
        wpa_s->scan_req = 1;
+       wpa_s->scan_interval = 5;
        wpa_s->new_connection = 1;
+       wpa_s->parent = wpa_s;
+       wpa_s->sched_scanning = 0;
+#if defined TIZEN_EXT
+       /*
+        * Jan, 9th 2012. TIZEN
+        * Remove reconnect procedure after getting disassoc event
+        */
+       wpa_s->auto_reconnect_disabled = 1;
+#endif
 
        return wpa_s;
 }
@@ -2040,12 +2354,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
        } else
                wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface,
                                                     iface->driver_param);
-       /*
-        * October 11st, 2011 TIZEN
-        * Workaround for timeout.
-        */
-       wpa_s->associate_num =2;
-       
+
        if (wpa_s->conf == NULL) {
                wpa_printf(MSG_ERROR, "\nNo configuration found.");
                return -1;
@@ -2091,24 +2400,25 @@ next_driver:
                const char *pos;
                pos = driver ? os_strchr(driver, ',') : NULL;
                if (pos) {
-                       wpa_printf(MSG_DEBUG, "Failed to initialize driver "
-                                  "interface - try next driver wrapper");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
+                               "driver interface - try next driver wrapper");
                        driver = pos + 1;
                        goto next_driver;
                }
-               wpa_printf(MSG_ERROR, "Failed to initialize driver interface");
+               wpa_msg(wpa_s, MSG_ERROR, "Failed to initialize driver "
+                       "interface");
                return -1;
        }
        if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
-               wpa_printf(MSG_ERROR, "Driver interface rejected "
-                          "driver_param '%s'", wpa_s->conf->driver_param);
+               wpa_msg(wpa_s, MSG_ERROR, "Driver interface rejected "
+                       "driver_param '%s'", wpa_s->conf->driver_param);
                return -1;
        }
 
        ifname = wpa_drv_get_ifname(wpa_s);
        if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) {
-               wpa_printf(MSG_DEBUG, "Driver interface replaced interface "
-                          "name with '%s'", ifname);
+               wpa_dbg(wpa_s, MSG_DEBUG, "Driver interface replaced "
+                       "interface name with '%s'", ifname);
                os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
        }
 
@@ -2123,15 +2433,15 @@ next_driver:
        if (wpa_s->conf->dot11RSNAConfigPMKLifetime &&
            wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
                             wpa_s->conf->dot11RSNAConfigPMKLifetime)) {
-               wpa_printf(MSG_ERROR, "Invalid WPA parameter value for "
-                          "dot11RSNAConfigPMKLifetime");
+               wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
+                       "dot11RSNAConfigPMKLifetime");
                return -1;
        }
 
        if (wpa_s->conf->dot11RSNAConfigPMKReauthThreshold &&
            wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
                             wpa_s->conf->dot11RSNAConfigPMKReauthThreshold)) {
-               wpa_printf(MSG_ERROR, "Invalid WPA parameter value for "
+               wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
                        "dot11RSNAConfigPMKReauthThreshold");
                return -1;
        }
@@ -2139,19 +2449,25 @@ next_driver:
        if (wpa_s->conf->dot11RSNAConfigSATimeout &&
            wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT,
                             wpa_s->conf->dot11RSNAConfigSATimeout)) {
-               wpa_printf(MSG_ERROR, "Invalid WPA parameter value for "
-                          "dot11RSNAConfigSATimeout");
+               wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
+                       "dot11RSNAConfigSATimeout");
                return -1;
        }
 
+       wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,
+                                                     &wpa_s->hw.num_modes,
+                                                     &wpa_s->hw.flags);
+
        if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
+               wpa_s->drv_capa_known = 1;
                wpa_s->drv_flags = capa.flags;
-               if (capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
-                       if (ieee80211_sta_init(wpa_s))
-                               return -1;
-               }
+               wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
                wpa_s->max_scan_ssids = capa.max_scan_ssids;
+               wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
+               wpa_s->sched_scan_supported = capa.sched_scan_supported;
+               wpa_s->max_match_sets = capa.max_match_sets;
                wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
+               wpa_s->max_stations = capa.max_stations;
        }
        if (wpa_s->max_remain_on_chan == 0)
                wpa_s->max_remain_on_chan = 1000;
@@ -2159,14 +2475,17 @@ next_driver:
        if (wpa_supplicant_driver_init(wpa_s) < 0)
                return -1;
 
+#ifdef CONFIG_TDLS
+       if (wpa_tdls_init(wpa_s->wpa))
+               return -1;
+#endif /* CONFIG_TDLS */
+
        if (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&
            wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {
-               wpa_printf(MSG_DEBUG, "Failed to set country");
+               wpa_dbg(wpa_s, MSG_DEBUG, "Failed to set country");
                return -1;
        }
 
-       wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
-
        if (wpas_wps_init(wpa_s))
                return -1;
 
@@ -2188,13 +2507,18 @@ next_driver:
                return -1;
        }
 
-#ifdef CONFIG_IBSS_RSN
-       wpa_s->ibss_rsn = ibss_rsn_init(wpa_s);
-       if (!wpa_s->ibss_rsn) {
-               wpa_printf(MSG_DEBUG, "Failed to init IBSS RSN");
+       wpa_s->gas = gas_query_init(wpa_s);
+       if (wpa_s->gas == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to initialize GAS query");
                return -1;
        }
-#endif /* CONFIG_IBSS_RSN */
+
+#ifdef CONFIG_P2P
+       if (wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
+               wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
+               return -1;
+       }
+#endif /* CONFIG_P2P */
 
        if (wpa_bss_init(wpa_s) < 0)
                return -1;
@@ -2288,7 +2612,7 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
        wpa_s->next = global->ifaces;
        global->ifaces = wpa_s;
 
-       wpa_printf(MSG_DEBUG, "Added interface %s", wpa_s->ifname);
+       wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname);
 
        return wpa_s;
 }
@@ -2322,8 +2646,10 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
                prev->next = wpa_s->next;
        }
 
-       wpa_printf(MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
+       wpa_dbg(wpa_s, MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
 
+       if (global->p2p_group_formation == wpa_s)
+               global->p2p_group_formation = NULL;
        wpa_supplicant_deinit_iface(wpa_s, 1);
        os_free(wpa_s);
 
@@ -2332,6 +2658,28 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
 
 
 /**
+ * wpa_supplicant_get_eap_mode - Get the current EAP mode
+ * @wpa_s: Pointer to the network interface
+ * Returns: Pointer to the eap mode or the string "UNKNOWN" if not found
+ */
+const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s)
+{
+       const char *eapol_method;
+
+        if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) == 0 &&
+            wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+               return "NO-EAP";
+       }
+
+       eapol_method = eapol_sm_get_method_name(wpa_s->eapol);
+       if (eapol_method == NULL)
+               return "UNKNOWN-EAP";
+
+       return eapol_method;
+}
+
+
+/**
  * wpa_supplicant_get_iface - Get a new network interface
  * @global: Pointer to global data from wpa_supplicant_init()
  * @ifname: Interface name
@@ -2350,6 +2698,17 @@ struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
 }
 
 
+#ifndef CONFIG_NO_WPA_MSG
+static const char * wpa_supplicant_msg_ifname_cb(void *ctx)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       if (wpa_s == NULL)
+               return NULL;
+       return wpa_s->ifname;
+}
+#endif /* CONFIG_NO_WPA_MSG */
+
+
 /**
  * wpa_supplicant_init - Initialize %wpa_supplicant
  * @params: Parameters for %wpa_supplicant
@@ -2367,6 +2726,17 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
        if (params == NULL)
                return NULL;
 
+#ifdef CONFIG_DRIVER_NDIS
+       {
+               void driver_ndis_init_ops(void);
+               driver_ndis_init_ops();
+       }
+#endif /* CONFIG_DRIVER_NDIS */
+
+#ifndef CONFIG_NO_WPA_MSG
+       wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);
+#endif /* CONFIG_NO_WPA_MSG */
+
        wpa_debug_open_file(params->wpa_debug_file_path);
        if (params->wpa_debug_syslog)
                wpa_debug_open_syslog();
@@ -2383,6 +2753,8 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
        global = os_zalloc(sizeof(*global));
        if (global == NULL)
                return NULL;
+       dl_list_init(&global->p2p_srv_bonjour);
+       dl_list_init(&global->p2p_srv_upnp);
        global->params.daemonize = params->daemonize;
        global->params.wait_for_monitor = params->wait_for_monitor;
        global->params.dbus_ctrl_interface = params->dbus_ctrl_interface;
@@ -2404,12 +2776,16 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
        wpa_debug_timestamp = global->params.wpa_debug_timestamp =
                params->wpa_debug_timestamp;
 
+       wpa_printf(MSG_DEBUG, "wpa_supplicant v" VERSION_STR);
+
        if (eloop_init()) {
                wpa_printf(MSG_ERROR, "Failed to initialize event loop");
                wpa_supplicant_deinit(global);
                return NULL;
        }
 
+       random_init(params->entropy_file);
+
        global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
        if (global->ctrl_iface == NULL) {
                wpa_supplicant_deinit(global);
@@ -2433,17 +2809,6 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
                wpa_supplicant_deinit(global);
                return NULL;
        }
-       for (i = 0; wpa_drivers[i]; i++) {
-               if (!wpa_drivers[i]->global_init)
-                       continue;
-               global->drv_priv[i] = wpa_drivers[i]->global_init();
-               if (global->drv_priv[i] == NULL) {
-                       wpa_printf(MSG_ERROR, "Failed to initialize driver "
-                                  "'%s'", wpa_drivers[i]->name);
-                       wpa_supplicant_deinit(global);
-                       return NULL;
-               }
-       }
 
        return global;
 }
@@ -2496,6 +2861,10 @@ void wpa_supplicant_deinit(struct wpa_global *global)
        if (global == NULL)
                return;
 
+#ifdef CONFIG_P2P
+       wpas_p2p_deinit_global(global);
+#endif /* CONFIG_P2P */
+
        while (global->ifaces)
                wpa_supplicant_remove_iface(global, global->ifaces);
 
@@ -2516,6 +2885,8 @@ void wpa_supplicant_deinit(struct wpa_global *global)
        }
        os_free(global->drv_priv);
 
+       random_deinit();
+
        eloop_destroy();
 
        if (global->params.pid_file) {
@@ -2530,3 +2901,144 @@ void wpa_supplicant_deinit(struct wpa_global *global)
        wpa_debug_close_syslog();
        wpa_debug_close_file();
 }
+
+
+void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
+{
+       if ((wpa_s->conf->changed_parameters & CFG_CHANGED_COUNTRY) &&
+           wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
+               char country[3];
+               country[0] = wpa_s->conf->country[0];
+               country[1] = wpa_s->conf->country[1];
+               country[2] = '\0';
+               if (wpa_drv_set_country(wpa_s, country) < 0) {
+                       wpa_printf(MSG_ERROR, "Failed to set country code "
+                                  "'%s'", country);
+               }
+       }
+
+#ifdef CONFIG_WPS
+       wpas_wps_update_config(wpa_s);
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+       wpas_p2p_update_config(wpa_s);
+#endif /* CONFIG_P2P */
+
+       wpa_s->conf->changed_parameters = 0;
+}
+
+
+static void add_freq(int *freqs, int *num_freqs, int freq)
+{
+       int i;
+
+       for (i = 0; i < *num_freqs; i++) {
+               if (freqs[i] == freq)
+                       return;
+       }
+
+       freqs[*num_freqs] = freq;
+       (*num_freqs)++;
+}
+
+
+static int * get_bss_freqs_in_ess(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_bss *bss, *cbss;
+       const int max_freqs = 10;
+       int *freqs;
+       int num_freqs = 0;
+
+       freqs = os_zalloc(sizeof(int) * (max_freqs + 1));
+       if (freqs == NULL)
+               return NULL;
+
+       cbss = wpa_s->current_bss;
+
+       dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+               if (bss == cbss)
+                       continue;
+               if (bss->ssid_len == cbss->ssid_len &&
+                   os_memcmp(bss->ssid, cbss->ssid, bss->ssid_len) == 0 &&
+                   wpa_blacklist_get(wpa_s, bss->bssid) == NULL) {
+                       add_freq(freqs, &num_freqs, bss->freq);
+                       if (num_freqs == max_freqs)
+                               break;
+               }
+       }
+
+       if (num_freqs == 0) {
+               os_free(freqs);
+               freqs = NULL;
+       }
+
+       return freqs;
+}
+
+
+void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+       int timeout;
+       int count;
+       int *freqs = NULL;
+
+       /*
+        * Add the failed BSSID into the blacklist and speed up next scan
+        * attempt if there could be other APs that could accept association.
+        * The current blacklist count indicates how many times we have tried
+        * connecting to this AP and multiple attempts mean that other APs are
+        * either not available or has already been tried, so that we can start
+        * increasing the delay here to avoid constant scanning.
+        */
+       count = wpa_blacklist_add(wpa_s, bssid);
+       if (count == 1 && wpa_s->current_bss) {
+               /*
+                * This BSS was not in the blacklist before. If there is
+                * another BSS available for the same ESS, we should try that
+                * next. Otherwise, we may as well try this one once more
+                * before allowing other, likely worse, ESSes to be considered.
+                */
+               freqs = get_bss_freqs_in_ess(wpa_s);
+               if (freqs) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "Another BSS in this ESS "
+                               "has been seen; try it next");
+                       wpa_blacklist_add(wpa_s, bssid);
+                       /*
+                        * On the next scan, go through only the known channels
+                        * used in this ESS based on previous scans to speed up
+                        * common load balancing use case.
+                        */
+                       os_free(wpa_s->next_scan_freqs);
+                       wpa_s->next_scan_freqs = freqs;
+               }
+       }
+
+       switch (count) {
+       case 1:
+               timeout = 100;
+               break;
+       case 2:
+               timeout = 500;
+               break;
+       case 3:
+               timeout = 1000;
+               break;
+       default:
+               timeout = 5000;
+       }
+
+       /*
+        * 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));
+}
+
+
+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);
+}
index 0cd5b02..d393015 100644 (file)
@@ -28,7 +28,7 @@
 # Parameters for the control interface. If this is specified, wpa_supplicant
 # will open a control interface that is available for external programs to
 # manage wpa_supplicant. The meaning of this string depends on which control
-# interface mechanism is used. For all cases, the existance of this parameter
+# interface mechanism is used. For all cases, the existence of this parameter
 # in configuration is used to determine whether the control interface is
 # enabled.
 #
@@ -199,8 +199,12 @@ fast_reauth=1
 # Config Methods
 # List of the supported configuration methods
 # Available methods: usba ethernet label display ext_nfc_token int_nfc_token
-#      nfc_interface push_button keypad
+#      nfc_interface push_button keypad virtual_display physical_display
+#      virtual_push_button physical_push_button
+# For WSC 1.0:
 #config_methods=label display push_button keypad
+# For WSC 2.0:
+#config_methods=label virtual_display virtual_push_button keypad
 
 # Credential processing
 #   0 = process received credentials internally (default)
@@ -224,6 +228,35 @@ fast_reauth=1
 #filter_ssids=0
 
 
+# Interworking (IEEE 802.11u)
+
+# Enable Interworking
+# interworking=1
+
+# Homogenous ESS identifier
+# If this is set, scans will be used to request response only from BSSes
+# belonging to the specified Homogeneous ESS. This is used only if interworking
+# is enabled.
+# hessid=00:11:22:33:44:55
+
+# 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
+
+# Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN> format
+#home_milenage=90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123
+
 # network block
 #
 # Each network (usually AP's sharing the same SSID) is configured as a separate
@@ -350,7 +383,7 @@ fast_reauth=1
 #
 # mixed_cell: This option can be used to configure whether so called mixed
 # cells, i.e., networks that use both plaintext and encryption in the same
-# SSID, are allowed when selecting a BSS form scan results.
+# SSID, are allowed when selecting a BSS from scan results.
 # 0 = disabled (default)
 # 1 = enabled
 #
index 994fba5..5469129 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "utils/list.h"
 #include "common/defs.h"
+#include "config_ssid.h"
 
 extern const char *wpa_supplicant_version;
 extern const char *wpa_supplicant_license;
@@ -34,6 +35,7 @@ struct ibss_rsn;
 struct scan_info;
 struct wpa_bss;
 struct wpa_scan_results;
+struct hostapd_hw_modes;
 
 /*
  * Forward declarations of private structures used within the ctrl_iface
@@ -180,6 +182,26 @@ struct wpa_params {
         * created.
         */
        char *override_ctrl_interface;
+
+       /**
+        * entropy_file - Optional entropy file
+        *
+        * This parameter can be used to configure wpa_supplicant to maintain
+        * its internal entropy store over restarts.
+        */
+       char *entropy_file;
+};
+
+struct p2p_srv_bonjour {
+       struct dl_list list;
+       struct wpabuf *query;
+       struct wpabuf *resp;
+};
+
+struct p2p_srv_upnp {
+       struct dl_list list;
+       u8 version;
+       char *service;
 };
 
 /**
@@ -196,101 +218,21 @@ struct wpa_global {
        void **drv_priv;
        size_t drv_count;
        struct os_time suspend_time;
+       struct p2p_data *p2p;
+       struct wpa_supplicant *p2p_group_formation;
+       u8 p2p_dev_addr[ETH_ALEN];
+       struct dl_list p2p_srv_bonjour; /* struct p2p_srv_bonjour */
+       struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */
+       int p2p_disabled;
+       int cross_connection;
 };
 
 
-struct wpa_client_mlme {
-#ifdef CONFIG_CLIENT_MLME
-       enum {
-               IEEE80211_DISABLED, IEEE80211_AUTHENTICATE,
-               IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED,
-               IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED
-       } state;
-       u8 prev_bssid[ETH_ALEN];
-       u8 ssid[32];
-       size_t ssid_len;
-       u16 aid;
-       u16 ap_capab, capab;
-       u8 *extra_ie; /* to be added to the end of AssocReq */
-       size_t extra_ie_len;
-       u8 *extra_probe_ie; /* to be added to the end of ProbeReq */
-       size_t extra_probe_ie_len;
-       enum wpa_key_mgmt key_mgmt;
-
-       /* The last AssocReq/Resp IEs */
-       u8 *assocreq_ies, *assocresp_ies;
-       size_t assocreq_ies_len, assocresp_ies_len;
-
-       int auth_tries, assoc_tries;
-
-       unsigned int ssid_set:1;
-       unsigned int bssid_set:1;
-       unsigned int prev_bssid_set:1;
-       unsigned int authenticated:1;
-       unsigned int associated:1;
-       unsigned int probereq_poll:1;
-       unsigned int use_protection:1;
-       unsigned int create_ibss:1;
-       unsigned int mixed_cell:1;
-       unsigned int wmm_enabled:1;
-
-       struct os_time last_probe;
-
-       unsigned int auth_algs; /* bitfield of allowed auth algs
-                                * (WPA_AUTH_ALG_*) */
-       int auth_alg; /* currently used IEEE 802.11 authentication algorithm */
-       int auth_transaction;
-
-       struct os_time ibss_join_req;
-       u8 *probe_resp; /* ProbeResp template for IBSS */
-       size_t probe_resp_len;
-       u32 supp_rates_bits;
-
-       int wmm_last_param_set;
-
-       int sta_scanning;
-       int scan_hw_mode_idx;
-       int scan_channel_idx;
-       enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
-       struct os_time last_scan_completed;
-       int scan_oper_channel;
-       int scan_oper_freq;
-       int scan_oper_phymode;
-       u8 scan_ssid[32];
-       size_t scan_ssid_len;
-       int scan_skip_11b;
-       int *scan_freqs;
-
-       struct ieee80211_sta_bss *sta_bss_list;
-#define STA_HASH_SIZE 256
-#define STA_HASH(sta) (sta[5])
-       struct ieee80211_sta_bss *sta_bss_hash[STA_HASH_SIZE];
-
-       int cts_protect_erp_frames;
-
-       enum hostapd_hw_mode phymode; /* current mode */
-       struct hostapd_hw_modes *modes;
-       size_t num_modes;
-       unsigned int hw_modes; /* bitfield of allowed hardware modes;
-                               * (1 << HOSTAPD_MODE_*) */
-       int num_curr_rates;
-       int *curr_rates;
-       int freq; /* The current frequency in MHz */
-       int channel; /* The current IEEE 802.11 channel number */
-
-#ifdef CONFIG_IEEE80211R
-       u8 current_md[6];
-       u8 *ft_ies;
-       size_t ft_ies_len;
-#endif /* CONFIG_IEEE80211R */
-
-       void (*public_action_cb)(void *ctx, const u8 *buf, size_t len,
-                                int freq);
-       void *public_action_cb_ctx;
-
-#else /* CONFIG_CLIENT_MLME */
-       int dummy; /* to keep MSVC happy */
-#endif /* CONFIG_CLIENT_MLME */
+enum offchannel_send_action_result {
+       OFFCHANNEL_SEND_ACTION_SUCCESS /* Frame was send and acknowledged */,
+       OFFCHANNEL_SEND_ACTION_NO_ACK /* Frame was sent, but not acknowledged
+                                      */,
+       OFFCHANNEL_SEND_ACTION_FAILED /* Frame was not sent due to a failure */
 };
 
 /**
@@ -303,6 +245,7 @@ struct wpa_client_mlme {
  */
 struct wpa_supplicant {
        struct wpa_global *global;
+       struct wpa_supplicant *parent;
        struct wpa_supplicant *next;
        struct l2_packet_data *l2;
        struct l2_packet_data *l2_br;
@@ -313,6 +256,7 @@ struct wpa_supplicant {
 #endif /* CONFIG_CTRL_IFACE_DBUS */
 #ifdef CONFIG_CTRL_IFACE_DBUS_NEW
        char *dbus_new_path;
+       char *dbus_groupobj_path;
 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
        char bridge_ifname[16];
 
@@ -322,7 +266,7 @@ struct wpa_supplicant {
        os_time_t last_michael_mic_error;
        u8 bssid[ETH_ALEN];
        u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
-                                    * field contains the targer BSSID. */
+                                    * field contains the target BSSID. */
        int reassociate; /* reassociation requested */
        int disconnected; /* all connections disabled; i.e., do no reassociate
                           * before this has been cleared */
@@ -335,6 +279,7 @@ struct wpa_supplicant {
        int pairwise_cipher;
        int group_cipher;
        int key_mgmt;
+       int wpa_proto;
        int mgmt_group_cipher;
 
        void *drv_priv; /* private data used by driver_ops */
@@ -348,6 +293,12 @@ struct wpa_supplicant {
                                          */
 #define WILDCARD_SSID_SCAN ((struct wpa_ssid *) 1)
 
+       struct wpa_ssid *prev_sched_ssid; /* last SSID used in sched scan */
+       int sched_scan_timeout;
+       int sched_scan_interval;
+       int first_sched_scan;
+       int sched_scan_timed_out;
+
        void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
                                 struct wpa_scan_results *scan_res);
        struct dl_list bss; /* struct wpa_bss::list */
@@ -366,6 +317,7 @@ struct wpa_supplicant {
 
        enum wpa_states wpa_state;
        int scanning;
+       int sched_scanning;
        int new_connection;
        int reassociated_connection;
 
@@ -383,11 +335,24 @@ struct wpa_supplicant {
        int scan_req; /* manual scan request; this forces a scan even if there
                       * are no enabled networks in the configuration */
        int scan_runs; /* number of scan runs since WPS was started */
+       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 */
 
-       struct wpa_client_mlme mlme;
        unsigned int drv_flags;
+
+       /*
+        * A bitmap of supported protocols for probe response offload. See
+        * struct wpa_driver_capa in driver.h
+        */
+       unsigned int probe_resp_offloads;
+
        int max_scan_ssids;
+       int max_sched_scan_ssids;
+       int sched_scan_supported;
+       unsigned int max_match_sets;
        unsigned int max_remain_on_chan;
+       unsigned int max_stations;
 
        int pending_mic_error_report;
        int pending_mic_error_pairwise;
@@ -404,12 +369,17 @@ struct wpa_supplicant {
 
        struct ibss_rsn *ibss_rsn;
 
+       int set_sta_uapsd;
+       int sta_uapsd;
+       int set_ap_uapsd;
+       int ap_uapsd;
+
 #ifdef CONFIG_SME
        struct {
                u8 ssid[32];
                size_t ssid_len;
                int freq;
-               u8 assoc_req_ie[80];
+               u8 assoc_req_ie[200];
                size_t assoc_req_ie_len;
                int mfp;
                int ft_used;
@@ -419,6 +389,15 @@ struct wpa_supplicant {
                u8 prev_bssid[ETH_ALEN];
                int prev_bssid_set;
                int auth_alg;
+               int proto;
+
+               int sa_query_count; /* number of pending SA Query requests;
+                                    * 0 = no SA Query in progress */
+               int sa_query_timed_out;
+               u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN *
+                                       * sa_query_count octets of pending
+                                       * SA Query transaction identifiers */
+               struct os_time sa_query_start;
        } sme;
 #endif /* CONFIG_SME */
 
@@ -429,19 +408,118 @@ struct wpa_supplicant {
        void *ap_configured_cb_data;
 #endif /* CONFIG_AP */
 
+       unsigned int off_channel_freq;
+       struct wpabuf *pending_action_tx;
+       u8 pending_action_src[ETH_ALEN];
+       u8 pending_action_dst[ETH_ALEN];
+       u8 pending_action_bssid[ETH_ALEN];
+       unsigned int pending_action_freq;
+       int pending_action_no_cck;
+       int pending_action_without_roc;
+       void (*pending_action_tx_status_cb)(struct wpa_supplicant *wpa_s,
+                                           unsigned int freq, const u8 *dst,
+                                           const u8 *src, const u8 *bssid,
+                                           const u8 *data, size_t data_len,
+                                           enum offchannel_send_action_result
+                                           result);
+       unsigned int roc_waiting_drv_freq;
+       int action_tx_wait_time;
+
+#ifdef CONFIG_P2P
+       struct p2p_go_neg_results *go_params;
+       int create_p2p_iface;
+       u8 pending_interface_addr[ETH_ALEN];
+       char pending_interface_name[100];
+       int pending_interface_type;
+       int p2p_group_idx;
+       unsigned int pending_listen_freq;
+       unsigned int pending_listen_duration;
+       enum {
+               NOT_P2P_GROUP_INTERFACE,
+               P2P_GROUP_INTERFACE_PENDING,
+               P2P_GROUP_INTERFACE_GO,
+               P2P_GROUP_INTERFACE_CLIENT
+       } p2p_group_interface;
+       struct p2p_group *p2p_group;
+       int p2p_long_listen; /* remaining time in long Listen state in ms */
+       char p2p_pin[10];
+       int p2p_wps_method;
+       u8 p2p_auth_invite[ETH_ALEN];
+       int p2p_sd_over_ctrl_iface;
+       int p2p_in_provisioning;
+       int pending_invite_ssid_id;
+       int show_group_started;
+       u8 go_dev_addr[ETH_ALEN];
+       int pending_pd_before_join;
+       u8 pending_join_iface_addr[ETH_ALEN];
+       u8 pending_join_dev_addr[ETH_ALEN];
+       int pending_join_wps_method;
+       int p2p_join_scan_count;
+       int force_long_sd;
+
+       /*
+        * Whether cross connection is disallowed by the AP to which this
+        * interface is associated (only valid if there is an association).
+        */
+       int cross_connect_disallowed;
+
+       /*
+        * Whether this P2P group is configured to use cross connection (only
+        * valid if this is P2P GO interface). The actual cross connect packet
+        * forwarding may not be configured depending on the uplink status.
+        */
+       int cross_connect_enabled;
+
+       /* Whether cross connection forwarding is in use at the moment. */
+       int cross_connect_in_use;
+
+       /*
+        * Uplink interface name for cross connection
+        */
+       char cross_connect_uplink[100];
+
+       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;
+#endif /* CONFIG_P2P */
+
        struct wpa_ssid *bgscan_ssid;
        const struct bgscan_ops *bgscan;
        void *bgscan_priv;
 
-       int connect_without_scan;
+       struct wpa_ssid *connect_without_scan;
 
        int after_wps;
        unsigned int wps_freq;
-       /*
-        * October 11st, 2011 TIZEN
-        * Workaround for timeout.
-        */
-       int associate_num;
+       int wps_fragment_size;
+       int auto_reconnect_disabled;
+
+        /* Channel preferences for AP/P2P GO use */
+       int best_24_freq;
+       int best_5_freq;
+       int best_overall_freq;
+
+       struct gas_query *gas;
+
+#ifdef CONFIG_INTERWORKING
+       unsigned int fetch_anqp_in_progress:1;
+       unsigned int network_select:1;
+       unsigned int auto_select:1;
+#endif /* CONFIG_INTERWORKING */
+       unsigned int drv_capa_known;
+
+       struct {
+               struct hostapd_hw_modes *modes;
+               u16 num_modes;
+               u16 flags;
+       } hw;
+
+       int pno;
 };
 
 
@@ -451,6 +529,7 @@ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
 int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s);
 
 const char * wpa_supplicant_state_txt(enum wpa_states state);
+int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s);
 int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s);
 int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                              struct wpa_bss *bss, struct wpa_ssid *ssid,
@@ -467,6 +546,7 @@ void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
 void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                              enum wpa_states state);
 struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s);
+const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
                                   int reason_code);
@@ -481,6 +561,10 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
                                   struct wpa_ssid *ssid);
 int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s,
                               int ap_scan);
+int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s,
+                                         unsigned int expire_age);
+int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s,
+                                           unsigned int expire_count);
 int wpa_supplicant_set_debug_params(struct wpa_global *global,
                                    int debug_level, int debug_timestamp,
                                    int debug_show_keys);
@@ -504,14 +588,30 @@ 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);
 
 /* events.c */
 void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s);
-void wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
-                           struct wpa_bss *selected,
-                           struct wpa_ssid *ssid);
+int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
+                          struct wpa_bss *selected,
+                          struct wpa_ssid *ssid);
+void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx);
+void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx);
 
 /* eap_register.c */
 int eap_register_methods(void);
 
+/**
+ * Utility method to tell if a given network is a persistent group
+ * @ssid: Network object
+ * Returns: 1 if network is a persistent group, 0 otherwise
+ */
+static inline int network_is_persistent_group(struct wpa_ssid *ssid)
+{
+       return ((ssid->disabled == 2) || ssid->p2p_persistent_group);
+}
+
 #endif /* WPA_SUPPLICANT_I_H */
index 4af0cd0..69b0cf8 100644 (file)
@@ -24,7 +24,6 @@
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
 #include "rsn_supp/pmksa_cache.h"
-#include "mlme.h"
 #include "sme.h"
 #include "common/ieee802_11_defs.h"
 #include "common/wpa_ctrl.h"
@@ -32,6 +31,7 @@
 #include "wps_supplicant.h"
 #include "bss.h"
 #include "scan.h"
+#include "notify.h"
 
 
 #ifndef CONFIG_NO_CONFIG_BLOBS
@@ -210,9 +210,8 @@ static int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx,
                        wpa_s->group_cipher = cipher;
        }
        return wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
-                              unicast ? wpa_s->bssid :
-                              (u8 *) "\xff\xff\xff\xff\xff\xff",
-                              keyidx, unicast, (u8 *) "", 0, key, keylen);
+                              unicast ? wpa_s->bssid : NULL,
+                              keyidx, unicast, NULL, 0, key, keylen);
 }
 
 
@@ -255,14 +254,29 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success,
                   "handshake");
 
        pmk_len = PMK_LEN;
-       res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
-       if (res) {
-               /*
-                * EAP-LEAP is an exception from other EAP methods: it
-                * uses only 16-byte PMK.
-                */
-               res = eapol_sm_get_key(eapol, pmk, 16);
-               pmk_len = 16;
+       if (wpa_key_mgmt_ft(wpa_s->key_mgmt)) {
+#ifdef CONFIG_IEEE80211R
+               u8 buf[2 * PMK_LEN];
+               wpa_printf(MSG_DEBUG, "RSN: Use FT XXKey as PMK for "
+                          "driver-based 4-way hs and FT");
+               res = eapol_sm_get_key(eapol, buf, 2 * PMK_LEN);
+               if (res == 0) {
+                       os_memcpy(pmk, buf + PMK_LEN, PMK_LEN);
+                       os_memset(buf, 0, sizeof(buf));
+               }
+#else /* CONFIG_IEEE80211R */
+               res = -1;
+#endif /* CONFIG_IEEE80211R */
+       } else {
+               res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
+               if (res) {
+                       /*
+                        * EAP-LEAP is an exception from other EAP methods: it
+                        * uses only 16-byte PMK.
+                        */
+                       res = eapol_sm_get_key(eapol, pmk, 16);
+                       pmk_len = 16;
+               }
        }
 
        if (res) {
@@ -271,6 +285,9 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success,
                return;
        }
 
+       wpa_hexdump_key(MSG_DEBUG, "RSN: Configure PMK for driver-based 4-way "
+                       "handshake", pmk, pmk_len);
+
        if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk,
                            pmk_len)) {
                wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver");
@@ -420,10 +437,6 @@ static void * wpa_supplicant_get_network_ctx(void *wpa_s)
 static int wpa_supplicant_get_bssid(void *ctx, u8 *bssid)
 {
        struct wpa_supplicant *wpa_s = ctx;
-       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
-               os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
-               return 0;
-       }
        return wpa_drv_get_bssid(wpa_s, bssid);
 }
 
@@ -471,8 +484,6 @@ static int wpa_supplicant_update_ft_ies(void *ctx, const u8 *md,
                                        const u8 *ies, size_t ies_len)
 {
        struct wpa_supplicant *wpa_s = ctx;
-       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-               return ieee80211_sta_update_ft_ies(wpa_s, md, ies, ies_len);
        if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
                return sme_update_ft_ies(wpa_s, md, ies, ies_len);
        return wpa_drv_update_ft_ies(wpa_s, md, ies, ies_len);
@@ -484,9 +495,6 @@ static int wpa_supplicant_send_ft_action(void *ctx, u8 action,
                                         const u8 *ies, size_t ies_len)
 {
        struct wpa_supplicant *wpa_s = ctx;
-       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-               return ieee80211_sta_send_ft_action(wpa_s, action, target_ap,
-                                                   ies, ies_len);
        return wpa_drv_send_ft_action(wpa_s, action, target_ap, ies, ies_len);
 }
 
@@ -497,9 +505,6 @@ static int wpa_supplicant_mark_authenticated(void *ctx, const u8 *target_ap)
        struct wpa_driver_auth_params params;
        struct wpa_bss *bss;
 
-       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-               return -1;
-
        bss = wpa_bss_get_bssid(wpa_s, target_ap);
        if (bss == NULL)
                return -1;
@@ -518,13 +523,142 @@ static int wpa_supplicant_mark_authenticated(void *ctx, const u8 *target_ap)
 #endif /* CONFIG_NO_WPA */
 
 
+#ifdef CONFIG_TDLS
+
+static int wpa_supplicant_tdls_get_capa(void *ctx, int *tdls_supported,
+                                       int *tdls_ext_setup)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       *tdls_supported = 0;
+       *tdls_ext_setup = 0;
+
+       if (!wpa_s->drv_capa_known)
+               return -1;
+
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)
+               *tdls_supported = 1;
+
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP)
+               *tdls_ext_setup = 1;
+
+       return 0;
+}
+
+
+static int wpa_supplicant_send_tdls_mgmt(void *ctx, const u8 *dst,
+                                        u8 action_code, u8 dialog_token,
+                                        u16 status_code, const u8 *buf,
+                                        size_t len)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       return wpa_drv_send_tdls_mgmt(wpa_s, dst, action_code, dialog_token,
+                                     status_code, buf, len);
+}
+
+
+static int wpa_supplicant_tdls_oper(void *ctx, int oper, const u8 *peer)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       return wpa_drv_tdls_oper(wpa_s, oper, peer);
+}
+
+
+static int wpa_supplicant_tdls_peer_addset(
+       void *ctx, const u8 *peer, int add, u16 capability,
+       const u8 *supp_rates, size_t supp_rates_len)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       struct hostapd_sta_add_params params;
+
+       params.addr = peer;
+       params.aid = 1;
+       params.capability = capability;
+       params.flags = WPA_STA_TDLS_PEER | WPA_STA_AUTHORIZED;
+       params.ht_capabilities = NULL;
+       params.listen_interval = 0;
+       params.supp_rates = supp_rates;
+       params.supp_rates_len = supp_rates_len;
+       params.set = !add;
+
+       return wpa_drv_sta_add(wpa_s, &params);
+}
+
+#endif /* CONFIG_TDLS */
+
+
+enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field)
+{
+       if (os_strcmp(field, "IDENTITY") == 0)
+               return WPA_CTRL_REQ_EAP_IDENTITY;
+       else if (os_strcmp(field, "PASSWORD") == 0)
+               return WPA_CTRL_REQ_EAP_PASSWORD;
+       else if (os_strcmp(field, "NEW_PASSWORD") == 0)
+               return WPA_CTRL_REQ_EAP_NEW_PASSWORD;
+       else if (os_strcmp(field, "PIN") == 0)
+               return WPA_CTRL_REQ_EAP_PIN;
+       else if (os_strcmp(field, "OTP") == 0)
+               return WPA_CTRL_REQ_EAP_OTP;
+       else if (os_strcmp(field, "PASSPHRASE") == 0)
+               return WPA_CTRL_REQ_EAP_PASSPHRASE;
+       return WPA_CTRL_REQ_UNKNOWN;
+}
+
+
+const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field,
+                                              const char *default_txt,
+                                              const char **txt)
+{
+       const char *ret = NULL;
+
+       *txt = default_txt;
+
+       switch (field) {
+       case WPA_CTRL_REQ_EAP_IDENTITY:
+               *txt = "Identity";
+               ret = "IDENTITY";
+               break;
+       case WPA_CTRL_REQ_EAP_PASSWORD:
+               *txt = "Password";
+               ret = "PASSWORD";
+               break;
+       case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
+               *txt = "New Password";
+               ret = "NEW_PASSWORD";
+               break;
+       case WPA_CTRL_REQ_EAP_PIN:
+               *txt = "PIN";
+               ret = "PIN";
+               break;
+       case WPA_CTRL_REQ_EAP_OTP:
+               ret = "OTP";
+               break;
+       case WPA_CTRL_REQ_EAP_PASSPHRASE:
+               *txt = "Private key passphrase";
+               ret = "PASSPHRASE";
+               break;
+       default:
+               break;
+       }
+
+       /* txt needs to be something */
+       if (*txt == NULL) {
+               wpa_printf(MSG_WARNING, "No message for request %d", field);
+               ret = NULL;
+       }
+
+       return ret;
+}
+
 #ifdef IEEE8021X_EAPOL
 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
-static void wpa_supplicant_eap_param_needed(void *ctx, const char *field,
-                                           const char *txt)
+static void wpa_supplicant_eap_param_needed(void *ctx,
+                                           enum wpa_ctrl_req_type field,
+                                           const char *default_txt)
 {
        struct wpa_supplicant *wpa_s = ctx;
        struct wpa_ssid *ssid = wpa_s->current_ssid;
+       const char *field_name, *txt = NULL;
        char *buf;
        size_t buflen;
        int len;
@@ -532,13 +666,23 @@ static void wpa_supplicant_eap_param_needed(void *ctx, const char *field,
        if (ssid == NULL)
                return;
 
+       wpas_notify_network_request(wpa_s, ssid, field, default_txt);
+
+       field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt,
+                                                      &txt);
+       if (field_name == NULL) {
+               wpa_printf(MSG_WARNING, "Unhandled EAP param %d needed",
+                          field);
+               return;
+       }
+
        buflen = 100 + os_strlen(txt) + ssid->ssid_len;
        buf = os_malloc(buflen);
        if (buf == NULL)
                return;
        len = os_snprintf(buf, buflen,
                          WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
-                         field, ssid->id, txt);
+                         field_name, ssid->id, txt);
        if (len < 0 || (size_t) len >= buflen) {
                os_free(buf);
                return;
@@ -572,6 +716,16 @@ static void wpa_supplicant_port_cb(void *ctx, int authorized)
                   authorized ? "Authorized" : "Unauthorized");
        wpa_drv_set_supp_port(wpa_s, authorized);
 }
+
+
+static void wpa_supplicant_cert_cb(void *ctx, int depth, const char *subject,
+                                  const char *cert_hash,
+                                  const struct wpabuf *cert)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       wpas_notify_certification(wpa_s, depth, subject, cert_hash, cert);
+}
 #endif /* IEEE8021X_EAPOL */
 
 
@@ -602,6 +756,7 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
        ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
        ctx->port_cb = wpa_supplicant_port_cb;
        ctx->cb = wpa_supplicant_eapol_cb;
+       ctx->cert_cb = wpa_supplicant_cert_cb;
        ctx->cb_ctx = wpa_s;
        wpa_s->eapol = eapol_sm_init(ctx);
        if (wpa_s->eapol == NULL) {
@@ -616,6 +771,16 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
 }
 
 
+static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek,
+                                            const u8 *kck,
+                                            const u8 *replay_ctr)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       wpa_drv_set_rekey_info(wpa_s, kek, kck, replay_ctr);
+}
+
+
 int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
 {
 #ifndef CONFIG_NO_WPA
@@ -651,6 +816,13 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
        ctx->send_ft_action = wpa_supplicant_send_ft_action;
        ctx->mark_authenticated = wpa_supplicant_mark_authenticated;
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_TDLS
+       ctx->tdls_get_capa = wpa_supplicant_tdls_get_capa;
+       ctx->send_tdls_mgmt = wpa_supplicant_send_tdls_mgmt;
+       ctx->tdls_oper = wpa_supplicant_tdls_oper;
+       ctx->tdls_peer_addset = wpa_supplicant_tdls_peer_addset;
+#endif /* CONFIG_TDLS */
+       ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload;
 
        wpa_s->wpa = wpa_sm_init(ctx);
        if (wpa_s->wpa == NULL) {
@@ -674,6 +846,7 @@ 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.eap_workaround = ssid->eap_workaround;
                conf.eap_conf_ctx = &ssid->eap;
 #endif /* IEEE8021X_EAPOL */
index b571e4d..78c1b3d 100644 (file)
 #ifndef WPAS_GLUE_H
 #define WPAS_GLUE_H
 
+enum wpa_ctrl_req_type;
+
 int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s);
 int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
                                        struct wpa_ssid *ssid);
 
+const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field,
+                                              const char *default_txt,
+                                              const char **txt);
+
+enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field);
+
 #endif /* WPAS_GLUE_H */
index ba94d33..870aff5 100644 (file)
@@ -24,6 +24,7 @@
 #include "common/wpa_ctrl.h"
 #include "eap_common/eap_wsc_common.h"
 #include "eap_peer/eap.h"
+#include "eapol_supp/eapol_supp_sm.h"
 #include "rsn_supp/wpa.h"
 #include "config.h"
 #include "wpa_supplicant_i.h"
 #include "blacklist.h"
 #include "bss.h"
 #include "scan.h"
+#include "ap.h"
+#include "p2p/p2p.h"
+#include "p2p_supplicant.h"
 #include "wps_supplicant.h"
 
 
+#ifndef WPS_PIN_SCAN_IGNORE_SEL_REG
 #define WPS_PIN_SCAN_IGNORE_SEL_REG 3
+#endif /* WPS_PIN_SCAN_IGNORE_SEL_REG */
 
 static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx);
 static void wpas_clear_wps(struct wpa_supplicant *wpa_s);
@@ -65,15 +71,24 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
        }
 
        eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+       if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && !wpa_s->wps_success)
+               wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL);
 
        if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid &&
            !(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+               int disabled = wpa_s->current_ssid->disabled;
                wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
                           "try to associate with the received credential");
                wpa_supplicant_deauthenticate(wpa_s,
                                              WLAN_REASON_DEAUTH_LEAVING);
+               if (disabled) {
+                       wpa_printf(MSG_DEBUG, "WPS: Current network is "
+                                  "disabled - wait for user to enable");
+                       return 1;
+               }
                wpa_s->after_wps = 5;
                wpa_s->wps_freq = wpa_s->assoc_freq;
+               wpa_s->normal_scans = 0;
                wpa_s->reassociate = 1;
                wpa_supplicant_req_scan(wpa_s, 0, 0);
                return 1;
@@ -113,6 +128,8 @@ static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s,
        if (wpa_drv_get_capa(wpa_s, &capa))
                return; /* Unknown what driver supports */
 
+       if (ssid->ssid == NULL)
+               return;
        bss = wpa_bss_get(wpa_s, cred->mac_addr, ssid->ssid, ssid->ssid_len);
        if (bss == NULL) {
                wpa_printf(MSG_DEBUG, "WPS: The AP was not found from BSS "
@@ -178,6 +195,9 @@ static int wpa_supplicant_wps_cred(void *ctx,
        struct wpa_ssid *ssid = wpa_s->current_ssid;
        u8 key_idx = 0;
        u16 auth_type;
+#ifdef CONFIG_WPS_REG_DISABLE_OPEN
+       int registrar = 0;
+#endif /* CONFIG_WPS_REG_DISABLE_OPEN */
 
        if ((wpa_s->conf->wps_cred_processing == 1 ||
             wpa_s->conf->wps_cred_processing == 2) && cred->cred_attr) {
@@ -231,6 +251,13 @@ static int wpa_supplicant_wps_cred(void *ctx,
        if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
                wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
                           "on the received credential");
+#ifdef CONFIG_WPS_REG_DISABLE_OPEN
+               if (ssid->eap.identity &&
+                   ssid->eap.identity_len == WSC_ID_REGISTRAR_LEN &&
+                   os_memcmp(ssid->eap.identity, WSC_ID_REGISTRAR,
+                             WSC_ID_REGISTRAR_LEN) == 0)
+                       registrar = 1;
+#endif /* CONFIG_WPS_REG_DISABLE_OPEN */
                os_free(ssid->eap.identity);
                ssid->eap.identity = NULL;
                ssid->eap.identity_len = 0;
@@ -238,6 +265,8 @@ 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)
+                       ssid->temporary = 0;
        } else {
                wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
                           "received credential");
@@ -304,6 +333,16 @@ static int wpa_supplicant_wps_cred(void *ctx,
                ssid->auth_alg = WPA_AUTH_ALG_OPEN;
                ssid->key_mgmt = WPA_KEY_MGMT_NONE;
                ssid->proto = 0;
+#ifdef CONFIG_WPS_REG_DISABLE_OPEN
+               if (registrar) {
+                       wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OPEN_NETWORK
+                               "id=%d - Credentials for an open "
+                               "network disabled by default - use "
+                               "'select_network %d' to enable",
+                               ssid->id, ssid->id);
+                       ssid->disabled = 1;
+               }
+#endif /* CONFIG_WPS_REG_DISABLE_OPEN */
                break;
        case WPS_AUTH_SHARED:
                ssid->auth_alg = WPA_AUTH_ALG_SHARED;
@@ -341,6 +380,7 @@ static int wpa_supplicant_wps_cred(void *ctx,
                                return -1;
                        }
                        ssid->psk_set = 1;
+                       ssid->export_keys = 1;
                } else if (cred->key_len >= 8 && cred->key_len < 2 * PMK_LEN) {
                        os_free(ssid->passphrase);
                        ssid->passphrase = os_malloc(cred->key_len + 1);
@@ -349,6 +389,7 @@ static int wpa_supplicant_wps_cred(void *ctx,
                        os_memcpy(ssid->passphrase, cred->key, cred->key_len);
                        ssid->passphrase[cred->key_len] = '\0';
                        wpa_config_update_psk(ssid);
+                       ssid->export_keys = 1;
                } else {
                        wpa_printf(MSG_ERROR, "WPS: Invalid Network Key "
                                   "length %lu",
@@ -371,6 +412,15 @@ static int wpa_supplicant_wps_cred(void *ctx,
 }
 
 
+#ifdef CONFIG_P2P
+static void wpas_wps_pbc_overlap_cb(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       wpas_p2p_notif_pbc_overlap(wpa_s);
+}
+#endif /* CONFIG_P2P */
+
+
 static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s,
                                         struct wps_event_m2d *m2d)
 {
@@ -378,15 +428,59 @@ static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s,
                "dev_password_id=%d config_error=%d",
                m2d->dev_password_id, m2d->config_error);
        wpas_notify_wps_event_m2d(wpa_s, m2d);
+#ifdef CONFIG_P2P
+       if (wpa_s->parent && wpa_s->parent != wpa_s) {
+               wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_M2D
+                       "dev_password_id=%d config_error=%d",
+                       m2d->dev_password_id, m2d->config_error);
+       }
+       if (m2d->config_error == WPS_CFG_MULTIPLE_PBC_DETECTED) {
+               /*
+                * Notify P2P from eloop timeout to avoid issues with the
+                * interface getting removed while processing a message.
+                */
+               eloop_register_timeout(0, 0, wpas_wps_pbc_overlap_cb, wpa_s,
+                                      NULL);
+       }
+#endif /* CONFIG_P2P */
 }
 
 
+static const char * wps_event_fail_reason[NUM_WPS_EI_VALUES] = {
+       "No Error", /* WPS_EI_NO_ERROR */
+       "TKIP Only Prohibited", /* WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED */
+       "WEP Prohibited" /* WPS_EI_SECURITY_WEP_PROHIBITED */
+};
+
 static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
                                          struct wps_event_fail *fail)
 {
-       wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL "msg=%d", fail->msg);
+       if (fail->error_indication > 0 &&
+           fail->error_indication < NUM_WPS_EI_VALUES) {
+               wpa_msg(wpa_s, MSG_INFO,
+                       WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)",
+                       fail->msg, fail->config_error, fail->error_indication,
+                       wps_event_fail_reason[fail->error_indication]);
+               if (wpa_s->parent && wpa_s->parent != wpa_s)
+                       wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+                               "msg=%d config_error=%d reason=%d (%s)",
+                               fail->msg, fail->config_error,
+                               fail->error_indication,
+                               wps_event_fail_reason[fail->error_indication]);
+       } else {
+               wpa_msg(wpa_s, MSG_INFO,
+                       WPS_EVENT_FAIL "msg=%d config_error=%d",
+                       fail->msg, fail->config_error);
+               if (wpa_s->parent && wpa_s->parent != wpa_s)
+                       wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+                               "msg=%d config_error=%d",
+                               fail->msg, fail->config_error);
+       }
        wpas_clear_wps(wpa_s);
        wpas_notify_wps_event_fail(wpa_s, fail);
+#ifdef CONFIG_P2P
+       wpas_p2p_wps_failed(wpa_s, fail);
+#endif /* CONFIG_P2P */
 }
 
 
@@ -395,6 +489,9 @@ 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);
+#ifdef CONFIG_P2P
+       wpas_p2p_wps_success(wpa_s, wpa_s->bssid, 0);
+#endif /* CONFIG_P2P */
 }
 
 
@@ -468,6 +565,59 @@ static void wpa_supplicant_wps_event_er_enrollee_remove(
 }
 
 
+static void wpa_supplicant_wps_event_er_ap_settings(
+       struct wpa_supplicant *wpa_s,
+       struct wps_event_er_ap_settings *ap_settings)
+{
+       char uuid_str[100];
+       char key_str[65];
+       const struct wps_credential *cred = ap_settings->cred;
+
+       key_str[0] = '\0';
+       if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
+               if (cred->key_len >= 8 && cred->key_len <= 64) {
+                       os_memcpy(key_str, cred->key, cred->key_len);
+                       key_str[cred->key_len] = '\0';
+               }
+       }
+
+       uuid_bin2str(ap_settings->uuid, uuid_str, sizeof(uuid_str));
+       /* Use wpa_msg_ctrl to avoid showing the key in debug log */
+       wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_SETTINGS
+                    "uuid=%s ssid=%s auth_type=0x%04x encr_type=0x%04x "
+                    "key=%s",
+                    uuid_str, wpa_ssid_txt(cred->ssid, cred->ssid_len),
+                    cred->auth_type, cred->encr_type, key_str);
+}
+
+
+static void wpa_supplicant_wps_event_er_set_sel_reg(
+       struct wpa_supplicant *wpa_s,
+       struct wps_event_er_set_selected_registrar *ev)
+{
+       char uuid_str[100];
+
+       uuid_bin2str(ev->uuid, uuid_str, sizeof(uuid_str));
+       switch (ev->state) {
+       case WPS_ER_SET_SEL_REG_START:
+               wpa_msg(wpa_s, MSG_DEBUG, WPS_EVENT_ER_SET_SEL_REG
+                       "uuid=%s state=START sel_reg=%d dev_passwd_id=%u "
+                       "sel_reg_config_methods=0x%x",
+                       uuid_str, ev->sel_reg, ev->dev_passwd_id,
+                       ev->sel_reg_config_methods);
+               break;
+       case WPS_ER_SET_SEL_REG_DONE:
+               wpa_msg(wpa_s, MSG_DEBUG, WPS_EVENT_ER_SET_SEL_REG
+                       "uuid=%s state=DONE", uuid_str);
+               break;
+       case WPS_ER_SET_SEL_REG_FAILED:
+               wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_SET_SEL_REG
+                       "uuid=%s state=FAILED", uuid_str);
+               break;
+       }
+}
+
+
 static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
                                     union wps_event_data *data)
 {
@@ -483,6 +633,10 @@ static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
                wpa_supplicant_wps_event_success(wpa_s);
                break;
        case WPS_EV_PWD_AUTH_FAIL:
+#ifdef CONFIG_AP
+               if (wpa_s->ap_iface && data->pwd_auth_fail.enrollee)
+                       wpa_supplicant_ap_pwd_auth_fail(wpa_s);
+#endif /* CONFIG_AP */
                break;
        case WPS_EV_PBC_OVERLAP:
                break;
@@ -502,6 +656,14 @@ static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
                wpa_supplicant_wps_event_er_enrollee_remove(wpa_s,
                                                            &data->enrollee);
                break;
+       case WPS_EV_ER_AP_SETTINGS:
+               wpa_supplicant_wps_event_er_ap_settings(wpa_s,
+                                                       &data->ap_settings);
+               break;
+       case WPS_EV_ER_SET_SELECTED_REGISTRAR:
+               wpa_supplicant_wps_event_er_set_sel_reg(wpa_s,
+                                                       &data->set_sel_reg);
+               break;
        }
 }
 
@@ -519,7 +681,9 @@ enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid)
 static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
 {
        int id;
-       struct wpa_ssid *ssid, *remove_ssid = NULL;
+       struct wpa_ssid *ssid, *remove_ssid = NULL, *prev_current;
+
+       prev_current = wpa_s->current_ssid;
 
        eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
 
@@ -538,6 +702,11 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
                        id = -1;
                ssid = ssid->next;
                if (id >= 0) {
+                       if (prev_current == remove_ssid) {
+                               wpa_sm_set_config(wpa_s->wpa, NULL);
+                               eapol_sm_notify_config(wpa_s->eapol, NULL,
+                                                      NULL);
+                       }
                        wpas_notify_network_removed(wpa_s, remove_ssid);
                        wpa_config_remove_network(wpa_s->conf, id);
                }
@@ -548,8 +717,8 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
 static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx)
 {
        struct wpa_supplicant *wpa_s = eloop_ctx;
-       wpa_printf(MSG_INFO, WPS_EVENT_TIMEOUT "Requested operation timed "
-                  "out");
+       wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_TIMEOUT "Requested operation timed "
+               "out");
        wpas_clear_wps(wpa_s);
 }
 
@@ -564,6 +733,7 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
                return NULL;
        wpas_notify_network_added(wpa_s, ssid);
        wpa_config_set_network_defaults(ssid);
+       ssid->temporary = 1;
        if (wpa_config_set(ssid, "key_mgmt", "WPS", 0) < 0 ||
            wpa_config_set(ssid, "eap", "WSC", 0) < 0 ||
            wpa_config_set(ssid, "identity", registrar ?
@@ -575,12 +745,20 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
        }
 
        if (bssid) {
+#ifndef CONFIG_P2P
                struct wpa_bss *bss;
                int count = 0;
+#endif /* CONFIG_P2P */
 
                os_memcpy(ssid->bssid, bssid, ETH_ALEN);
                ssid->bssid_set = 1;
 
+               /*
+                * Note: With P2P, the SSID may change at the time the WPS
+                * provisioning is started, so better not filter the AP based
+                * on the current SSID in the scan results.
+                */
+#ifndef CONFIG_P2P
                dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
                        if (os_memcmp(bssid, bss->bssid, ETH_ALEN) != 0)
                                continue;
@@ -604,6 +782,7 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
                        ssid->ssid = NULL;
                        ssid->ssid_len = 0;
                }
+#endif /* CONFIG_P2P */
        }
 
        return ssid;
@@ -615,32 +794,63 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
 {
        struct wpa_ssid *ssid;
 
+       if (wpa_s->current_ssid)
+               wpa_supplicant_deauthenticate(
+                       wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+
        /* Mark all other networks disabled and trigger reassociation */
        ssid = wpa_s->conf->ssid;
        while (ssid) {
                int was_disabled = ssid->disabled;
-               ssid->disabled = ssid != selected;
-               if (was_disabled != ssid->disabled)
-                       wpas_notify_network_enabled_changed(wpa_s, ssid);
+               /*
+                * In case the network object corresponds to a persistent group
+                * then do not send out network disabled signal. In addition,
+                * do not change disabled status of persistent network objects
+                * from 2 to 1 should we connect to another network.
+                */
+               if (was_disabled != 2) {
+                       ssid->disabled = ssid != selected;
+                       if (was_disabled != ssid->disabled)
+                               wpas_notify_network_enabled_changed(wpa_s,
+                                                                   ssid);
+               }
                ssid = ssid->next;
        }
        wpa_s->disconnected = 0;
        wpa_s->reassociate = 1;
        wpa_s->scan_runs = 0;
+       wpa_s->normal_scans = 0;
        wpa_s->wps_success = 0;
        wpa_s->blacklist_cleared = 0;
        wpa_supplicant_req_scan(wpa_s, 0, 0);
 }
 
 
-int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid)
+int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
+                      int p2p_group)
 {
        struct wpa_ssid *ssid;
        wpas_clear_wps(wpa_s);
        ssid = wpas_wps_add_network(wpa_s, 0, bssid);
        if (ssid == NULL)
                return -1;
+       ssid->temporary = 1;
+       ssid->p2p_group = p2p_group;
+#ifdef CONFIG_P2P
+       if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) {
+               ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1);
+               if (ssid->ssid) {
+                       ssid->ssid_len = wpa_s->go_params->ssid_len;
+                       os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
+                                 ssid->ssid_len);
+                       wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
+                                         "SSID", ssid->ssid, ssid->ssid_len);
+               }
+       }
+#endif /* CONFIG_P2P */
        wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0);
+       if (wpa_s->wps_fragment_size)
+               ssid->eap.fragment_size = wpa_s->wps_fragment_size;
        eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
                               wpa_s, NULL);
        wpas_wps_reassoc(wpa_s, ssid);
@@ -649,7 +859,7 @@ 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)
+                      const char *pin, int p2p_group, u16 dev_pw_id)
 {
        struct wpa_ssid *ssid;
        char val[128];
@@ -659,13 +869,31 @@ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
        ssid = wpas_wps_add_network(wpa_s, 0, bssid);
        if (ssid == NULL)
                return -1;
+       ssid->temporary = 1;
+       ssid->p2p_group = p2p_group;
+#ifdef CONFIG_P2P
+       if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) {
+               ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1);
+               if (ssid->ssid) {
+                       ssid->ssid_len = wpa_s->go_params->ssid_len;
+                       os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
+                                 ssid->ssid_len);
+                       wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
+                                         "SSID", ssid->ssid, ssid->ssid_len);
+               }
+       }
+#endif /* CONFIG_P2P */
        if (pin)
-               os_snprintf(val, sizeof(val), "\"pin=%s\"", pin);
+               os_snprintf(val, sizeof(val), "\"pin=%s dev_pw_id=%u\"",
+                           pin, dev_pw_id);
        else {
                rpin = wps_generate_pin();
-               os_snprintf(val, sizeof(val), "\"pin=%08d\"", rpin);
+               os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u\"",
+                           rpin, dev_pw_id);
        }
        wpa_config_set(ssid, "phase1", val, 0);
+       if (wpa_s->wps_fragment_size)
+               ssid->eap.fragment_size = wpa_s->wps_fragment_size;
        eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
                               wpa_s, NULL);
        wpas_wps_reassoc(wpa_s, ssid);
@@ -673,6 +901,32 @@ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
 }
 
 
+/* Cancel the wps pbc/pin requests */
+int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_AP
+       if (wpa_s->ap_iface) {
+               wpa_printf(MSG_DEBUG, "WPS: Cancelling in AP mode");
+               return wpa_supplicant_ap_wps_cancel(wpa_s);
+       }
+#endif /* CONFIG_AP */
+
+       if (wpa_s->wpa_state == WPA_SCANNING) {
+               wpa_printf(MSG_DEBUG, "WPS: Cancel operation - cancel scan");
+               wpa_supplicant_cancel_scan(wpa_s);
+               wpas_clear_wps(wpa_s);
+       } else if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
+               wpa_printf(MSG_DEBUG, "WPS: Cancel operation - "
+                          "deauthenticate");
+               wpa_supplicant_deauthenticate(wpa_s,
+                                             WLAN_REASON_DEAUTH_LEAVING);
+               wpas_clear_wps(wpa_s);
+       }
+
+       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)
@@ -715,7 +969,8 @@ int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type,
        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)
+                              wpabuf_head(wps->oob_conf.dev_password), 0,
+                              DEV_PW_DEFAULT) < 0)
                        return -1;
 
        return 0;
@@ -737,6 +992,7 @@ int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
        ssid = wpas_wps_add_network(wpa_s, 1, bssid);
        if (ssid == NULL)
                return -1;
+       ssid->temporary = 1;
        pos = val;
        end = pos + sizeof(val);
        res = os_snprintf(pos, end - pos, "\"pin=%s", pin);
@@ -756,6 +1012,8 @@ int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
        if (res < 0 || res >= end - pos)
                return -1;
        wpa_config_set(ssid, "phase1", val, 0);
+       if (wpa_s->wps_fragment_size)
+               ssid->eap.fragment_size = wpa_s->wps_fragment_size;
        eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
                               wpa_s, NULL);
        wpas_wps_reassoc(wpa_s, ssid);
@@ -805,16 +1063,71 @@ static void wpas_wps_set_sel_reg_cb(void *ctx, int sel_reg, u16 dev_passwd_id,
 
        if (wpa_s->wps_er == NULL)
                return;
+       wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar - sel_reg=%d "
+                  "dev_password_id=%u sel_reg_config_methods=0x%x",
+                  sel_reg, dev_passwd_id, sel_reg_config_methods);
        wps_er_set_sel_reg(wpa_s->wps_er, sel_reg, dev_passwd_id,
                           sel_reg_config_methods);
 #endif /* CONFIG_WPS_ER */
 }
 
 
+static u16 wps_fix_config_methods(u16 config_methods)
+{
+#ifdef CONFIG_WPS2
+       if ((config_methods &
+            (WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY |
+             WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) {
+               wpa_printf(MSG_INFO, "WPS: Converting display to "
+                          "virtual_display for WPS 2.0 compliance");
+               config_methods |= WPS_CONFIG_VIRT_DISPLAY;
+       }
+       if ((config_methods &
+            (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON |
+             WPS_CONFIG_PHY_PUSHBUTTON)) == WPS_CONFIG_PUSHBUTTON) {
+               wpa_printf(MSG_INFO, "WPS: Converting push_button to "
+                          "virtual_push_button for WPS 2.0 compliance");
+               config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
+       }
+#endif /* CONFIG_WPS2 */
+
+       return config_methods;
+}
+
+
+static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s,
+                             struct wps_context *wps)
+{
+       wpa_printf(MSG_DEBUG, "WPS: Set UUID for interface %s", wpa_s->ifname);
+       if (is_nil_uuid(wpa_s->conf->uuid)) {
+               struct wpa_supplicant *first;
+               first = wpa_s->global->ifaces;
+               while (first && first->next)
+                       first = first->next;
+               if (first && first != wpa_s) {
+                       os_memcpy(wps->uuid, wpa_s->global->ifaces->wps->uuid,
+                                 WPS_UUID_LEN);
+                       wpa_hexdump(MSG_DEBUG, "WPS: UUID from the first "
+                                   "interface", wps->uuid, WPS_UUID_LEN);
+               } else {
+                       uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid);
+                       wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC "
+                                   "address", wps->uuid, WPS_UUID_LEN);
+               }
+       } else {
+               os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
+               wpa_hexdump(MSG_DEBUG, "WPS: UUID based on configuration",
+                           wps->uuid, WPS_UUID_LEN);
+       }
+}
+
+
 int wpas_wps_init(struct wpa_supplicant *wpa_s)
 {
        struct wps_context *wps;
        struct wps_registrar_config rcfg;
+       struct hostapd_hw_modes *modes;
+       u16 m;
 
        wps = os_zalloc(sizeof(*wps));
        if (wps == NULL)
@@ -831,22 +1144,42 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
        wps->dev.serial_number = wpa_s->conf->serial_number;
        wps->config_methods =
                wps_config_methods_str2bin(wpa_s->conf->config_methods);
-       if (wpa_s->conf->device_type &&
-           wps_dev_type_str2bin(wpa_s->conf->device_type,
-                                wps->dev.pri_dev_type) < 0) {
-               wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
+       if ((wps->config_methods & (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) ==
+           (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) {
+               wpa_printf(MSG_ERROR, "WPS: Both Label and Display config "
+                          "methods are not allowed at the same time");
                os_free(wps);
                return -1;
        }
+       wps->config_methods = wps_fix_config_methods(wps->config_methods);
+       wps->dev.config_methods = wps->config_methods;
+       os_memcpy(wps->dev.pri_dev_type, wpa_s->conf->device_type,
+                 WPS_DEV_TYPE_LEN);
+
+       wps->dev.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
+       os_memcpy(wps->dev.sec_dev_type, wpa_s->conf->sec_device_type,
+                 WPS_DEV_TYPE_LEN * wps->dev.num_sec_dev_types);
+
        wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
-       wps->dev.rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ; /* TODO: config */
+       modes = wpa_s->hw.modes;
+       if (modes) {
+               for (m = 0; m < wpa_s->hw.num_modes; m++) {
+                       if (modes[m].mode == HOSTAPD_MODE_IEEE80211B ||
+                           modes[m].mode == HOSTAPD_MODE_IEEE80211G)
+                               wps->dev.rf_bands |= WPS_RF_24GHZ;
+                       else if (modes[m].mode == HOSTAPD_MODE_IEEE80211A)
+                               wps->dev.rf_bands |= WPS_RF_50GHZ;
+               }
+       }
+       if (wps->dev.rf_bands == 0) {
+               /*
+                * Default to claiming support for both bands if the driver
+                * does not provide support for fetching supported bands.
+                */
+               wps->dev.rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ;
+       }
        os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN);
-       if (is_nil_uuid(wpa_s->conf->uuid)) {
-               uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid);
-               wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC address",
-                           wps->uuid, WPS_UUID_LEN);
-       } else
-               os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
+       wpas_wps_set_uuid(wpa_s, wps);
 
        wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
        wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
@@ -929,12 +1262,13 @@ int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
                }
 
                /*
-                * Start with WPS APs that advertise active PIN Registrar and
-                * allow any WPS AP after third scan since some APs do not set
-                * Selected Registrar attribute properly when using external
-                * Registrar.
+                * Start with WPS APs that advertise our address as an
+                * authorized MAC (v2.0) or active PIN Registrar (v1.0) and
+                * allow any WPS AP after couple of scans since some APs do not
+                * set Selected Registrar attribute properly when using
+                * external Registrar.
                 */
-               if (!wps_is_selected_pin_registrar(wps_ie)) {
+               if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) {
                        if (wpa_s->scan_runs < WPS_PIN_SCAN_IGNORE_SEL_REG) {
                                wpa_printf(MSG_DEBUG, "   skip - WPS AP "
                                           "without active PIN Registrar");
@@ -944,7 +1278,7 @@ int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
                        wpa_printf(MSG_DEBUG, "   selected based on WPS IE");
                } else {
                        wpa_printf(MSG_DEBUG, "   selected based on WPS IE "
-                                  "(Active PIN)");
+                                  "(Authorized MAC or Active PIN)");
                }
                wpabuf_free(wps_ie);
                return 1;
@@ -976,7 +1310,7 @@ int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
        } else if (eap_is_wps_pin_enrollee(&ssid->eap)) {
                wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
                if (wps_ie &&
-                   (wps_is_selected_pin_registrar(wps_ie) ||
+                   (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1) ||
                     wpa_s->scan_runs >= WPS_PIN_SCAN_IGNORE_SEL_REG)) {
                        /* allow wildcard SSID for WPS PIN */
                        ret = 1;
@@ -989,6 +1323,28 @@ int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
                ret = 1;
        }
 
+#ifdef CONFIG_WPS_STRICT
+       if (wps_ie) {
+               if (wps_validate_beacon_probe_resp(wps_ie, bss->beacon_ie_len >
+                                                  0, bss->bssid) < 0)
+                       ret = 0;
+               if (bss->beacon_ie_len) {
+                       struct wpabuf *bcn_wps;
+                       bcn_wps = wpa_scan_get_vendor_ie_multi_beacon(
+                               bss, WPS_IE_VENDOR_TYPE);
+                       if (bcn_wps == NULL) {
+                               wpa_printf(MSG_DEBUG, "WPS: Mandatory WPS IE "
+                                          "missing from AP Beacon");
+                               ret = 0;
+                       } else {
+                               if (wps_validate_beacon(wps_ie) < 0)
+                                       ret = 0;
+                               wpabuf_free(bcn_wps);
+                       }
+               }
+       }
+#endif /* CONFIG_WPS_STRICT */
+
        wpabuf_free(wps_ie);
 
        return ret;
@@ -1006,12 +1362,21 @@ int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
        if (!eap_is_wps_pbc_enrollee(&ssid->eap))
                return 0;
 
+       wpa_printf(MSG_DEBUG, "WPS: Check whether PBC session overlap is "
+                  "present in scan results; selected BSSID " MACSTR,
+                  MAC2STR(selected->bssid));
+
        /* Make sure that only one AP is in active PBC mode */
        wps_ie = wpa_bss_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE);
-       if (wps_ie)
+       if (wps_ie) {
                sel_uuid = wps_get_uuid_e(wps_ie);
-       else
+               wpa_hexdump(MSG_DEBUG, "WPS: UUID of the selected BSS",
+                           sel_uuid, UUID_LEN);
+       } else {
+               wpa_printf(MSG_DEBUG, "WPS: Selected BSS does not include "
+                          "WPS IE?!");
                sel_uuid = NULL;
+       }
 
        dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
                struct wpabuf *ie;
@@ -1024,10 +1389,18 @@ int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
                        wpabuf_free(ie);
                        continue;
                }
+               wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: "
+                          MACSTR, MAC2STR(bss->bssid));
                uuid = wps_get_uuid_e(ie);
+               wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",
+                           uuid, UUID_LEN);
                if (sel_uuid == NULL || uuid == NULL ||
-                   os_memcmp(sel_uuid, uuid, 16) != 0) {
+                   os_memcmp(sel_uuid, uuid, UUID_LEN) != 0) {
                        ret = 1; /* PBC overlap */
+                       wpa_msg(wpa_s, MSG_INFO, "WPS: PBC overlap detected: "
+                               MACSTR " and " MACSTR,
+                               MAC2STR(selected->bssid),
+                               MAC2STR(bss->bssid));
                        wpabuf_free(ie);
                        break;
                }
@@ -1046,6 +1419,7 @@ int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
 void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s)
 {
        struct wpa_bss *bss;
+       unsigned int pbc = 0, auth = 0, pin = 0, wps = 0;
 
        if (wpa_s->disconnected || wpa_s->wpa_state >= WPA_ASSOCIATED)
                return;
@@ -1056,17 +1430,24 @@ void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s)
                if (!ie)
                        continue;
                if (wps_is_selected_pbc_registrar(ie))
-                       wpa_msg_ctrl(wpa_s, MSG_INFO,
-                                    WPS_EVENT_AP_AVAILABLE_PBC);
+                       pbc++;
+               else if (wps_is_addr_authorized(ie, wpa_s->own_addr, 0))
+                       auth++;
                else if (wps_is_selected_pin_registrar(ie))
-                       wpa_msg_ctrl(wpa_s, MSG_INFO,
-                                    WPS_EVENT_AP_AVAILABLE_PIN);
+                       pin++;
                else
-                       wpa_msg_ctrl(wpa_s, MSG_INFO,
-                                    WPS_EVENT_AP_AVAILABLE);
+                       wps++;
                wpabuf_free(ie);
-               break;
        }
+
+       if (pbc)
+               wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PBC);
+       else if (auth)
+               wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_AUTH);
+       else if (pin)
+               wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PIN);
+       else if (wps)
+               wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE);
 }
 
 
@@ -1099,14 +1480,14 @@ int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
 }
 
 
-int wpas_wps_er_start(struct wpa_supplicant *wpa_s)
+int wpas_wps_er_start(struct wpa_supplicant *wpa_s, const char *filter)
 {
 #ifdef CONFIG_WPS_ER
        if (wpa_s->wps_er) {
                wps_er_refresh(wpa_s->wps_er);
                return 0;
        }
-       wpa_s->wps_er = wps_er_init(wpa_s->wps, wpa_s->ifname);
+       wpa_s->wps_er = wps_er_init(wpa_s->wps, wpa_s->ifname, filter);
        if (wpa_s->wps_er == NULL)
                return -1;
        return 0;
@@ -1127,8 +1508,8 @@ int wpas_wps_er_stop(struct wpa_supplicant *wpa_s)
 
 
 #ifdef CONFIG_WPS_ER
-int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const char *uuid,
-                       const char *pin)
+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;
@@ -1137,7 +1518,8 @@ int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const char *uuid,
                any = 1;
        else if (uuid_str2bin(uuid, u))
                return -1;
-       return wps_registrar_add_pin(wpa_s->wps->registrar, any ? NULL : u,
+       return wps_registrar_add_pin(wpa_s->wps->registrar, addr,
+                                    any ? NULL : u,
                                     (const u8 *) pin, os_strlen(pin), 300);
 }
 
@@ -1164,10 +1546,107 @@ int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid,
 }
 
 
+int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
+                          int id)
+{
+       u8 u[UUID_LEN];
+       struct wpa_ssid *ssid;
+       struct wps_credential cred;
+
+       if (uuid_str2bin(uuid, u))
+               return -1;
+       ssid = wpa_config_get_network(wpa_s->conf, id);
+       if (ssid == NULL || ssid->ssid == NULL)
+               return -1;
+
+       os_memset(&cred, 0, sizeof(cred));
+       if (ssid->ssid_len > 32)
+               return -1;
+       os_memcpy(cred.ssid, ssid->ssid, ssid->ssid_len);
+       cred.ssid_len = ssid->ssid_len;
+       if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
+               cred.auth_type = (ssid->proto & WPA_PROTO_RSN) ?
+                       WPS_AUTH_WPA2PSK : WPS_AUTH_WPAPSK;
+               if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
+                       cred.encr_type = WPS_ENCR_AES;
+               else
+                       cred.encr_type = WPS_ENCR_TKIP;
+               if (ssid->passphrase) {
+                       cred.key_len = os_strlen(ssid->passphrase);
+                       if (cred.key_len >= 64)
+                               return -1;
+                       os_memcpy(cred.key, ssid->passphrase, cred.key_len);
+               } else if (ssid->psk_set) {
+                       cred.key_len = 32;
+                       os_memcpy(cred.key, ssid->psk, 32);
+               } else
+                       return -1;
+       } else {
+               cred.auth_type = WPS_AUTH_OPEN;
+               cred.encr_type = WPS_ENCR_NONE;
+       }
+       return wps_er_set_config(wpa_s->wps_er, u, &cred);
+}
+
+
+int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
+                      const char *pin, struct wps_new_ap_settings *settings)
+{
+       u8 u[UUID_LEN];
+       struct wps_credential cred;
+       size_t len;
+
+       if (uuid_str2bin(uuid, u))
+               return -1;
+       if (settings->ssid_hex == NULL || settings->auth == NULL ||
+           settings->encr == NULL || settings->key_hex == NULL)
+               return -1;
+
+       os_memset(&cred, 0, sizeof(cred));
+       len = os_strlen(settings->ssid_hex);
+       if ((len & 1) || len > 2 * sizeof(cred.ssid) ||
+           hexstr2bin(settings->ssid_hex, cred.ssid, len / 2))
+               return -1;
+       cred.ssid_len = len / 2;
+
+       len = os_strlen(settings->key_hex);
+       if ((len & 1) || len > 2 * sizeof(cred.key) ||
+           hexstr2bin(settings->key_hex, cred.key, len / 2))
+               return -1;
+       cred.key_len = len / 2;
+
+       if (os_strcmp(settings->auth, "OPEN") == 0)
+               cred.auth_type = WPS_AUTH_OPEN;
+       else if (os_strcmp(settings->auth, "WPAPSK") == 0)
+               cred.auth_type = WPS_AUTH_WPAPSK;
+       else if (os_strcmp(settings->auth, "WPA2PSK") == 0)
+               cred.auth_type = WPS_AUTH_WPA2PSK;
+       else
+               return -1;
+
+       if (os_strcmp(settings->encr, "NONE") == 0)
+               cred.encr_type = WPS_ENCR_NONE;
+       else if (os_strcmp(settings->encr, "WEP") == 0)
+               cred.encr_type = WPS_ENCR_WEP;
+       else if (os_strcmp(settings->encr, "TKIP") == 0)
+               cred.encr_type = WPS_ENCR_TKIP;
+       else if (os_strcmp(settings->encr, "CCMP") == 0)
+               cred.encr_type = WPS_ENCR_AES;
+       else
+               return -1;
+
+       return wps_er_config(wpa_s->wps_er, u, (const u8 *) pin,
+                            os_strlen(pin), &cred);
+}
+
+
+static int callbacks_pending = 0;
+
 static void wpas_wps_terminate_cb(void *ctx)
 {
        wpa_printf(MSG_DEBUG, "WPS ER: Terminated");
-       eloop_terminate();
+       if (--callbacks_pending <= 0)
+               eloop_terminate();
 }
 #endif /* CONFIG_WPS_ER */
 
@@ -1176,6 +1655,7 @@ int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s)
 {
 #ifdef CONFIG_WPS_ER
        if (wpa_s->wps_er) {
+               callbacks_pending++;
                wps_er_deinit(wpa_s->wps_er, wpas_wps_terminate_cb, wpa_s);
                wpa_s->wps_er = NULL;
                return 1;
@@ -1183,3 +1663,65 @@ int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s)
 #endif /* CONFIG_WPS_ER */
        return 0;
 }
+
+
+int wpas_wps_in_progress(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_ssid *ssid;
+
+       for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+               if (!ssid->disabled && ssid->key_mgmt == WPA_KEY_MGMT_WPS)
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
+{
+       struct wps_context *wps = wpa_s->wps;
+
+       if (wps == NULL)
+               return;
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_CONFIG_METHODS) {
+               wps->config_methods = wps_config_methods_str2bin(
+                       wpa_s->conf->config_methods);
+               if ((wps->config_methods &
+                    (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) ==
+                   (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) {
+                       wpa_printf(MSG_ERROR, "WPS: Both Label and Display "
+                                  "config methods are not allowed at the "
+                                  "same time");
+                       wps->config_methods &= ~WPS_CONFIG_LABEL;
+               }
+       }
+       wps->config_methods = wps_fix_config_methods(wps->config_methods);
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_TYPE)
+               os_memcpy(wps->dev.pri_dev_type, wpa_s->conf->device_type,
+                         WPS_DEV_TYPE_LEN);
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_SEC_DEVICE_TYPE) {
+               wps->dev.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
+               os_memcpy(wps->dev.sec_dev_type, wpa_s->conf->sec_device_type,
+                         wps->dev.num_sec_dev_types * WPS_DEV_TYPE_LEN);
+       }
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_OS_VERSION)
+               wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_UUID)
+               wpas_wps_set_uuid(wpa_s, wps);
+
+       if (wpa_s->conf->changed_parameters &
+           (CFG_CHANGED_DEVICE_NAME | CFG_CHANGED_WPS_STRING)) {
+               /* Update pointers to make sure they refer current values */
+               wps->dev.device_name = wpa_s->conf->device_name;
+               wps->dev.manufacturer = wpa_s->conf->manufacturer;
+               wps->dev.model_name = wpa_s->conf->model_name;
+               wps->dev.model_number = wpa_s->conf->model_number;
+               wps->dev.serial_number = wpa_s->conf->serial_number;
+       }
+}
index ba2fb16..b38c091 100644 (file)
@@ -35,9 +35,11 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s);
 void wpas_wps_deinit(struct wpa_supplicant *wpa_s);
 int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s);
 enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid);
-int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
+                      int p2p_group);
 int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
-                      const char *pin);
+                      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,
@@ -52,14 +54,20 @@ void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s);
 int wpas_wps_searching(struct wpa_supplicant *wpa_s);
 int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *pos,
                              char *end);
-int wpas_wps_er_start(struct wpa_supplicant *wpa_s);
+int wpas_wps_er_start(struct wpa_supplicant *wpa_s, const char *filter);
 int wpas_wps_er_stop(struct wpa_supplicant *wpa_s);
-int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const char *uuid,
-                       const char *pin);
+int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const u8 *addr,
+                       const char *uuid, const char *pin);
 int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid);
 int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid,
                      const char *pin);
+int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
+                          int id);
+int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
+                      const char *pin, struct wps_new_ap_settings *settings);
 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);
 
 #else /* CONFIG_WPS */
 
diff --git a/wpa_supplicant/xcode/wpa_supplicant.xcodeproj/project.pbxproj b/wpa_supplicant/xcode/wpa_supplicant.xcodeproj/project.pbxproj
deleted file mode 100644 (file)
index 6fea81b..0000000
+++ /dev/null
@@ -1,513 +0,0 @@
-// !$*UTF8*$!
-{
-       archiveVersion = 1;
-       classes = {
-       };
-       objectVersion = 45;
-       objects = {
-
-/* Begin PBXBuildFile section */
-               881EED0F10DC14EF009E449F /* eap_register.c in Sources */ = {isa = PBXBuildFile; fileRef = 881EED0E10DC14EF009E449F /* eap_register.c */; };
-               8853CB17109F385C00358CEF /* libpcap.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8853CB16109F385C00358CEF /* libpcap.dylib */; };
-               8853CB1B109F389800358CEF /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8853CB1A109F389800358CEF /* libcrypto.dylib */; };
-               8853CB1F109F38BD00358CEF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8853CB1E109F38BD00358CEF /* CoreFoundation.framework */; };
-               8853CB2E109F3A3900358CEF /* scan_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CB2D109F3A3900358CEF /* scan_helpers.c */; };
-               8853CB32109F3A9400358CEF /* wpa_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CB31109F3A9400358CEF /* wpa_common.c */; };
-               8853CB36109F3AC700358CEF /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CB35109F3AC700358CEF /* md5.c */; };
-               8853CB3C109F3B5800358CEF /* Apple80211.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8853CB3B109F3B5800358CEF /* Apple80211.framework */; };
-               8853CBFB109F4C6E00358CEF /* eap_gtc.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBEC109F4C6E00358CEF /* eap_gtc.c */; };
-               8853CBFC109F4C6E00358CEF /* eap_leap.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBED109F4C6E00358CEF /* eap_leap.c */; };
-               8853CBFD109F4C6E00358CEF /* eap_md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBEE109F4C6E00358CEF /* eap_md5.c */; };
-               8853CBFE109F4C6E00358CEF /* eap_methods.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBEF109F4C6E00358CEF /* eap_methods.c */; };
-               8853CBFF109F4C6E00358CEF /* eap_mschapv2.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF0109F4C6E00358CEF /* eap_mschapv2.c */; };
-               8853CC00109F4C6E00358CEF /* eap_otp.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF1109F4C6E00358CEF /* eap_otp.c */; };
-               8853CC01109F4C6E00358CEF /* eap_peap.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF2109F4C6E00358CEF /* eap_peap.c */; };
-               8853CC02109F4C6E00358CEF /* eap_tls_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF3109F4C6E00358CEF /* eap_tls_common.c */; };
-               8853CC03109F4C6E00358CEF /* eap_tls.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF4109F4C6E00358CEF /* eap_tls.c */; };
-               8853CC04109F4C6E00358CEF /* eap_tnc.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF5109F4C6E00358CEF /* eap_tnc.c */; };
-               8853CC05109F4C6E00358CEF /* eap_ttls.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF6109F4C6E00358CEF /* eap_ttls.c */; };
-               8853CC06109F4C6E00358CEF /* eap_wsc.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF7109F4C6E00358CEF /* eap_wsc.c */; };
-               8853CC07109F4C6E00358CEF /* eap.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF8109F4C6E00358CEF /* eap.c */; };
-               8853CC08109F4C6E00358CEF /* mschapv2.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF9109F4C6E00358CEF /* mschapv2.c */; };
-               8853CC09109F4C6E00358CEF /* tncc.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBFA109F4C6E00358CEF /* tncc.c */; };
-               8853CC0E109F4CA100358CEF /* ctrl_iface_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC0C109F4CA100358CEF /* ctrl_iface_unix.c */; };
-               8853CC0F109F4CA100358CEF /* ctrl_iface.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC0D109F4CA100358CEF /* ctrl_iface.c */; };
-               8853CC11109F4CC800358CEF /* eapol_supp_sm.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC10109F4CC800358CEF /* eapol_supp_sm.c */; };
-               8853CC18109F4D0800358CEF /* chap.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC14109F4D0800358CEF /* chap.c */; };
-               8853CC19109F4D0800358CEF /* eap_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC15109F4D0800358CEF /* eap_common.c */; };
-               8853CC1A109F4D0800358CEF /* eap_peap_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC16109F4D0800358CEF /* eap_peap_common.c */; };
-               8853CC1B109F4D0800358CEF /* eap_wsc_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC17109F4D0800358CEF /* eap_wsc_common.c */; };
-               8853CC26109F4D3500358CEF /* wps_attr_build.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC1E109F4D3500358CEF /* wps_attr_build.c */; };
-               8853CC27109F4D3500358CEF /* wps_attr_parse.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC1F109F4D3500358CEF /* wps_attr_parse.c */; };
-               8853CC28109F4D3500358CEF /* wps_attr_process.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC20109F4D3500358CEF /* wps_attr_process.c */; };
-               8853CC29109F4D3500358CEF /* wps_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC21109F4D3500358CEF /* wps_common.c */; };
-               8853CC2A109F4D3500358CEF /* wps_dev_attr.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC22109F4D3500358CEF /* wps_dev_attr.c */; };
-               8853CC2B109F4D3500358CEF /* wps_enrollee.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC23109F4D3500358CEF /* wps_enrollee.c */; };
-               8853CC2C109F4D3500358CEF /* wps_registrar.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC24109F4D3500358CEF /* wps_registrar.c */; };
-               8853CC2D109F4D3500358CEF /* wps.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC25109F4D3500358CEF /* wps.c */; };
-               8853CC34109F4DE200358CEF /* ms_funcs.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC32109F4DE200358CEF /* ms_funcs.c */; };
-               8853CC35109F4DE200358CEF /* tls_openssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC33109F4DE200358CEF /* tls_openssl.c */; };
-               8853CC3C109F4E1D00358CEF /* libssl.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8853CC3B109F4E1D00358CEF /* libssl.dylib */; };
-               8853CC40109F4E3A00358CEF /* wps_supplicant.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC3F109F4E3A00358CEF /* wps_supplicant.c */; };
-               8853CC44109F4E6200358CEF /* uuid.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC43109F4E6200358CEF /* uuid.c */; };
-               8853CC48109F4E8700358CEF /* ieee802_11_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC47109F4E8700358CEF /* ieee802_11_common.c */; };
-               8853CC4E109F4ED500358CEF /* sha256.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC4C109F4ED500358CEF /* sha256.c */; };
-               8853CC53109F4F3500358CEF /* aes-cbc.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC51109F4F3500358CEF /* aes-cbc.c */; };
-               8853CC54109F4F3500358CEF /* sha1-tlsprf.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC52109F4F3500358CEF /* sha1-tlsprf.c */; };
-               88950831109F2FAB004FB35D /* blacklist.c in Sources */ = {isa = PBXBuildFile; fileRef = 88950828109F2FAB004FB35D /* blacklist.c */; };
-               88950832109F2FAB004FB35D /* config_file.c in Sources */ = {isa = PBXBuildFile; fileRef = 88950829109F2FAB004FB35D /* config_file.c */; };
-               88950833109F2FAB004FB35D /* config.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895082A109F2FAB004FB35D /* config.c */; };
-               88950834109F2FAB004FB35D /* events.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895082B109F2FAB004FB35D /* events.c */; };
-               88950835109F2FAB004FB35D /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895082C109F2FAB004FB35D /* main.c */; };
-               88950836109F2FAB004FB35D /* notify.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895082D109F2FAB004FB35D /* notify.c */; };
-               88950837109F2FAB004FB35D /* scan.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895082E109F2FAB004FB35D /* scan.c */; };
-               88950838109F2FAB004FB35D /* wpa_supplicant.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895082F109F2FAB004FB35D /* wpa_supplicant.c */; };
-               88950839109F2FAB004FB35D /* wpas_glue.c in Sources */ = {isa = PBXBuildFile; fileRef = 88950830109F2FAB004FB35D /* wpas_glue.c */; };
-               88950840109F301A004FB35D /* base64.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895083A109F301A004FB35D /* base64.c */; };
-               88950841109F301A004FB35D /* common.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895083B109F301A004FB35D /* common.c */; };
-               88950842109F301A004FB35D /* eloop.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895083C109F301A004FB35D /* eloop.c */; };
-               88950843109F301A004FB35D /* os_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895083D109F301A004FB35D /* os_unix.c */; };
-               88950844109F301A004FB35D /* wpa_debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895083E109F301A004FB35D /* wpa_debug.c */; };
-               88950845109F301A004FB35D /* wpabuf.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895083F109F301A004FB35D /* wpabuf.c */; };
-               88950864109F32D1004FB35D /* peerkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895085F109F32D1004FB35D /* peerkey.c */; };
-               88950865109F32D1004FB35D /* pmksa_cache.c in Sources */ = {isa = PBXBuildFile; fileRef = 88950860109F32D1004FB35D /* pmksa_cache.c */; };
-               88950866109F32D1004FB35D /* preauth.c in Sources */ = {isa = PBXBuildFile; fileRef = 88950861109F32D1004FB35D /* preauth.c */; };
-               88950867109F32D1004FB35D /* wpa_ie.c in Sources */ = {isa = PBXBuildFile; fileRef = 88950862109F32D1004FB35D /* wpa_ie.c */; };
-               88950868109F32D1004FB35D /* wpa.c in Sources */ = {isa = PBXBuildFile; fileRef = 88950863109F32D1004FB35D /* wpa.c */; };
-               8895086C109F3316004FB35D /* l2_packet_freebsd.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895086B109F3316004FB35D /* l2_packet_freebsd.c */; };
-               88950871109F3367004FB35D /* aes-unwrap.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895086D109F3367004FB35D /* aes-unwrap.c */; };
-               88950872109F3367004FB35D /* crypto_openssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895086E109F3367004FB35D /* crypto_openssl.c */; };
-               88950873109F3367004FB35D /* sha1-pbkdf2.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895086F109F3367004FB35D /* sha1-pbkdf2.c */; };
-               88950874109F3367004FB35D /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 88950870109F3367004FB35D /* sha1.c */; };
-               88950885109F3538004FB35D /* driver_osx.m in Sources */ = {isa = PBXBuildFile; fileRef = 88950883109F3538004FB35D /* driver_osx.m */; };
-               88950886109F3538004FB35D /* drivers.c in Sources */ = {isa = PBXBuildFile; fileRef = 88950884109F3538004FB35D /* drivers.c */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXCopyFilesBuildPhase section */
-               8DD76FAF0486AB0100D96B5E /* CopyFiles */ = {
-                       isa = PBXCopyFilesBuildPhase;
-                       buildActionMask = 8;
-                       dstPath = /usr/share/man/man1/;
-                       dstSubfolderSpec = 0;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 1;
-               };
-/* End PBXCopyFilesBuildPhase section */
-
-/* Begin PBXFileReference section */
-               881EED0E10DC14EF009E449F /* eap_register.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_register.c; path = ../eap_register.c; sourceTree = SOURCE_ROOT; };
-               8853CB16109F385C00358CEF /* libpcap.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpcap.dylib; path = usr/lib/libpcap.dylib; sourceTree = SDKROOT; };
-               8853CB1A109F389800358CEF /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.dylib; path = usr/lib/libcrypto.dylib; sourceTree = SDKROOT; };
-               8853CB1E109F38BD00358CEF /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
-               8853CB2D109F3A3900358CEF /* scan_helpers.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = scan_helpers.c; path = ../../src/drivers/scan_helpers.c; sourceTree = SOURCE_ROOT; };
-               8853CB31109F3A9400358CEF /* wpa_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wpa_common.c; path = ../../src/common/wpa_common.c; sourceTree = SOURCE_ROOT; };
-               8853CB35109F3AC700358CEF /* md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md5.c; path = ../../src/crypto/md5.c; sourceTree = SOURCE_ROOT; };
-               8853CB3B109F3B5800358CEF /* Apple80211.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Apple80211.framework; path = /System/Library/PrivateFrameworks/Apple80211.framework; sourceTree = "<absolute>"; };
-               8853CBEC109F4C6E00358CEF /* eap_gtc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_gtc.c; path = ../../src/eap_peer/eap_gtc.c; sourceTree = SOURCE_ROOT; };
-               8853CBED109F4C6E00358CEF /* eap_leap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_leap.c; path = ../../src/eap_peer/eap_leap.c; sourceTree = SOURCE_ROOT; };
-               8853CBEE109F4C6E00358CEF /* eap_md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_md5.c; path = ../../src/eap_peer/eap_md5.c; sourceTree = SOURCE_ROOT; };
-               8853CBEF109F4C6E00358CEF /* eap_methods.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_methods.c; path = ../../src/eap_peer/eap_methods.c; sourceTree = SOURCE_ROOT; };
-               8853CBF0109F4C6E00358CEF /* eap_mschapv2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_mschapv2.c; path = ../../src/eap_peer/eap_mschapv2.c; sourceTree = SOURCE_ROOT; };
-               8853CBF1109F4C6E00358CEF /* eap_otp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_otp.c; path = ../../src/eap_peer/eap_otp.c; sourceTree = SOURCE_ROOT; };
-               8853CBF2109F4C6E00358CEF /* eap_peap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_peap.c; path = ../../src/eap_peer/eap_peap.c; sourceTree = SOURCE_ROOT; };
-               8853CBF3109F4C6E00358CEF /* eap_tls_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_tls_common.c; path = ../../src/eap_peer/eap_tls_common.c; sourceTree = SOURCE_ROOT; };
-               8853CBF4109F4C6E00358CEF /* eap_tls.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_tls.c; path = ../../src/eap_peer/eap_tls.c; sourceTree = SOURCE_ROOT; };
-               8853CBF5109F4C6E00358CEF /* eap_tnc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_tnc.c; path = ../../src/eap_peer/eap_tnc.c; sourceTree = SOURCE_ROOT; };
-               8853CBF6109F4C6E00358CEF /* eap_ttls.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_ttls.c; path = ../../src/eap_peer/eap_ttls.c; sourceTree = SOURCE_ROOT; };
-               8853CBF7109F4C6E00358CEF /* eap_wsc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_wsc.c; path = ../../src/eap_peer/eap_wsc.c; sourceTree = SOURCE_ROOT; };
-               8853CBF8109F4C6E00358CEF /* eap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap.c; path = ../../src/eap_peer/eap.c; sourceTree = SOURCE_ROOT; };
-               8853CBF9109F4C6E00358CEF /* mschapv2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mschapv2.c; path = ../../src/eap_peer/mschapv2.c; sourceTree = SOURCE_ROOT; };
-               8853CBFA109F4C6E00358CEF /* tncc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tncc.c; path = ../../src/eap_peer/tncc.c; sourceTree = SOURCE_ROOT; };
-               8853CC0C109F4CA100358CEF /* ctrl_iface_unix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ctrl_iface_unix.c; path = ../ctrl_iface_unix.c; sourceTree = SOURCE_ROOT; };
-               8853CC0D109F4CA100358CEF /* ctrl_iface.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ctrl_iface.c; path = ../ctrl_iface.c; sourceTree = SOURCE_ROOT; };
-               8853CC10109F4CC800358CEF /* eapol_supp_sm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eapol_supp_sm.c; path = ../../src/eapol_supp/eapol_supp_sm.c; sourceTree = SOURCE_ROOT; };
-               8853CC14109F4D0800358CEF /* chap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = chap.c; path = ../../src/eap_common/chap.c; sourceTree = SOURCE_ROOT; };
-               8853CC15109F4D0800358CEF /* eap_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_common.c; path = ../../src/eap_common/eap_common.c; sourceTree = SOURCE_ROOT; };
-               8853CC16109F4D0800358CEF /* eap_peap_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_peap_common.c; path = ../../src/eap_common/eap_peap_common.c; sourceTree = SOURCE_ROOT; };
-               8853CC17109F4D0800358CEF /* eap_wsc_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_wsc_common.c; path = ../../src/eap_common/eap_wsc_common.c; sourceTree = SOURCE_ROOT; };
-               8853CC1E109F4D3500358CEF /* wps_attr_build.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wps_attr_build.c; path = ../../src/wps/wps_attr_build.c; sourceTree = SOURCE_ROOT; };
-               8853CC1F109F4D3500358CEF /* wps_attr_parse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wps_attr_parse.c; path = ../../src/wps/wps_attr_parse.c; sourceTree = SOURCE_ROOT; };
-               8853CC20109F4D3500358CEF /* wps_attr_process.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wps_attr_process.c; path = ../../src/wps/wps_attr_process.c; sourceTree = SOURCE_ROOT; };
-               8853CC21109F4D3500358CEF /* wps_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wps_common.c; path = ../../src/wps/wps_common.c; sourceTree = SOURCE_ROOT; };
-               8853CC22109F4D3500358CEF /* wps_dev_attr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wps_dev_attr.c; path = ../../src/wps/wps_dev_attr.c; sourceTree = SOURCE_ROOT; };
-               8853CC23109F4D3500358CEF /* wps_enrollee.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wps_enrollee.c; path = ../../src/wps/wps_enrollee.c; sourceTree = SOURCE_ROOT; };
-               8853CC24109F4D3500358CEF /* wps_registrar.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wps_registrar.c; path = ../../src/wps/wps_registrar.c; sourceTree = SOURCE_ROOT; };
-               8853CC25109F4D3500358CEF /* wps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wps.c; path = ../../src/wps/wps.c; sourceTree = SOURCE_ROOT; };
-               8853CC32109F4DE200358CEF /* ms_funcs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ms_funcs.c; path = ../../src/crypto/ms_funcs.c; sourceTree = SOURCE_ROOT; };
-               8853CC33109F4DE200358CEF /* tls_openssl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tls_openssl.c; path = ../../src/crypto/tls_openssl.c; sourceTree = SOURCE_ROOT; };
-               8853CC3B109F4E1D00358CEF /* libssl.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libssl.dylib; path = usr/lib/libssl.dylib; sourceTree = SDKROOT; };
-               8853CC3F109F4E3A00358CEF /* wps_supplicant.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wps_supplicant.c; path = ../wps_supplicant.c; sourceTree = SOURCE_ROOT; };
-               8853CC43109F4E6200358CEF /* uuid.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uuid.c; path = ../../src/utils/uuid.c; sourceTree = SOURCE_ROOT; };
-               8853CC47109F4E8700358CEF /* ieee802_11_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ieee802_11_common.c; path = ../../src/common/ieee802_11_common.c; sourceTree = SOURCE_ROOT; };
-               8853CC4C109F4ED500358CEF /* sha256.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sha256.c; path = ../../src/crypto/sha256.c; sourceTree = SOURCE_ROOT; };
-               8853CC51109F4F3500358CEF /* aes-cbc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "aes-cbc.c"; path = "../../src/crypto/aes-cbc.c"; sourceTree = SOURCE_ROOT; };
-               8853CC52109F4F3500358CEF /* sha1-tlsprf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "sha1-tlsprf.c"; path = "../../src/crypto/sha1-tlsprf.c"; sourceTree = SOURCE_ROOT; };
-               88950828109F2FAB004FB35D /* blacklist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = blacklist.c; path = ../../wpa_supplicant/blacklist.c; sourceTree = SOURCE_ROOT; };
-               88950829109F2FAB004FB35D /* config_file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = config_file.c; path = ../../wpa_supplicant/config_file.c; sourceTree = SOURCE_ROOT; };
-               8895082A109F2FAB004FB35D /* config.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = config.c; path = ../../wpa_supplicant/config.c; sourceTree = SOURCE_ROOT; };
-               8895082B109F2FAB004FB35D /* events.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = events.c; path = ../../wpa_supplicant/events.c; sourceTree = SOURCE_ROOT; };
-               8895082C109F2FAB004FB35D /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = ../../wpa_supplicant/main.c; sourceTree = SOURCE_ROOT; };
-               8895082D109F2FAB004FB35D /* notify.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = notify.c; path = ../../wpa_supplicant/notify.c; sourceTree = SOURCE_ROOT; };
-               8895082E109F2FAB004FB35D /* scan.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = scan.c; path = ../../wpa_supplicant/scan.c; sourceTree = SOURCE_ROOT; };
-               8895082F109F2FAB004FB35D /* wpa_supplicant.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wpa_supplicant.c; path = ../../wpa_supplicant/wpa_supplicant.c; sourceTree = SOURCE_ROOT; };
-               88950830109F2FAB004FB35D /* wpas_glue.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wpas_glue.c; path = ../../wpa_supplicant/wpas_glue.c; sourceTree = SOURCE_ROOT; };
-               8895083A109F301A004FB35D /* base64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = base64.c; path = ../../src/utils/base64.c; sourceTree = SOURCE_ROOT; };
-               8895083B109F301A004FB35D /* common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = common.c; path = ../../src/utils/common.c; sourceTree = SOURCE_ROOT; };
-               8895083C109F301A004FB35D /* eloop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eloop.c; path = ../../src/utils/eloop.c; sourceTree = SOURCE_ROOT; };
-               8895083D109F301A004FB35D /* os_unix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = os_unix.c; path = ../../src/utils/os_unix.c; sourceTree = SOURCE_ROOT; };
-               8895083E109F301A004FB35D /* wpa_debug.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wpa_debug.c; path = ../../src/utils/wpa_debug.c; sourceTree = SOURCE_ROOT; };
-               8895083F109F301A004FB35D /* wpabuf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wpabuf.c; path = ../../src/utils/wpabuf.c; sourceTree = SOURCE_ROOT; };
-               8895085F109F32D1004FB35D /* peerkey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = peerkey.c; path = ../../src/rsn_supp/peerkey.c; sourceTree = SOURCE_ROOT; };
-               88950860109F32D1004FB35D /* pmksa_cache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pmksa_cache.c; path = ../../src/rsn_supp/pmksa_cache.c; sourceTree = SOURCE_ROOT; };
-               88950861109F32D1004FB35D /* preauth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = preauth.c; path = ../../src/rsn_supp/preauth.c; sourceTree = SOURCE_ROOT; };
-               88950862109F32D1004FB35D /* wpa_ie.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wpa_ie.c; path = ../../src/rsn_supp/wpa_ie.c; sourceTree = SOURCE_ROOT; };
-               88950863109F32D1004FB35D /* wpa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wpa.c; path = ../../src/rsn_supp/wpa.c; sourceTree = SOURCE_ROOT; };
-               8895086B109F3316004FB35D /* l2_packet_freebsd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = l2_packet_freebsd.c; path = ../../src/l2_packet/l2_packet_freebsd.c; sourceTree = SOURCE_ROOT; };
-               8895086D109F3367004FB35D /* aes-unwrap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "aes-unwrap.c"; path = "../../src/crypto/aes-unwrap.c"; sourceTree = SOURCE_ROOT; };
-               8895086E109F3367004FB35D /* crypto_openssl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_openssl.c; path = ../../src/crypto/crypto_openssl.c; sourceTree = SOURCE_ROOT; };
-               8895086F109F3367004FB35D /* sha1-pbkdf2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "sha1-pbkdf2.c"; path = "../../src/crypto/sha1-pbkdf2.c"; sourceTree = SOURCE_ROOT; };
-               88950870109F3367004FB35D /* sha1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sha1.c; path = ../../src/crypto/sha1.c; sourceTree = SOURCE_ROOT; };
-               88950883109F3538004FB35D /* driver_osx.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = driver_osx.m; path = ../../src/drivers/driver_osx.m; sourceTree = SOURCE_ROOT; };
-               88950884109F3538004FB35D /* drivers.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = drivers.c; path = ../../src/drivers/drivers.c; sourceTree = SOURCE_ROOT; };
-               8DD76FB20486AB0100D96B5E /* wpa_supplicant */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = wpa_supplicant; sourceTree = BUILT_PRODUCTS_DIR; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
-               8DD76FAD0486AB0100D96B5E /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               8853CB17109F385C00358CEF /* libpcap.dylib in Frameworks */,
-                               8853CB1B109F389800358CEF /* libcrypto.dylib in Frameworks */,
-                               8853CB1F109F38BD00358CEF /* CoreFoundation.framework in Frameworks */,
-                               8853CB3C109F3B5800358CEF /* Apple80211.framework in Frameworks */,
-                               8853CC3C109F4E1D00358CEF /* libssl.dylib in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
-               08FB7794FE84155DC02AAC07 /* wpa_supplicant */ = {
-                       isa = PBXGroup;
-                       children = (
-                               08FB7795FE84155DC02AAC07 /* Source */,
-                               C6A0FF2B0290797F04C91782 /* Documentation */,
-                               1AB674ADFE9D54B511CA2CBB /* Products */,
-                               8853CB16109F385C00358CEF /* libpcap.dylib */,
-                               8853CB1A109F389800358CEF /* libcrypto.dylib */,
-                               8853CB1E109F38BD00358CEF /* CoreFoundation.framework */,
-                               8853CB3B109F3B5800358CEF /* Apple80211.framework */,
-                               8853CC3B109F4E1D00358CEF /* libssl.dylib */,
-                       );
-                       name = wpa_supplicant;
-                       sourceTree = "<group>";
-               };
-               08FB7795FE84155DC02AAC07 /* Source */ = {
-                       isa = PBXGroup;
-                       children = (
-                               881EED0E10DC14EF009E449F /* eap_register.c */,
-                               8853CC51109F4F3500358CEF /* aes-cbc.c */,
-                               8853CC52109F4F3500358CEF /* sha1-tlsprf.c */,
-                               8853CC4C109F4ED500358CEF /* sha256.c */,
-                               8853CC47109F4E8700358CEF /* ieee802_11_common.c */,
-                               8853CC43109F4E6200358CEF /* uuid.c */,
-                               8853CC3F109F4E3A00358CEF /* wps_supplicant.c */,
-                               8853CC32109F4DE200358CEF /* ms_funcs.c */,
-                               8853CC33109F4DE200358CEF /* tls_openssl.c */,
-                               8853CC1E109F4D3500358CEF /* wps_attr_build.c */,
-                               8853CC1F109F4D3500358CEF /* wps_attr_parse.c */,
-                               8853CC20109F4D3500358CEF /* wps_attr_process.c */,
-                               8853CC21109F4D3500358CEF /* wps_common.c */,
-                               8853CC22109F4D3500358CEF /* wps_dev_attr.c */,
-                               8853CC23109F4D3500358CEF /* wps_enrollee.c */,
-                               8853CC24109F4D3500358CEF /* wps_registrar.c */,
-                               8853CC25109F4D3500358CEF /* wps.c */,
-                               8853CC14109F4D0800358CEF /* chap.c */,
-                               8853CC15109F4D0800358CEF /* eap_common.c */,
-                               8853CC16109F4D0800358CEF /* eap_peap_common.c */,
-                               8853CC17109F4D0800358CEF /* eap_wsc_common.c */,
-                               8853CC10109F4CC800358CEF /* eapol_supp_sm.c */,
-                               8853CC0C109F4CA100358CEF /* ctrl_iface_unix.c */,
-                               8853CC0D109F4CA100358CEF /* ctrl_iface.c */,
-                               8853CBEC109F4C6E00358CEF /* eap_gtc.c */,
-                               8853CBED109F4C6E00358CEF /* eap_leap.c */,
-                               8853CBEE109F4C6E00358CEF /* eap_md5.c */,
-                               8853CBEF109F4C6E00358CEF /* eap_methods.c */,
-                               8853CBF0109F4C6E00358CEF /* eap_mschapv2.c */,
-                               8853CBF1109F4C6E00358CEF /* eap_otp.c */,
-                               8853CBF2109F4C6E00358CEF /* eap_peap.c */,
-                               8853CBF3109F4C6E00358CEF /* eap_tls_common.c */,
-                               8853CBF4109F4C6E00358CEF /* eap_tls.c */,
-                               8853CBF5109F4C6E00358CEF /* eap_tnc.c */,
-                               8853CBF6109F4C6E00358CEF /* eap_ttls.c */,
-                               8853CBF7109F4C6E00358CEF /* eap_wsc.c */,
-                               8853CBF8109F4C6E00358CEF /* eap.c */,
-                               8853CBF9109F4C6E00358CEF /* mschapv2.c */,
-                               8853CBFA109F4C6E00358CEF /* tncc.c */,
-                               8853CB35109F3AC700358CEF /* md5.c */,
-                               8853CB31109F3A9400358CEF /* wpa_common.c */,
-                               8853CB2D109F3A3900358CEF /* scan_helpers.c */,
-                               88950883109F3538004FB35D /* driver_osx.m */,
-                               88950884109F3538004FB35D /* drivers.c */,
-                               8895086D109F3367004FB35D /* aes-unwrap.c */,
-                               8895086E109F3367004FB35D /* crypto_openssl.c */,
-                               8895086F109F3367004FB35D /* sha1-pbkdf2.c */,
-                               88950870109F3367004FB35D /* sha1.c */,
-                               8895086B109F3316004FB35D /* l2_packet_freebsd.c */,
-                               8895085F109F32D1004FB35D /* peerkey.c */,
-                               88950860109F32D1004FB35D /* pmksa_cache.c */,
-                               88950861109F32D1004FB35D /* preauth.c */,
-                               88950862109F32D1004FB35D /* wpa_ie.c */,
-                               88950863109F32D1004FB35D /* wpa.c */,
-                               8895083A109F301A004FB35D /* base64.c */,
-                               8895083B109F301A004FB35D /* common.c */,
-                               8895083C109F301A004FB35D /* eloop.c */,
-                               8895083D109F301A004FB35D /* os_unix.c */,
-                               8895083E109F301A004FB35D /* wpa_debug.c */,
-                               8895083F109F301A004FB35D /* wpabuf.c */,
-                               88950828109F2FAB004FB35D /* blacklist.c */,
-                               88950829109F2FAB004FB35D /* config_file.c */,
-                               8895082A109F2FAB004FB35D /* config.c */,
-                               8895082B109F2FAB004FB35D /* events.c */,
-                               8895082C109F2FAB004FB35D /* main.c */,
-                               8895082D109F2FAB004FB35D /* notify.c */,
-                               8895082E109F2FAB004FB35D /* scan.c */,
-                               8895082F109F2FAB004FB35D /* wpa_supplicant.c */,
-                               88950830109F2FAB004FB35D /* wpas_glue.c */,
-                       );
-                       name = Source;
-                       sourceTree = "<group>";
-               };
-               1AB674ADFE9D54B511CA2CBB /* Products */ = {
-                       isa = PBXGroup;
-                       children = (
-                               8DD76FB20486AB0100D96B5E /* wpa_supplicant */,
-                       );
-                       name = Products;
-                       sourceTree = "<group>";
-               };
-               C6A0FF2B0290797F04C91782 /* Documentation */ = {
-                       isa = PBXGroup;
-                       children = (
-                       );
-                       name = Documentation;
-                       sourceTree = "<group>";
-               };
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
-               8DD76FA90486AB0100D96B5E /* wpa_supplicant */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 1DEB928508733DD80010E9CD /* Build configuration list for PBXNativeTarget "wpa_supplicant" */;
-                       buildPhases = (
-                               8DD76FAB0486AB0100D96B5E /* Sources */,
-                               8DD76FAD0486AB0100D96B5E /* Frameworks */,
-                               8DD76FAF0486AB0100D96B5E /* CopyFiles */,
-                       );
-                       buildRules = (
-                       );
-                       dependencies = (
-                       );
-                       name = wpa_supplicant;
-                       productInstallPath = "$(HOME)/bin";
-                       productName = wpa_supplicant;
-                       productReference = 8DD76FB20486AB0100D96B5E /* wpa_supplicant */;
-                       productType = "com.apple.product-type.tool";
-               };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
-               08FB7793FE84155DC02AAC07 /* Project object */ = {
-                       isa = PBXProject;
-                       buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "wpa_supplicant" */;
-                       compatibilityVersion = "Xcode 3.1";
-                       hasScannedForEncodings = 1;
-                       mainGroup = 08FB7794FE84155DC02AAC07 /* wpa_supplicant */;
-                       projectDirPath = "";
-                       projectRoot = "";
-                       targets = (
-                               8DD76FA90486AB0100D96B5E /* wpa_supplicant */,
-                       );
-               };
-/* End PBXProject section */
-
-/* Begin PBXSourcesBuildPhase section */
-               8DD76FAB0486AB0100D96B5E /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               88950831109F2FAB004FB35D /* blacklist.c in Sources */,
-                               88950832109F2FAB004FB35D /* config_file.c in Sources */,
-                               88950833109F2FAB004FB35D /* config.c in Sources */,
-                               88950834109F2FAB004FB35D /* events.c in Sources */,
-                               88950835109F2FAB004FB35D /* main.c in Sources */,
-                               88950836109F2FAB004FB35D /* notify.c in Sources */,
-                               88950837109F2FAB004FB35D /* scan.c in Sources */,
-                               88950838109F2FAB004FB35D /* wpa_supplicant.c in Sources */,
-                               88950839109F2FAB004FB35D /* wpas_glue.c in Sources */,
-                               88950840109F301A004FB35D /* base64.c in Sources */,
-                               88950841109F301A004FB35D /* common.c in Sources */,
-                               88950842109F301A004FB35D /* eloop.c in Sources */,
-                               88950843109F301A004FB35D /* os_unix.c in Sources */,
-                               88950844109F301A004FB35D /* wpa_debug.c in Sources */,
-                               88950845109F301A004FB35D /* wpabuf.c in Sources */,
-                               88950864109F32D1004FB35D /* peerkey.c in Sources */,
-                               88950865109F32D1004FB35D /* pmksa_cache.c in Sources */,
-                               88950866109F32D1004FB35D /* preauth.c in Sources */,
-                               88950867109F32D1004FB35D /* wpa_ie.c in Sources */,
-                               88950868109F32D1004FB35D /* wpa.c in Sources */,
-                               8895086C109F3316004FB35D /* l2_packet_freebsd.c in Sources */,
-                               88950871109F3367004FB35D /* aes-unwrap.c in Sources */,
-                               88950872109F3367004FB35D /* crypto_openssl.c in Sources */,
-                               88950873109F3367004FB35D /* sha1-pbkdf2.c in Sources */,
-                               88950874109F3367004FB35D /* sha1.c in Sources */,
-                               88950885109F3538004FB35D /* driver_osx.m in Sources */,
-                               88950886109F3538004FB35D /* drivers.c in Sources */,
-                               8853CB2E109F3A3900358CEF /* scan_helpers.c in Sources */,
-                               8853CB32109F3A9400358CEF /* wpa_common.c in Sources */,
-                               8853CB36109F3AC700358CEF /* md5.c in Sources */,
-                               8853CBFB109F4C6E00358CEF /* eap_gtc.c in Sources */,
-                               8853CBFC109F4C6E00358CEF /* eap_leap.c in Sources */,
-                               8853CBFD109F4C6E00358CEF /* eap_md5.c in Sources */,
-                               8853CBFE109F4C6E00358CEF /* eap_methods.c in Sources */,
-                               8853CBFF109F4C6E00358CEF /* eap_mschapv2.c in Sources */,
-                               8853CC00109F4C6E00358CEF /* eap_otp.c in Sources */,
-                               8853CC01109F4C6E00358CEF /* eap_peap.c in Sources */,
-                               8853CC02109F4C6E00358CEF /* eap_tls_common.c in Sources */,
-                               8853CC03109F4C6E00358CEF /* eap_tls.c in Sources */,
-                               8853CC04109F4C6E00358CEF /* eap_tnc.c in Sources */,
-                               8853CC05109F4C6E00358CEF /* eap_ttls.c in Sources */,
-                               8853CC06109F4C6E00358CEF /* eap_wsc.c in Sources */,
-                               8853CC07109F4C6E00358CEF /* eap.c in Sources */,
-                               8853CC08109F4C6E00358CEF /* mschapv2.c in Sources */,
-                               8853CC09109F4C6E00358CEF /* tncc.c in Sources */,
-                               8853CC0E109F4CA100358CEF /* ctrl_iface_unix.c in Sources */,
-                               8853CC0F109F4CA100358CEF /* ctrl_iface.c in Sources */,
-                               8853CC11109F4CC800358CEF /* eapol_supp_sm.c in Sources */,
-                               8853CC18109F4D0800358CEF /* chap.c in Sources */,
-                               8853CC19109F4D0800358CEF /* eap_common.c in Sources */,
-                               8853CC1A109F4D0800358CEF /* eap_peap_common.c in Sources */,
-                               8853CC1B109F4D0800358CEF /* eap_wsc_common.c in Sources */,
-                               8853CC26109F4D3500358CEF /* wps_attr_build.c in Sources */,
-                               8853CC27109F4D3500358CEF /* wps_attr_parse.c in Sources */,
-                               8853CC28109F4D3500358CEF /* wps_attr_process.c in Sources */,
-                               8853CC29109F4D3500358CEF /* wps_common.c in Sources */,
-                               8853CC2A109F4D3500358CEF /* wps_dev_attr.c in Sources */,
-                               8853CC2B109F4D3500358CEF /* wps_enrollee.c in Sources */,
-                               8853CC2C109F4D3500358CEF /* wps_registrar.c in Sources */,
-                               8853CC2D109F4D3500358CEF /* wps.c in Sources */,
-                               8853CC34109F4DE200358CEF /* ms_funcs.c in Sources */,
-                               8853CC35109F4DE200358CEF /* tls_openssl.c in Sources */,
-                               8853CC40109F4E3A00358CEF /* wps_supplicant.c in Sources */,
-                               8853CC44109F4E6200358CEF /* uuid.c in Sources */,
-                               8853CC48109F4E8700358CEF /* ieee802_11_common.c in Sources */,
-                               8853CC4E109F4ED500358CEF /* sha256.c in Sources */,
-                               8853CC53109F4F3500358CEF /* aes-cbc.c in Sources */,
-                               8853CC54109F4F3500358CEF /* sha1-tlsprf.c in Sources */,
-                               881EED0F10DC14EF009E449F /* eap_register.c in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin XCBuildConfiguration section */
-               1DEB928608733DD80010E9CD /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               COPY_PHASE_STRIP = NO;
-                               FRAMEWORK_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"",
-                               );
-                               GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
-                               GCC_MODEL_TUNING = G5;
-                               GCC_OPTIMIZATION_LEVEL = 0;
-                               INSTALL_PATH = /usr/local/bin;
-                               PRODUCT_NAME = wpa_supplicant;
-                       };
-                       name = Debug;
-               };
-               1DEB928708733DD80010E9CD /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               FRAMEWORK_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"",
-                               );
-                               GCC_MODEL_TUNING = G5;
-                               INSTALL_PATH = /usr/local/bin;
-                               PRODUCT_NAME = wpa_supplicant;
-                       };
-                       name = Release;
-               };
-               1DEB928A08733DD80010E9CD /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
-                               FRAMEWORK_SEARCH_PATHS = /System/Library/PrivateFrameworks;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
-                               GCC_OPTIMIZATION_LEVEL = 0;
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES;
-                               GCC_WARN_UNUSED_VARIABLE = YES;
-                               HEADER_SEARCH_PATHS = (
-                                       ../../src,
-                                       ../../src/utils,
-                               );
-                               ONLY_ACTIVE_ARCH = YES;
-                               OTHER_CFLAGS = "-DCONFIG_XCODE_DEFAULTS";
-                               PREBINDING = NO;
-                               PRELINK_LIBS = "";
-                               RUN_CLANG_STATIC_ANALYZER = YES;
-                               SDKROOT = macosx10.6;
-                       };
-                       name = Debug;
-               };
-               1DEB928B08733DD80010E9CD /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
-                               FRAMEWORK_SEARCH_PATHS = /System/Library/PrivateFrameworks;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES;
-                               GCC_WARN_UNUSED_VARIABLE = YES;
-                               HEADER_SEARCH_PATHS = (
-                                       ../../src,
-                                       ../../src/utils,
-                               );
-                               OTHER_CFLAGS = "-DCONFIG_XCODE_DEFAULTS";
-                               PREBINDING = NO;
-                               SDKROOT = macosx10.6;
-                       };
-                       name = Release;
-               };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
-               1DEB928508733DD80010E9CD /* Build configuration list for PBXNativeTarget "wpa_supplicant" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               1DEB928608733DD80010E9CD /* Debug */,
-                               1DEB928708733DD80010E9CD /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "wpa_supplicant" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               1DEB928A08733DD80010E9CD /* Debug */,
-                               1DEB928B08733DD80010E9CD /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-/* End XCConfigurationList section */
-       };
-       rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
-}